genai-lite 0.8.2 → 0.9.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.
Files changed (52) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +210 -207
  3. package/dist/adapters/image/GenaiElectronImageAdapter.d.ts +1 -0
  4. package/dist/adapters/image/GenaiElectronImageAdapter.js +5 -5
  5. package/dist/adapters/image/OpenAIImageAdapter.d.ts +1 -0
  6. package/dist/adapters/image/OpenAIImageAdapter.js +4 -4
  7. package/dist/config/llm-presets.json +24 -0
  8. package/dist/image/ImageService.js +2 -0
  9. package/dist/index.d.ts +4 -2
  10. package/dist/index.js +6 -1
  11. package/dist/llm/LLMService.d.ts +30 -1
  12. package/dist/llm/LLMService.js +43 -5
  13. package/dist/llm/clients/AnthropicClientAdapter.d.ts +6 -2
  14. package/dist/llm/clients/AnthropicClientAdapter.js +26 -11
  15. package/dist/llm/clients/GeminiClientAdapter.d.ts +6 -2
  16. package/dist/llm/clients/GeminiClientAdapter.js +21 -9
  17. package/dist/llm/clients/LlamaCppClientAdapter.d.ts +8 -4
  18. package/dist/llm/clients/LlamaCppClientAdapter.js +131 -28
  19. package/dist/llm/clients/MistralClientAdapter.d.ts +6 -2
  20. package/dist/llm/clients/MistralClientAdapter.js +22 -11
  21. package/dist/llm/clients/MockClientAdapter.d.ts +2 -2
  22. package/dist/llm/clients/MockClientAdapter.js +36 -19
  23. package/dist/llm/clients/OpenAIClientAdapter.d.ts +6 -2
  24. package/dist/llm/clients/OpenAIClientAdapter.js +33 -9
  25. package/dist/llm/clients/OpenRouterClientAdapter.d.ts +6 -2
  26. package/dist/llm/clients/OpenRouterClientAdapter.js +87 -16
  27. package/dist/llm/clients/types.d.ts +18 -1
  28. package/dist/llm/clients/types.js +4 -0
  29. package/dist/llm/config.d.ts +9 -2
  30. package/dist/llm/config.js +697 -33
  31. package/dist/llm/services/ModelResolver.d.ts +6 -0
  32. package/dist/llm/services/ModelResolver.js +57 -17
  33. package/dist/llm/services/RequestValidator.d.ts +8 -0
  34. package/dist/llm/services/RequestValidator.js +9 -2
  35. package/dist/llm/services/SettingsManager.d.ts +1 -1
  36. package/dist/llm/services/SettingsManager.js +92 -4
  37. package/dist/llm/types.d.ts +127 -0
  38. package/dist/prompting/index.d.ts +1 -1
  39. package/dist/prompting/index.js +2 -1
  40. package/dist/prompting/parser.d.ts +23 -0
  41. package/dist/prompting/parser.js +33 -0
  42. package/dist/shared/adapters/errorUtils.d.ts +15 -0
  43. package/dist/shared/adapters/errorUtils.js +69 -1
  44. package/dist/shared/adapters/logprobsUtils.d.ts +13 -0
  45. package/dist/shared/adapters/logprobsUtils.js +33 -0
  46. package/dist/shared/services/AdapterRegistry.js +3 -1
  47. package/dist/shared/services/withRetry.d.ts +50 -0
  48. package/dist/shared/services/withRetry.js +78 -0
  49. package/dist/types/image.d.ts +2 -0
  50. package/package.json +59 -59
  51. package/src/config/image-presets.json +212 -212
  52. package/src/config/llm-presets.json +623 -599
@@ -9,9 +9,9 @@ exports.OpenAIClientAdapter = void 0;
9
9
  const openai_1 = __importDefault(require("openai"));
10
10
  const types_1 = require("./types");
11
11
  const errorUtils_1 = require("../../shared/adapters/errorUtils");
12
+ const logprobsUtils_1 = require("../../shared/adapters/logprobsUtils");
12
13
  const systemMessageUtils_1 = require("../../shared/adapters/systemMessageUtils");
13
14
  const defaultLogger_1 = require("../../logging/defaultLogger");
14
- const logger = (0, defaultLogger_1.createDefaultLogger)();
15
15
  /**
16
16
  * Client adapter for OpenAI API integration
17
17
  *
@@ -27,9 +27,11 @@ class OpenAIClientAdapter {
27
27
  *
28
28
  * @param config Optional configuration for the adapter
29
29
  * @param config.baseURL Custom base URL for OpenAI-compatible APIs
30
+ * @param config.logger Custom logger instance
30
31
  */
31
32
  constructor(config) {
32
33
  this.baseURL = config?.baseURL;
34
+ this.logger = config?.logger ?? (0, defaultLogger_1.createDefaultLogger)();
33
35
  }
34
36
  /**
35
37
  * Sends a chat message to OpenAI's API
@@ -38,12 +40,13 @@ class OpenAIClientAdapter {
38
40
  * @param apiKey - The decrypted OpenAI API key
39
41
  * @returns Promise resolving to success or failure response
40
42
  */
41
- async sendMessage(request, apiKey) {
43
+ async sendMessage(request, apiKey, options) {
42
44
  try {
43
45
  // Initialize OpenAI client
44
46
  const openai = new openai_1.default({
45
47
  apiKey,
46
48
  ...(this.baseURL && { baseURL: this.baseURL }),
49
+ maxRetries: 0, // retries are owned by the unified LLMService retry layer
47
50
  });
48
51
  // Format messages for OpenAI API
49
52
  const messages = this.formatMessages(request);
@@ -63,6 +66,15 @@ class OpenAIClientAdapter {
63
66
  ...(request.settings.presencePenalty !== 0 && {
64
67
  presence_penalty: request.settings.presencePenalty,
65
68
  }),
69
+ ...(request.settings.seed !== undefined && {
70
+ seed: request.settings.seed,
71
+ }),
72
+ ...(request.settings.logprobs === true && {
73
+ logprobs: true,
74
+ ...(request.settings.topLogprobs !== undefined && {
75
+ top_logprobs: request.settings.topLogprobs,
76
+ }),
77
+ }),
66
78
  ...(request.settings.user && {
67
79
  user: request.settings.user,
68
80
  }),
@@ -95,7 +107,7 @@ class OpenAIClientAdapter {
95
107
  }
96
108
  };
97
109
  }
98
- logger.debug(`OpenAI API parameters:`, {
110
+ this.logger.debug(`OpenAI API parameters:`, {
99
111
  model: completionParams.model,
100
112
  temperature: completionParams.temperature,
101
113
  max_completion_tokens: completionParams.max_completion_tokens,
@@ -105,12 +117,18 @@ class OpenAIClientAdapter {
105
117
  presence_penalty: completionParams.presence_penalty,
106
118
  hasUser: !!completionParams.user,
107
119
  });
108
- logger.info(`Making OpenAI API call for model: ${request.modelId}`);
120
+ this.logger.info(`Making OpenAI API call for model: ${request.modelId}`);
109
121
  // Make the API call
110
- const completion = await openai.chat.completions.create(completionParams);
122
+ const transportOptions = {
123
+ ...(options?.signal && { signal: options.signal }),
124
+ ...(options?.timeoutMs !== undefined && { timeout: options.timeoutMs }),
125
+ };
126
+ const completion = Object.keys(transportOptions).length > 0
127
+ ? await openai.chat.completions.create(completionParams, transportOptions)
128
+ : await openai.chat.completions.create(completionParams);
111
129
  // Type guard to ensure we have a non-streaming response
112
130
  if ('id' in completion && 'choices' in completion) {
113
- logger.info(`OpenAI API call successful, response ID: ${completion.id}`);
131
+ this.logger.info(`OpenAI API call successful, response ID: ${completion.id}`);
114
132
  // Convert to standardized response format
115
133
  return this.createSuccessResponse(completion, request);
116
134
  }
@@ -119,7 +137,7 @@ class OpenAIClientAdapter {
119
137
  }
120
138
  }
121
139
  catch (error) {
122
- logger.error("OpenAI API error:", error);
140
+ this.logger.error("OpenAI API error:", error);
123
141
  return this.createErrorResponse(error, request);
124
142
  }
125
143
  }
@@ -224,7 +242,7 @@ class OpenAIClientAdapter {
224
242
  const modifiedIndex = (0, systemMessageUtils_1.prependSystemToFirstUserMessage)(simpleMessages, combinedSystemContent, request.settings.systemMessageFallback);
225
243
  if (modifiedIndex !== -1) {
226
244
  messages[modifiedIndex].content = simpleMessages[modifiedIndex].content;
227
- logger.debug(`Model ${request.modelId} doesn't support system messages - prepended to first user message`);
245
+ this.logger.debug(`Model ${request.modelId} doesn't support system messages - prepended to first user message`);
228
246
  }
229
247
  }
230
248
  }
@@ -255,6 +273,11 @@ class OpenAIClientAdapter {
255
273
  if (choice.reasoning && request.settings.reasoning && !request.settings.reasoning.exclude) {
256
274
  responseChoice.reasoning = choice.reasoning;
257
275
  }
276
+ // Per-token log probabilities (when requested via settings.logprobs)
277
+ const logprobs = (0, logprobsUtils_1.mapOpenAIChatLogprobs)(choice.logprobs);
278
+ if (logprobs) {
279
+ responseChoice.logprobs = logprobs;
280
+ }
258
281
  return {
259
282
  id: completion.id,
260
283
  provider: request.providerId,
@@ -281,7 +304,7 @@ class OpenAIClientAdapter {
281
304
  createErrorResponse(error, request) {
282
305
  // Use shared error mapping utility for common error patterns
283
306
  const initialProviderMessage = error instanceof openai_1.default.APIError ? error.message : undefined;
284
- let { errorCode, errorMessage, errorType, status } = (0, errorUtils_1.getCommonMappedErrorDetails)(error, initialProviderMessage);
307
+ let { errorCode, errorMessage, errorType, status, retryAfterMs } = (0, errorUtils_1.getCommonMappedErrorDetails)(error, initialProviderMessage);
285
308
  // Apply OpenAI-specific refinements for 400 errors based on message content
286
309
  if (error instanceof openai_1.default.APIError && status === 400) {
287
310
  if (error.message.toLowerCase().includes("context length")) {
@@ -301,6 +324,7 @@ class OpenAIClientAdapter {
301
324
  code: errorCode,
302
325
  type: errorType,
303
326
  ...(status && { status }),
327
+ ...(retryAfterMs !== undefined && { retryAfterMs }),
304
328
  providerError: error,
305
329
  },
306
330
  object: "error",
@@ -1,5 +1,6 @@
1
1
  import type { LLMResponse, LLMFailureResponse } from "../types";
2
- import type { ILLMClientAdapter, InternalLLMChatRequest } from "./types";
2
+ import type { ILLMClientAdapter, InternalLLMChatRequest, AdapterRequestOptions } from "./types";
3
+ import type { Logger } from "../../logging/types";
3
4
  /**
4
5
  * Configuration options for OpenRouterClientAdapter
5
6
  */
@@ -10,6 +11,8 @@ export interface OpenRouterClientConfig {
10
11
  httpReferer?: string;
11
12
  /** Your app's display name for rankings (optional) */
12
13
  siteTitle?: string;
14
+ /** Logger instance for adapter logging */
15
+ logger?: Logger;
13
16
  }
14
17
  /**
15
18
  * Client adapter for OpenRouter API integration
@@ -45,6 +48,7 @@ export declare class OpenRouterClientAdapter implements ILLMClientAdapter {
45
48
  private baseURL;
46
49
  private httpReferer?;
47
50
  private siteTitle?;
51
+ private logger;
48
52
  /**
49
53
  * Creates a new OpenRouter client adapter
50
54
  *
@@ -58,7 +62,7 @@ export declare class OpenRouterClientAdapter implements ILLMClientAdapter {
58
62
  * @param apiKey - The OpenRouter API key
59
63
  * @returns Promise resolving to success or failure response
60
64
  */
61
- sendMessage(request: InternalLLMChatRequest, apiKey: string): Promise<LLMResponse | LLMFailureResponse>;
65
+ sendMessage(request: InternalLLMChatRequest, apiKey: string, options?: AdapterRequestOptions): Promise<LLMResponse | LLMFailureResponse>;
62
66
  /**
63
67
  * Validates OpenRouter API key format
64
68
  *
@@ -9,9 +9,9 @@ exports.OpenRouterClientAdapter = void 0;
9
9
  const openai_1 = __importDefault(require("openai"));
10
10
  const types_1 = require("./types");
11
11
  const errorUtils_1 = require("../../shared/adapters/errorUtils");
12
+ const logprobsUtils_1 = require("../../shared/adapters/logprobsUtils");
12
13
  const systemMessageUtils_1 = require("../../shared/adapters/systemMessageUtils");
13
14
  const defaultLogger_1 = require("../../logging/defaultLogger");
14
- const logger = (0, defaultLogger_1.createDefaultLogger)();
15
15
  /**
16
16
  * Client adapter for OpenRouter API integration
17
17
  *
@@ -52,6 +52,7 @@ class OpenRouterClientAdapter {
52
52
  this.baseURL = config?.baseURL || 'https://openrouter.ai/api/v1';
53
53
  this.httpReferer = config?.httpReferer || process.env.OPENROUTER_HTTP_REFERER;
54
54
  this.siteTitle = config?.siteTitle || process.env.OPENROUTER_SITE_TITLE;
55
+ this.logger = config?.logger ?? (0, defaultLogger_1.createDefaultLogger)();
55
56
  }
56
57
  /**
57
58
  * Sends a chat message to OpenRouter API
@@ -60,11 +61,12 @@ class OpenRouterClientAdapter {
60
61
  * @param apiKey - The OpenRouter API key
61
62
  * @returns Promise resolving to success or failure response
62
63
  */
63
- async sendMessage(request, apiKey) {
64
+ async sendMessage(request, apiKey, options) {
64
65
  try {
65
66
  // Initialize OpenAI client with OpenRouter base URL and custom headers
66
67
  const openai = new openai_1.default({
67
68
  apiKey,
69
+ maxRetries: 0, // retries are owned by the unified LLMService retry layer
68
70
  baseURL: this.baseURL,
69
71
  defaultHeaders: {
70
72
  ...(this.httpReferer && { 'HTTP-Referer': this.httpReferer }),
@@ -89,6 +91,26 @@ class OpenRouterClientAdapter {
89
91
  ...(request.settings.presencePenalty !== 0 && {
90
92
  presence_penalty: request.settings.presencePenalty,
91
93
  }),
94
+ ...(request.settings.seed !== undefined && {
95
+ seed: request.settings.seed,
96
+ }),
97
+ // OpenRouter pass-through sampling params (not in the OpenAI SDK types;
98
+ // sent as-is — OpenRouter ignores them for models that don't support them)
99
+ ...(request.settings.topK !== undefined && {
100
+ top_k: request.settings.topK,
101
+ }),
102
+ ...(request.settings.minP !== undefined && {
103
+ min_p: request.settings.minP,
104
+ }),
105
+ ...(request.settings.repeatPenalty !== undefined && {
106
+ repetition_penalty: request.settings.repeatPenalty,
107
+ }),
108
+ ...(request.settings.logprobs === true && {
109
+ logprobs: true,
110
+ ...(request.settings.topLogprobs !== undefined && {
111
+ top_logprobs: request.settings.topLogprobs,
112
+ }),
113
+ }),
92
114
  };
93
115
  // Add OpenRouter-specific provider routing if configured
94
116
  const providerSettings = request.settings.openRouterProvider;
@@ -126,7 +148,31 @@ class OpenRouterClientAdapter {
126
148
  }
127
149
  };
128
150
  }
129
- logger.debug(`OpenRouter API parameters:`, {
151
+ // Map unified reasoning settings to OpenRouter's reasoning body param.
152
+ // effort and max_tokens are mutually exclusive on OpenRouter; max_tokens wins
153
+ // when both are set (matching the Anthropic adapter's precedence). OpenRouter
154
+ // silently ignores the param for models without reasoning support.
155
+ const reasoningSettings = request.settings.reasoning;
156
+ if (reasoningSettings &&
157
+ (reasoningSettings.enabled === true ||
158
+ reasoningSettings.effort !== undefined ||
159
+ reasoningSettings.maxTokens !== undefined)) {
160
+ const reasoning = {};
161
+ if (reasoningSettings.maxTokens !== undefined) {
162
+ reasoning.max_tokens = reasoningSettings.maxTokens;
163
+ }
164
+ else if (reasoningSettings.effort) {
165
+ reasoning.effort = reasoningSettings.effort;
166
+ }
167
+ else {
168
+ reasoning.enabled = true;
169
+ }
170
+ if (reasoningSettings.exclude === true) {
171
+ reasoning.exclude = true;
172
+ }
173
+ completionParams.reasoning = reasoning;
174
+ }
175
+ this.logger.debug(`OpenRouter API parameters:`, {
130
176
  baseURL: this.baseURL,
131
177
  model: completionParams.model,
132
178
  temperature: completionParams.temperature,
@@ -134,12 +180,18 @@ class OpenRouterClientAdapter {
134
180
  top_p: completionParams.top_p,
135
181
  hasProviderRouting: !!completionParams.provider,
136
182
  });
137
- logger.info(`Making OpenRouter API call for model: ${request.modelId}`);
183
+ this.logger.info(`Making OpenRouter API call for model: ${request.modelId}`);
138
184
  // Make the API call
139
- const completion = await openai.chat.completions.create(completionParams);
185
+ const transportOptions = {
186
+ ...(options?.signal && { signal: options.signal }),
187
+ ...(options?.timeoutMs !== undefined && { timeout: options.timeoutMs }),
188
+ };
189
+ const completion = Object.keys(transportOptions).length > 0
190
+ ? await openai.chat.completions.create(completionParams, transportOptions)
191
+ : await openai.chat.completions.create(completionParams);
140
192
  // Type guard to ensure we have a non-streaming response
141
193
  if ('id' in completion && 'choices' in completion) {
142
- logger.info(`OpenRouter API call successful, response ID: ${completion.id}`);
194
+ this.logger.info(`OpenRouter API call successful, response ID: ${completion.id}`);
143
195
  return this.createSuccessResponse(completion, request);
144
196
  }
145
197
  else {
@@ -147,7 +199,7 @@ class OpenRouterClientAdapter {
147
199
  }
148
200
  }
149
201
  catch (error) {
150
- logger.error("OpenRouter API error:", error);
202
+ this.logger.error("OpenRouter API error:", error);
151
203
  return this.createErrorResponse(error, request);
152
204
  }
153
205
  }
@@ -223,7 +275,7 @@ class OpenRouterClientAdapter {
223
275
  const modifiedIndex = (0, systemMessageUtils_1.prependSystemToFirstUserMessage)(simpleMessages, combinedSystemContent, request.settings.systemMessageFallback);
224
276
  if (modifiedIndex !== -1) {
225
277
  messages[modifiedIndex].content = simpleMessages[modifiedIndex].content;
226
- logger.debug(`Model ${request.modelId} doesn't support system messages - prepended to first user message`);
278
+ this.logger.debug(`Model ${request.modelId} doesn't support system messages - prepended to first user message`);
227
279
  }
228
280
  }
229
281
  }
@@ -246,14 +298,32 @@ class OpenRouterClientAdapter {
246
298
  provider: request.providerId,
247
299
  model: completion.model || request.modelId,
248
300
  created: completion.created,
249
- choices: completion.choices.map((c) => ({
250
- message: {
251
- role: "assistant",
252
- content: c.message.content || "",
253
- },
254
- finish_reason: c.finish_reason,
255
- index: c.index,
256
- })),
301
+ choices: completion.choices.map((c) => {
302
+ const mappedChoice = {
303
+ message: {
304
+ role: "assistant",
305
+ content: c.message.content || "",
306
+ },
307
+ finish_reason: c.finish_reason,
308
+ index: c.index,
309
+ };
310
+ // OpenRouter returns the reasoning trace on message.reasoning (plus
311
+ // structured reasoning_details) for models that expose it
312
+ const messageReasoning = c.message.reasoning;
313
+ if (messageReasoning && request.settings.reasoning?.exclude !== true) {
314
+ mappedChoice.reasoning = messageReasoning;
315
+ }
316
+ const reasoningDetails = c.message.reasoning_details;
317
+ if (reasoningDetails && request.settings.reasoning?.exclude !== true) {
318
+ mappedChoice.reasoning_details = reasoningDetails;
319
+ }
320
+ // Per-token log probabilities (OpenAI-compatible shape)
321
+ const logprobs = (0, logprobsUtils_1.mapOpenAIChatLogprobs)(c.logprobs);
322
+ if (logprobs) {
323
+ mappedChoice.logprobs = logprobs;
324
+ }
325
+ return mappedChoice;
326
+ }),
257
327
  usage: completion.usage
258
328
  ? {
259
329
  prompt_tokens: completion.usage.prompt_tokens,
@@ -289,6 +359,7 @@ class OpenRouterClientAdapter {
289
359
  code: mappedError.errorCode,
290
360
  type: mappedError.errorType,
291
361
  ...(mappedError.status && { status: mappedError.status }),
362
+ ...(mappedError.retryAfterMs !== undefined && { retryAfterMs: mappedError.retryAfterMs }),
292
363
  providerError: error,
293
364
  },
294
365
  object: "error",
@@ -6,6 +6,18 @@ import type { LLMChatRequest, LLMResponse, LLMFailureResponse, LLMSettings } fro
6
6
  export interface InternalLLMChatRequest extends Omit<LLMChatRequest, "settings"> {
7
7
  settings: Required<LLMSettings>;
8
8
  }
9
+ /**
10
+ * Per-request transport options passed from the service layer to adapters.
11
+ */
12
+ export interface AdapterRequestOptions {
13
+ /**
14
+ * Abort signal for cancelling the in-flight request. Note that aborting only
15
+ * cancels the client-side wait — the provider may still process (and bill) the request.
16
+ */
17
+ signal?: AbortSignal;
18
+ /** Request timeout in milliseconds (mapped to each SDK's timeout mechanism) */
19
+ timeoutMs?: number;
20
+ }
9
21
  /**
10
22
  * Interface that all LLM client adapters must implement
11
23
  *
@@ -22,11 +34,12 @@ export interface ILLMClientAdapter {
22
34
  *
23
35
  * @param request - The LLM request with applied default settings
24
36
  * @param apiKey - The decrypted API key for the provider
37
+ * @param options - Optional per-request transport options (abort signal, timeout)
25
38
  * @returns Promise resolving to either a successful response or failure response
26
39
  *
27
40
  * @throws Should not throw - all errors should be caught and returned as LLMFailureResponse
28
41
  */
29
- sendMessage(request: InternalLLMChatRequest, apiKey: string): Promise<LLMResponse | LLMFailureResponse>;
42
+ sendMessage(request: InternalLLMChatRequest, apiKey: string, options?: AdapterRequestOptions): Promise<LLMResponse | LLMFailureResponse>;
30
43
  /**
31
44
  * Optional method to validate API key format before making requests
32
45
  *
@@ -58,6 +71,10 @@ export declare const ADAPTER_ERROR_CODES: {
58
71
  readonly NETWORK_ERROR: "NETWORK_ERROR";
59
72
  readonly PROVIDER_ERROR: "PROVIDER_ERROR";
60
73
  readonly UNKNOWN_ERROR: "UNKNOWN_ERROR";
74
+ /** The request exceeded its timeout (retryable by default) */
75
+ readonly REQUEST_TIMEOUT: "REQUEST_TIMEOUT";
76
+ /** The request was cancelled via AbortSignal (never retried) */
77
+ readonly REQUEST_ABORTED: "REQUEST_ABORTED";
61
78
  };
62
79
  /**
63
80
  * Helper type for adapter error codes
@@ -16,4 +16,8 @@ exports.ADAPTER_ERROR_CODES = {
16
16
  NETWORK_ERROR: "NETWORK_ERROR",
17
17
  PROVIDER_ERROR: "PROVIDER_ERROR",
18
18
  UNKNOWN_ERROR: "UNKNOWN_ERROR",
19
+ /** The request exceeded its timeout (retryable by default) */
20
+ REQUEST_TIMEOUT: "REQUEST_TIMEOUT",
21
+ /** The request was cancelled via AbortSignal (never retried) */
22
+ REQUEST_ABORTED: "REQUEST_ABORTED",
19
23
  };
@@ -50,7 +50,11 @@ export interface GgufModelPattern {
50
50
  * Order matters: more specific patterns should come before generic ones.
51
51
  * First matching pattern wins.
52
52
  *
53
- * Example: "Qwen3-0.6B-0522" should be before "Qwen3-0.6B"
53
+ * Ordering rules (see docs/dev/adding-models-and-providers.md):
54
+ * - Specific before generic: "qwen3-4b-instruct-2507" before "qwen3-4b"
55
+ * - Newer family names before older substrings they contain: "qwen3.5" contains no
56
+ * "qwen3-" (the dot breaks the match) but is listed first anyway for clarity
57
+ * - Quantization agnostic: never embed Q4_K_M/Q8_0 in patterns
54
58
  */
55
59
  export declare const KNOWN_GGUF_MODELS: GgufModelPattern[];
56
60
  /**
@@ -131,9 +135,12 @@ export declare function createFallbackModelInfo(modelId: string, providerId: str
131
135
  *
132
136
  * @param modelId - The model ID
133
137
  * @param providerId - The provider ID
138
+ * @param resolvedModelInfo - Optional already-resolved ModelInfo (e.g. a detected GGUF
139
+ * model's fallback info). When provided it is used instead of a registry lookup, so
140
+ * capabilities and defaultSettings of dynamically-detected models flow into settings.
134
141
  * @returns Merged default settings with model-specific overrides applied
135
142
  */
136
- export declare function getDefaultSettingsForModel(modelId: string, providerId: ApiProviderId): Required<LLMSettings>;
143
+ export declare function getDefaultSettingsForModel(modelId: string, providerId: ApiProviderId, resolvedModelInfo?: ModelInfo): Required<LLMSettings>;
137
144
  /**
138
145
  * Validates LLM settings values
139
146
  *