orchid-ai 1.2.2 → 1.2.4
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 +3 -3
- package/dist/cli/components/ChatPanel.d.ts +2 -1
- package/dist/cli/components/Conversation.d.ts +2 -1
- package/dist/cli/components/ModelSwitcher.d.ts +2 -1
- package/dist/cli/hooks/useModelSwitcher.d.ts +7 -4
- package/dist/cli/hooks/useResolvedDefaultModel.d.ts +21 -0
- package/dist/cli/hooks/useStreamingAI.d.ts +3 -2
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/server/contextual-service.d.ts +49 -1
- package/dist/cli/server/intent-detection.d.ts +2 -0
- package/dist/cli/server/utils.d.ts +0 -12
- package/dist/cli/types/types.d.ts +2 -1
- package/dist/components/ChatPanel.d.ts +2 -1
- package/dist/components/Conversation.d.ts +2 -1
- package/dist/components/ModelSwitcher.d.ts +2 -1
- package/dist/hooks/useModelSwitcher.d.ts +7 -4
- package/dist/hooks/useResolvedDefaultModel.d.ts +21 -0
- package/dist/hooks/useStreamingAI.d.ts +3 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.esm.js +425 -39
- package/dist/index.js +425 -38
- package/dist/server/components/ChatPanel.d.ts +2 -1
- package/dist/server/components/Conversation.d.ts +2 -1
- package/dist/server/components/ModelSwitcher.d.ts +2 -1
- package/dist/server/contextual-service.d.ts +49 -1
- package/dist/server/hooks/useModelSwitcher.d.ts +7 -4
- package/dist/server/hooks/useResolvedDefaultModel.d.ts +21 -0
- package/dist/server/hooks/useStreamingAI.d.ts +3 -2
- package/dist/server/index.esm.js +507 -151
- package/dist/server/index.js +473 -99
- package/dist/server/intent-detection.d.ts +2 -0
- package/dist/server/server/contextual-service.d.ts +49 -1
- package/dist/server/server/intent-detection.d.ts +2 -0
- package/dist/server/server/utils.d.ts +0 -12
- package/dist/server/types/types.d.ts +2 -1
- package/dist/server/utils.d.ts +0 -12
- package/dist/types/types.d.ts +2 -1
- package/package.json +1 -1
package/dist/server/index.esm.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import express from 'express';
|
|
2
2
|
import http from 'http';
|
|
3
|
-
import path$a from 'path';
|
|
4
|
-
import
|
|
3
|
+
import * as path$a from 'path';
|
|
4
|
+
import path__default from 'path';
|
|
5
|
+
import * as fs$8 from 'fs';
|
|
6
|
+
import fs__default from 'fs';
|
|
5
7
|
import require$$0 from 'os';
|
|
6
8
|
import require$$0$1 from 'util';
|
|
7
9
|
import require$$0$2 from 'stream';
|
|
@@ -79,7 +81,7 @@ var path$9 = {};
|
|
|
79
81
|
Object.defineProperty(path$9, "__esModule", { value: true });
|
|
80
82
|
path$9.convertPosixPathToPattern = path$9.convertWindowsPathToPattern = path$9.convertPathToPattern = path$9.escapePosixPath = path$9.escapeWindowsPath = path$9.escape = path$9.removeLeadingDotSegment = path$9.makeAbsolute = path$9.unixify = void 0;
|
|
81
83
|
const os = require$$0;
|
|
82
|
-
const path$8 =
|
|
84
|
+
const path$8 = path__default;
|
|
83
85
|
const IS_WINDOWS_PLATFORM = os.platform() === 'win32';
|
|
84
86
|
const LEADING_DOT_SEGMENT_CHARACTERS_COUNT = 2; // ./ or .\\
|
|
85
87
|
/**
|
|
@@ -319,7 +321,7 @@ var isGlob$1 = function isGlob(str, options) {
|
|
|
319
321
|
};
|
|
320
322
|
|
|
321
323
|
var isGlob = isGlob$1;
|
|
322
|
-
var pathPosixDirname =
|
|
324
|
+
var pathPosixDirname = path__default.posix.dirname;
|
|
323
325
|
var isWin32 = require$$0.platform() === 'win32';
|
|
324
326
|
|
|
325
327
|
var slash = '/';
|
|
@@ -1758,7 +1760,7 @@ var braces_1 = braces$1;
|
|
|
1758
1760
|
|
|
1759
1761
|
var utils$f = {};
|
|
1760
1762
|
|
|
1761
|
-
const path$7 =
|
|
1763
|
+
const path$7 = path__default;
|
|
1762
1764
|
const WIN_SLASH = '\\\\/';
|
|
1763
1765
|
const WIN_NO_SLASH = `[^${WIN_SLASH}]`;
|
|
1764
1766
|
|
|
@@ -1938,7 +1940,7 @@ var constants$3 = {
|
|
|
1938
1940
|
|
|
1939
1941
|
(function (exports) {
|
|
1940
1942
|
|
|
1941
|
-
const path =
|
|
1943
|
+
const path = path__default;
|
|
1942
1944
|
const win32 = process.platform === 'win32';
|
|
1943
1945
|
const {
|
|
1944
1946
|
REGEX_BACKSLASH,
|
|
@@ -3482,7 +3484,7 @@ parse$1.fastpaths = (input, options) => {
|
|
|
3482
3484
|
|
|
3483
3485
|
var parse_1 = parse$1;
|
|
3484
3486
|
|
|
3485
|
-
const path$6 =
|
|
3487
|
+
const path$6 = path__default;
|
|
3486
3488
|
const scan = scan_1;
|
|
3487
3489
|
const parse = parse_1;
|
|
3488
3490
|
const utils$c = utils$f;
|
|
@@ -4300,7 +4302,7 @@ var micromatch_1 = micromatch$1;
|
|
|
4300
4302
|
|
|
4301
4303
|
Object.defineProperty(pattern$1, "__esModule", { value: true });
|
|
4302
4304
|
pattern$1.isAbsolute = pattern$1.partitionAbsoluteAndRelative = pattern$1.removeDuplicateSlashes = pattern$1.matchAny = pattern$1.convertPatternsToRe = pattern$1.makeRe = pattern$1.getPatternParts = pattern$1.expandBraceExpansion = pattern$1.expandPatternsWithBraceExpansion = pattern$1.isAffectDepthOfReadingPattern = pattern$1.endsWithSlashGlobStar = pattern$1.hasGlobStar = pattern$1.getBaseDirectory = pattern$1.isPatternRelatedToParentDirectory = pattern$1.getPatternsOutsideCurrentDirectory = pattern$1.getPatternsInsideCurrentDirectory = pattern$1.getPositivePatterns = pattern$1.getNegativePatterns = pattern$1.isPositivePattern = pattern$1.isNegativePattern = pattern$1.convertToNegativePattern = pattern$1.convertToPositivePattern = pattern$1.isDynamicPattern = pattern$1.isStaticPattern = void 0;
|
|
4303
|
-
const path$5 =
|
|
4305
|
+
const path$5 = path__default;
|
|
4304
4306
|
const globParent = globParent$1;
|
|
4305
4307
|
const micromatch = micromatch_1;
|
|
4306
4308
|
const GLOBSTAR = '**';
|
|
@@ -4893,7 +4895,7 @@ var fs$5 = {};
|
|
|
4893
4895
|
(function (exports) {
|
|
4894
4896
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4895
4897
|
exports.createFileSystemAdapter = exports.FILE_SYSTEM_ADAPTER = void 0;
|
|
4896
|
-
const fs =
|
|
4898
|
+
const fs = fs__default;
|
|
4897
4899
|
exports.FILE_SYSTEM_ADAPTER = {
|
|
4898
4900
|
lstat: fs.lstat,
|
|
4899
4901
|
stat: fs.stat,
|
|
@@ -5244,7 +5246,7 @@ var fs$1 = {};
|
|
|
5244
5246
|
(function (exports) {
|
|
5245
5247
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5246
5248
|
exports.createFileSystemAdapter = exports.FILE_SYSTEM_ADAPTER = void 0;
|
|
5247
|
-
const fs =
|
|
5249
|
+
const fs = fs__default;
|
|
5248
5250
|
exports.FILE_SYSTEM_ADAPTER = {
|
|
5249
5251
|
lstat: fs.lstat,
|
|
5250
5252
|
stat: fs.stat,
|
|
@@ -5263,7 +5265,7 @@ var fs$1 = {};
|
|
|
5263
5265
|
} (fs$1));
|
|
5264
5266
|
|
|
5265
5267
|
Object.defineProperty(settings$2, "__esModule", { value: true });
|
|
5266
|
-
const path$3 =
|
|
5268
|
+
const path$3 = path__default;
|
|
5267
5269
|
const fsStat$3 = out$1;
|
|
5268
5270
|
const fs = fs$1;
|
|
5269
5271
|
let Settings$1 = class Settings {
|
|
@@ -5947,7 +5949,7 @@ sync$3.default = SyncProvider;
|
|
|
5947
5949
|
var settings$1 = {};
|
|
5948
5950
|
|
|
5949
5951
|
Object.defineProperty(settings$1, "__esModule", { value: true });
|
|
5950
|
-
const path$2 =
|
|
5952
|
+
const path$2 = path__default;
|
|
5951
5953
|
const fsScandir = out$2;
|
|
5952
5954
|
class Settings {
|
|
5953
5955
|
constructor(_options = {}) {
|
|
@@ -6009,7 +6011,7 @@ function getSettings(settingsOrOptions = {}) {
|
|
|
6009
6011
|
var reader = {};
|
|
6010
6012
|
|
|
6011
6013
|
Object.defineProperty(reader, "__esModule", { value: true });
|
|
6012
|
-
const path$1 =
|
|
6014
|
+
const path$1 = path__default;
|
|
6013
6015
|
const fsStat$2 = out$1;
|
|
6014
6016
|
const utils$6 = utils$k;
|
|
6015
6017
|
class Reader {
|
|
@@ -6419,7 +6421,7 @@ class EntryTransformer {
|
|
|
6419
6421
|
entry.default = EntryTransformer;
|
|
6420
6422
|
|
|
6421
6423
|
Object.defineProperty(provider, "__esModule", { value: true });
|
|
6422
|
-
const path =
|
|
6424
|
+
const path = path__default;
|
|
6423
6425
|
const deep_1 = deep;
|
|
6424
6426
|
const entry_1 = entry$1;
|
|
6425
6427
|
const error_1 = error;
|
|
@@ -6597,7 +6599,7 @@ var settings = {};
|
|
|
6597
6599
|
(function (exports) {
|
|
6598
6600
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6599
6601
|
exports.DEFAULT_FILE_SYSTEM_ADAPTER = void 0;
|
|
6600
|
-
const fs =
|
|
6602
|
+
const fs = fs__default;
|
|
6601
6603
|
const os = require$$0;
|
|
6602
6604
|
/**
|
|
6603
6605
|
* The `os.cpus` method can return zero. We expect the number of cores to be greater than zero.
|
|
@@ -6759,7 +6761,7 @@ var fg = /*@__PURE__*/getDefaultExportFromCjs(out);
|
|
|
6759
6761
|
|
|
6760
6762
|
const DEFAULT_CONFIG = {
|
|
6761
6763
|
service: 'claude',
|
|
6762
|
-
model: 'claude-sonnet-4-
|
|
6764
|
+
model: 'claude-sonnet-4-5-20250929', // Updated to use newer 4.5 model
|
|
6763
6765
|
temperature: 0.7,
|
|
6764
6766
|
maxTokens: 4096,
|
|
6765
6767
|
chatLevel: 'none',
|
|
@@ -7156,7 +7158,7 @@ const noneChatInstructions = genericInstructions +
|
|
|
7156
7158
|
"action": "Create John Smith",
|
|
7157
7159
|
"actionType": "create",
|
|
7158
7160
|
"path": "/users/add",
|
|
7159
|
-
"formState": {"
|
|
7161
|
+
"formState": {"firstName": "John", "lastName": "Smith", "email": "john@example.com", "role": "user"}
|
|
7160
7162
|
}
|
|
7161
7163
|
]
|
|
7162
7164
|
|
|
@@ -7583,7 +7585,7 @@ class CommandTrainingCollector {
|
|
|
7583
7585
|
if (files.length > 0) {
|
|
7584
7586
|
this.log(`✅ Found ${files.length} ${type}:`);
|
|
7585
7587
|
files.forEach((file) => {
|
|
7586
|
-
this.log(` 📄 ${
|
|
7588
|
+
this.log(` 📄 ${path__default.relative(this.rootDir, file.filePath)}`);
|
|
7587
7589
|
});
|
|
7588
7590
|
}
|
|
7589
7591
|
else {
|
|
@@ -7818,9 +7820,9 @@ class CommandTrainingCollector {
|
|
|
7818
7820
|
const results = await Promise.all(expandedPaths.map(async (filePath) => {
|
|
7819
7821
|
try {
|
|
7820
7822
|
// Read and process the file
|
|
7821
|
-
const content = await
|
|
7823
|
+
const content = await fs__default.promises.readFile(filePath, 'utf8');
|
|
7822
7824
|
const extractedInfo = this.extractFileInfo(fieldName, content);
|
|
7823
|
-
const relativePath =
|
|
7825
|
+
const relativePath = path__default.relative(this.rootDir, filePath);
|
|
7824
7826
|
// Log what we found in the file
|
|
7825
7827
|
const foundItems = Object.keys(extractedInfo).length;
|
|
7826
7828
|
if (foundItems > 0) {
|
|
@@ -7855,8 +7857,8 @@ class CommandTrainingCollector {
|
|
|
7855
7857
|
for (const pattern of patterns) {
|
|
7856
7858
|
try {
|
|
7857
7859
|
// Check if it's a direct file path first
|
|
7858
|
-
const fullPath =
|
|
7859
|
-
const exists = await
|
|
7860
|
+
const fullPath = path__default.join(this.rootDir, pattern);
|
|
7861
|
+
const exists = await fs__default.promises
|
|
7860
7862
|
.access(fullPath)
|
|
7861
7863
|
.then(() => true)
|
|
7862
7864
|
.catch(() => false);
|
|
@@ -7875,7 +7877,7 @@ class CommandTrainingCollector {
|
|
|
7875
7877
|
});
|
|
7876
7878
|
if (matches.length > 0) {
|
|
7877
7879
|
this.log(`✅ Found ${matches.length} files matching pattern: ${pattern}`);
|
|
7878
|
-
matches.forEach((match) => this.log(` - ${
|
|
7880
|
+
matches.forEach((match) => this.log(` - ${path__default.relative(this.rootDir, match)}`));
|
|
7879
7881
|
}
|
|
7880
7882
|
else {
|
|
7881
7883
|
this.log(`⚠️ No files found matching pattern: ${pattern}`);
|
|
@@ -8348,20 +8350,35 @@ function getModelSupportsImages(modelId, provider) {
|
|
|
8348
8350
|
openai: {
|
|
8349
8351
|
'gpt-4o': true,
|
|
8350
8352
|
'gpt-4o-mini': true,
|
|
8351
|
-
'gpt-4-vision-preview': true,
|
|
8352
8353
|
'gpt-4-turbo': true,
|
|
8353
8354
|
'gpt-4-turbo-2024-04-09': true,
|
|
8355
|
+
'gpt-4-turbo-preview': true,
|
|
8356
|
+
'gpt-4-vision-preview': true,
|
|
8357
|
+
'gpt-4-0125-preview': true,
|
|
8358
|
+
'gpt-4-1106-preview': true,
|
|
8359
|
+
'gpt-5-nano-2025-08-07': false, // Note: add when known
|
|
8360
|
+
'gpt-5-search-api-2025-10-14': false, // Note: add when known
|
|
8361
|
+
'gpt-4o-transcribe-diarize': false, // Audio model, not images
|
|
8354
8362
|
'gpt-3.5-turbo': false,
|
|
8355
8363
|
'gpt-4': false,
|
|
8364
|
+
'gpt-4-0613': false,
|
|
8356
8365
|
},
|
|
8357
|
-
// Claude models - all Claude 3+ models support images
|
|
8366
|
+
// Claude models - all Claude 3+ and 4+ models support images
|
|
8358
8367
|
claude: {
|
|
8368
|
+
// Claude 3.x models
|
|
8359
8369
|
'claude-3-haiku-20240307': true,
|
|
8360
8370
|
'claude-3-sonnet-20240229': true,
|
|
8361
8371
|
'claude-3-opus-20240229': true,
|
|
8362
8372
|
'claude-3-5-haiku-20241022': true,
|
|
8363
8373
|
'claude-3-5-sonnet-20241022': true,
|
|
8364
8374
|
'claude-3-7-sonnet-20250219': true,
|
|
8375
|
+
// Claude 4.x models (newer naming)
|
|
8376
|
+
'claude-opus-4-20250514': true,
|
|
8377
|
+
'claude-opus-4-1-20250805': true,
|
|
8378
|
+
'claude-sonnet-4-20250514': true,
|
|
8379
|
+
'claude-sonnet-4-5-20250929': true,
|
|
8380
|
+
'claude-haiku-4-5-20251001': true,
|
|
8381
|
+
// Claude 2.x and older - no image support
|
|
8365
8382
|
'claude-2.1': false,
|
|
8366
8383
|
'claude-2.0': false,
|
|
8367
8384
|
'claude-instant-1.2': false,
|
|
@@ -8371,6 +8388,10 @@ function getModelSupportsImages(modelId, provider) {
|
|
|
8371
8388
|
'gemini-1.5-flash': true,
|
|
8372
8389
|
'gemini-1.5-pro': true,
|
|
8373
8390
|
'gemini-2.0-flash-exp': true,
|
|
8391
|
+
'gemini-2.0-flash-thinking-exp-1219': true,
|
|
8392
|
+
'gemini-2.5-pro': true,
|
|
8393
|
+
'gemini-2.5-flash': true,
|
|
8394
|
+
'gemini-2.5-flash-lite': true,
|
|
8374
8395
|
'gemini-pro': false,
|
|
8375
8396
|
'gemini-pro-vision': true,
|
|
8376
8397
|
},
|
|
@@ -8382,9 +8403,16 @@ function getModelSupportsImages(modelId, provider) {
|
|
|
8382
8403
|
if (modelId in providerSupport) {
|
|
8383
8404
|
return providerSupport[modelId];
|
|
8384
8405
|
}
|
|
8385
|
-
// For Claude models, assume true if it's a claude-3+ model
|
|
8386
|
-
|
|
8387
|
-
|
|
8406
|
+
// For Claude models, assume true if it's a claude-3+ or claude-4+ model
|
|
8407
|
+
// Also handle claude-sonnet-4, claude-opus-4, claude-haiku-4 pattern
|
|
8408
|
+
if (provider?.toLowerCase() === 'claude') {
|
|
8409
|
+
if (modelId.startsWith('claude-3') || modelId.startsWith('claude-4')) {
|
|
8410
|
+
return true;
|
|
8411
|
+
}
|
|
8412
|
+
// Handle newer naming like claude-sonnet-4, claude-opus-4, claude-haiku-4
|
|
8413
|
+
if (modelId.match(/claude-(?:sonnet|opus|haiku)-\d/)) {
|
|
8414
|
+
return true;
|
|
8415
|
+
}
|
|
8388
8416
|
}
|
|
8389
8417
|
// For OpenAI, assume false unless explicitly listed
|
|
8390
8418
|
if (provider?.toLowerCase() === 'openai') {
|
|
@@ -8397,6 +8425,32 @@ function getModelSupportsImages(modelId, provider) {
|
|
|
8397
8425
|
return false;
|
|
8398
8426
|
}
|
|
8399
8427
|
function getDefaultModelsForProvider(provider) {
|
|
8428
|
+
// Try to get from cache first
|
|
8429
|
+
try {
|
|
8430
|
+
// Dynamic import to avoid circular dependency
|
|
8431
|
+
const { ContextualCommandService } = require('./contextual-service.js');
|
|
8432
|
+
const cachedModels = ContextualCommandService.getCachedModelsSync();
|
|
8433
|
+
if (cachedModels && cachedModels.length > 0) {
|
|
8434
|
+
const providerModels = cachedModels.filter((m) => m.provider.toLowerCase() === provider.toLowerCase());
|
|
8435
|
+
if (providerModels.length > 0) {
|
|
8436
|
+
// Sort by computeWeight (lowest = cheapest/fastest first)
|
|
8437
|
+
const sorted = providerModels.sort((a, b) => (a.computeWeight ?? 0.5) - (b.computeWeight ?? 0.5));
|
|
8438
|
+
// Return top 3 models for the provider
|
|
8439
|
+
return sorted.slice(0, 3).map((model) => ({
|
|
8440
|
+
id: model.id,
|
|
8441
|
+
name: model.name,
|
|
8442
|
+
provider: model.provider,
|
|
8443
|
+
available: model.available,
|
|
8444
|
+
supportsImages: model.supportsImages ?? getModelSupportsImages(model.id, model.provider),
|
|
8445
|
+
computeWeight: model.computeWeight,
|
|
8446
|
+
}));
|
|
8447
|
+
}
|
|
8448
|
+
}
|
|
8449
|
+
}
|
|
8450
|
+
catch (error) {
|
|
8451
|
+
// Silently fall through to defaults
|
|
8452
|
+
}
|
|
8453
|
+
// Fallback to hardcoded defaults if cache unavailable
|
|
8400
8454
|
const defaultModels = {
|
|
8401
8455
|
openai: [
|
|
8402
8456
|
{
|
|
@@ -8416,18 +8470,18 @@ function getDefaultModelsForProvider(provider) {
|
|
|
8416
8470
|
],
|
|
8417
8471
|
claude: [
|
|
8418
8472
|
{
|
|
8419
|
-
id: 'claude-
|
|
8420
|
-
name: 'Claude
|
|
8473
|
+
id: 'claude-haiku-4-5-20251001',
|
|
8474
|
+
name: 'Claude 4.5 Haiku',
|
|
8421
8475
|
provider: 'claude',
|
|
8422
8476
|
available: true,
|
|
8423
|
-
supportsImages: getModelSupportsImages('claude-
|
|
8477
|
+
supportsImages: getModelSupportsImages('claude-haiku-4-5-20251001', 'claude'),
|
|
8424
8478
|
},
|
|
8425
8479
|
{
|
|
8426
|
-
id: 'claude-
|
|
8427
|
-
name: 'Claude
|
|
8480
|
+
id: 'claude-sonnet-4-5-20250929',
|
|
8481
|
+
name: 'Claude 4.5 Sonnet',
|
|
8428
8482
|
provider: 'claude',
|
|
8429
8483
|
available: true,
|
|
8430
|
-
supportsImages: getModelSupportsImages('claude-
|
|
8484
|
+
supportsImages: getModelSupportsImages('claude-sonnet-4-5-20250929', 'claude'),
|
|
8431
8485
|
},
|
|
8432
8486
|
],
|
|
8433
8487
|
gemini: [
|
|
@@ -10207,7 +10261,7 @@ class CommandService {
|
|
|
10207
10261
|
// Default models for each provider
|
|
10208
10262
|
const defaultModels = {
|
|
10209
10263
|
openai: ['gpt-3.5-turbo', 'gpt-4'],
|
|
10210
|
-
claude: ['claude-
|
|
10264
|
+
claude: ['claude-haiku-4-5-20251001', 'claude-sonnet-4-5-20250929'],
|
|
10211
10265
|
gemini: ['gemini-pro'],
|
|
10212
10266
|
};
|
|
10213
10267
|
// Configure each provider that has an API key
|
|
@@ -10383,8 +10437,8 @@ class CommandService {
|
|
|
10383
10437
|
return;
|
|
10384
10438
|
}
|
|
10385
10439
|
// Write to file
|
|
10386
|
-
const configPath =
|
|
10387
|
-
await
|
|
10440
|
+
const configPath = path__default.join(process.cwd(), 'ai-command-config.json');
|
|
10441
|
+
await fs__default.promises.writeFile(configPath, JSON.stringify(configToWrite, null, 2), 'utf8');
|
|
10388
10442
|
this.log(`✅ CommandService: Config written to file: ${configPath}`);
|
|
10389
10443
|
}
|
|
10390
10444
|
catch (error) {
|
|
@@ -10394,7 +10448,7 @@ class CommandService {
|
|
|
10394
10448
|
async writeFailedJsonToFile(failedJson, errorMessage) {
|
|
10395
10449
|
try {
|
|
10396
10450
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
10397
|
-
const debugPath =
|
|
10451
|
+
const debugPath = path__default.join(process.cwd(), `failed-json-${timestamp}.json`);
|
|
10398
10452
|
const debugData = {
|
|
10399
10453
|
timestamp: new Date().toISOString(),
|
|
10400
10454
|
error: errorMessage,
|
|
@@ -10403,7 +10457,7 @@ class CommandService {
|
|
|
10403
10457
|
// Also include a prettified version for easier reading
|
|
10404
10458
|
prettyJson: this.tryPrettifyJson(failedJson),
|
|
10405
10459
|
};
|
|
10406
|
-
await
|
|
10460
|
+
await fs__default.promises.writeFile(debugPath, JSON.stringify(debugData, null, 2));
|
|
10407
10461
|
this.log('📁 Failed JSON written to file:', debugPath);
|
|
10408
10462
|
}
|
|
10409
10463
|
catch (error) {
|
|
@@ -12729,22 +12783,24 @@ async function setupCommandServer(options = {}) {
|
|
|
12729
12783
|
// Create the command configuration
|
|
12730
12784
|
// Build providers configuration with all available API keys
|
|
12731
12785
|
const availableProviders = {};
|
|
12786
|
+
// These model lists are just placeholders - the actual models will be auto-discovered
|
|
12787
|
+
// from the provider APIs and cached. The models here are only used for legacy compatibility.
|
|
12732
12788
|
if (openaiApiKey) {
|
|
12733
12789
|
availableProviders.openai = {
|
|
12734
12790
|
apiKey: openaiApiKey,
|
|
12735
|
-
models: [
|
|
12791
|
+
models: [], // Models will be auto-discovered from API
|
|
12736
12792
|
};
|
|
12737
12793
|
}
|
|
12738
12794
|
if (claudeApiKey) {
|
|
12739
12795
|
availableProviders.claude = {
|
|
12740
12796
|
apiKey: claudeApiKey,
|
|
12741
|
-
models: [
|
|
12797
|
+
models: [], // Models will be auto-discovered from API
|
|
12742
12798
|
};
|
|
12743
12799
|
}
|
|
12744
12800
|
if (geminiApiKey) {
|
|
12745
12801
|
availableProviders.gemini = {
|
|
12746
12802
|
apiKey: geminiApiKey,
|
|
12747
|
-
models: [
|
|
12803
|
+
models: [], // Models will be auto-discovered from API
|
|
12748
12804
|
};
|
|
12749
12805
|
}
|
|
12750
12806
|
// Add custom providers if provided
|
|
@@ -13239,6 +13295,9 @@ async function collectTrainingData(config) {
|
|
|
13239
13295
|
*/
|
|
13240
13296
|
class ContextualCommandService {
|
|
13241
13297
|
config;
|
|
13298
|
+
modelsCache = null;
|
|
13299
|
+
cacheFilePath;
|
|
13300
|
+
CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours in milliseconds
|
|
13242
13301
|
verboseLogging;
|
|
13243
13302
|
usage;
|
|
13244
13303
|
constructor(config) {
|
|
@@ -13254,8 +13313,55 @@ class ContextualCommandService {
|
|
|
13254
13313
|
currentProvider: '',
|
|
13255
13314
|
currentModel: '',
|
|
13256
13315
|
};
|
|
13316
|
+
// Set up cache file path (store in node_modules/.cache or process.cwd())
|
|
13317
|
+
const cacheDir = path$a.join(process.cwd(), '.cache', 'orchid-ai');
|
|
13318
|
+
if (!fs$8.existsSync(cacheDir)) {
|
|
13319
|
+
fs$8.mkdirSync(cacheDir, { recursive: true });
|
|
13320
|
+
}
|
|
13321
|
+
this.cacheFilePath = path$a.join(cacheDir, 'models-cache.json');
|
|
13322
|
+
// Load cache on initialization
|
|
13323
|
+
this.loadModelsCache();
|
|
13257
13324
|
this.autoConfigureProviders();
|
|
13258
13325
|
}
|
|
13326
|
+
/**
|
|
13327
|
+
* Load models cache from file if it exists and is fresh
|
|
13328
|
+
*/
|
|
13329
|
+
loadModelsCache() {
|
|
13330
|
+
try {
|
|
13331
|
+
if (fs$8.existsSync(this.cacheFilePath)) {
|
|
13332
|
+
const cacheData = fs$8.readFileSync(this.cacheFilePath, 'utf8');
|
|
13333
|
+
const cache = JSON.parse(cacheData);
|
|
13334
|
+
const age = Date.now() - cache.timestamp;
|
|
13335
|
+
if (age < this.CACHE_TTL_MS) {
|
|
13336
|
+
this.modelsCache = cache;
|
|
13337
|
+
this.log(`📦 Loaded models cache (age: ${Math.round(age / 1000 / 60)} minutes, ${cache.models.length} models)`);
|
|
13338
|
+
}
|
|
13339
|
+
else {
|
|
13340
|
+
this.log(`⏰ Models cache expired (age: ${Math.round(age / 1000 / 60 / 60)} hours), will refresh`);
|
|
13341
|
+
}
|
|
13342
|
+
}
|
|
13343
|
+
}
|
|
13344
|
+
catch (error) {
|
|
13345
|
+
this.log('⚠️ Could not load models cache:', error instanceof Error ? error.message : String(error));
|
|
13346
|
+
}
|
|
13347
|
+
}
|
|
13348
|
+
/**
|
|
13349
|
+
* Save models cache to file
|
|
13350
|
+
*/
|
|
13351
|
+
saveModelsCache(models) {
|
|
13352
|
+
try {
|
|
13353
|
+
const cache = {
|
|
13354
|
+
timestamp: Date.now(),
|
|
13355
|
+
models,
|
|
13356
|
+
};
|
|
13357
|
+
fs$8.writeFileSync(this.cacheFilePath, JSON.stringify(cache, null, 2), 'utf8');
|
|
13358
|
+
this.modelsCache = cache;
|
|
13359
|
+
this.log(`💾 Saved models cache (${models.length} models) to ${this.cacheFilePath}`);
|
|
13360
|
+
}
|
|
13361
|
+
catch (error) {
|
|
13362
|
+
this.log('⚠️ Could not save models cache:', error instanceof Error ? error.message : String(error));
|
|
13363
|
+
}
|
|
13364
|
+
}
|
|
13259
13365
|
autoConfigureProviders() {
|
|
13260
13366
|
const apiKeys = {
|
|
13261
13367
|
openai: this.config.openaiApiKey || process.env.OPENAI_API_KEY,
|
|
@@ -13479,8 +13585,6 @@ ${additionalContext}
|
|
|
13479
13585
|
`;
|
|
13480
13586
|
}
|
|
13481
13587
|
const fullPrompt = `${baseInstructions}${schemaInstructions}${contextSection}`;
|
|
13482
|
-
// Debug: Log the system prompt being sent to AI
|
|
13483
|
-
this.log('🔍 [SYSTEM PROMPT DEBUG] Full system prompt:', fullPrompt);
|
|
13484
13588
|
return fullPrompt;
|
|
13485
13589
|
}
|
|
13486
13590
|
/**
|
|
@@ -13551,14 +13655,48 @@ ${additionalContext}
|
|
|
13551
13655
|
async streamSuggestions(request, onData, onDone, onError) {
|
|
13552
13656
|
const { command, schema, chatHistory = [], modelSelection, chatLevel = this.config.chatLevel || 'none', additionalContext, images = [], } = request;
|
|
13553
13657
|
try {
|
|
13554
|
-
this.log('🚀 [CONTEXTUAL STREAM] Starting with schema:', schema?.title || 'none');
|
|
13555
13658
|
// Create model for this request
|
|
13556
|
-
|
|
13557
|
-
|
|
13558
|
-
|
|
13559
|
-
|
|
13560
|
-
|
|
13561
|
-
|
|
13659
|
+
let finalModelSelection = modelSelection;
|
|
13660
|
+
if (!finalModelSelection) {
|
|
13661
|
+
// Use tier-based default (fast/cheapest tier)
|
|
13662
|
+
const defaultProvider = Object.keys(this.config.providers || {})[0] || DEFAULT_CONFIG.service;
|
|
13663
|
+
this.log(`⚠️ [MODEL SELECTION] No modelSelection provided, using default provider: ${defaultProvider}`);
|
|
13664
|
+
const defaultModel = await this.getDefaultModelByTier(defaultProvider, 'fast');
|
|
13665
|
+
// Use dynamic default instead of hardcoded DEFAULT_CONFIG.model
|
|
13666
|
+
const fallbackModel = defaultModel || await this.getLatestDefaultModel(defaultProvider);
|
|
13667
|
+
finalModelSelection = {
|
|
13668
|
+
provider: defaultProvider,
|
|
13669
|
+
model: fallbackModel,
|
|
13670
|
+
};
|
|
13671
|
+
this.log(`📋 [MODEL SELECTION] Using default model for ${defaultProvider}: ${finalModelSelection.model}`);
|
|
13672
|
+
}
|
|
13673
|
+
else if (finalModelSelection.provider && !finalModelSelection.model) {
|
|
13674
|
+
// Provider specified but no model - auto-select from tier
|
|
13675
|
+
const tier = finalModelSelection.tier || 'fast';
|
|
13676
|
+
const selectedModel = await this.getDefaultModelByTier(finalModelSelection.provider, tier);
|
|
13677
|
+
if (!selectedModel) {
|
|
13678
|
+
}
|
|
13679
|
+
// Use dynamic default instead of hardcoded DEFAULT_CONFIG.model
|
|
13680
|
+
const fallbackModel = selectedModel || await this.getLatestDefaultModel(finalModelSelection.provider);
|
|
13681
|
+
finalModelSelection = {
|
|
13682
|
+
provider: finalModelSelection.provider,
|
|
13683
|
+
model: fallbackModel,
|
|
13684
|
+
};
|
|
13685
|
+
}
|
|
13686
|
+
else if (finalModelSelection.model) {
|
|
13687
|
+
}
|
|
13688
|
+
// Ensure model is always defined before creating request model
|
|
13689
|
+
if (!finalModelSelection.model) {
|
|
13690
|
+
finalModelSelection.model = await this.getLatestDefaultModel(finalModelSelection.provider || DEFAULT_CONFIG.service);
|
|
13691
|
+
}
|
|
13692
|
+
// Ensure provider is also defined
|
|
13693
|
+
if (!finalModelSelection.provider) {
|
|
13694
|
+
finalModelSelection.provider = DEFAULT_CONFIG.service;
|
|
13695
|
+
}
|
|
13696
|
+
const requestModel = this.createModelForRequest({
|
|
13697
|
+
provider: finalModelSelection.provider,
|
|
13698
|
+
model: finalModelSelection.model,
|
|
13699
|
+
});
|
|
13562
13700
|
// Build system prompt with schema context
|
|
13563
13701
|
const systemPrompt = this.buildContextualSystemPrompt(schema, chatLevel, additionalContext);
|
|
13564
13702
|
// Build messages array
|
|
@@ -13919,12 +14057,37 @@ ${additionalContext}
|
|
|
13919
14057
|
const { command, schema, chatHistory = [], modelSelection, chatLevel = this.config.chatLevel || 'none', additionalContext, } = request;
|
|
13920
14058
|
try {
|
|
13921
14059
|
// Create model for this request
|
|
13922
|
-
|
|
13923
|
-
|
|
13924
|
-
|
|
13925
|
-
|
|
13926
|
-
|
|
13927
|
-
|
|
14060
|
+
let finalModelSelection = modelSelection;
|
|
14061
|
+
if (!finalModelSelection) {
|
|
14062
|
+
// Use tier-based default (fast/cheapest tier)
|
|
14063
|
+
const defaultProvider = DEFAULT_CONFIG.service;
|
|
14064
|
+
const defaultModel = await this.getDefaultModelByTier(defaultProvider, 'fast');
|
|
14065
|
+
finalModelSelection = {
|
|
14066
|
+
provider: defaultProvider,
|
|
14067
|
+
model: defaultModel || DEFAULT_CONFIG.model,
|
|
14068
|
+
};
|
|
14069
|
+
this.log(`📋 Using default model for ${defaultProvider}: ${finalModelSelection.model}`);
|
|
14070
|
+
}
|
|
14071
|
+
else if (finalModelSelection.provider && !finalModelSelection.model) {
|
|
14072
|
+
// Provider specified but no model - auto-select from tier
|
|
14073
|
+
const tier = finalModelSelection.tier || 'fast';
|
|
14074
|
+
const defaultModel = await this.getDefaultModelByTier(finalModelSelection.provider, tier);
|
|
14075
|
+
finalModelSelection = {
|
|
14076
|
+
provider: finalModelSelection.provider,
|
|
14077
|
+
model: defaultModel || DEFAULT_CONFIG.model,
|
|
14078
|
+
};
|
|
14079
|
+
if (defaultModel) {
|
|
14080
|
+
this.log(`📋 Auto-selected ${tier} tier model for ${finalModelSelection.provider}: ${defaultModel}`);
|
|
14081
|
+
}
|
|
14082
|
+
}
|
|
14083
|
+
// Ensure model is always defined before creating request model
|
|
14084
|
+
if (!finalModelSelection.model) {
|
|
14085
|
+
finalModelSelection.model = DEFAULT_CONFIG.model;
|
|
14086
|
+
}
|
|
14087
|
+
const requestModel = this.createModelForRequest({
|
|
14088
|
+
provider: finalModelSelection.provider,
|
|
14089
|
+
model: finalModelSelection.model,
|
|
14090
|
+
});
|
|
13928
14091
|
// Build system prompt
|
|
13929
14092
|
const systemPrompt = this.buildContextualSystemPrompt(schema, chatLevel, additionalContext);
|
|
13930
14093
|
// Build messages
|
|
@@ -13995,9 +14158,55 @@ ${additionalContext}
|
|
|
13995
14158
|
}
|
|
13996
14159
|
}
|
|
13997
14160
|
/**
|
|
13998
|
-
*
|
|
14161
|
+
* Static utility to read cached models from file (for use in other services)
|
|
14162
|
+
*/
|
|
14163
|
+
static getCachedModelsSync() {
|
|
14164
|
+
try {
|
|
14165
|
+
// Use the same cache location as instance method
|
|
14166
|
+
const cacheDir = path$a.join(process.cwd(), '.cache', 'orchid-ai');
|
|
14167
|
+
const cacheFilePath = path$a.join(cacheDir, 'models-cache.json');
|
|
14168
|
+
if (!fs$8.existsSync(cacheFilePath)) {
|
|
14169
|
+
return [];
|
|
14170
|
+
}
|
|
14171
|
+
const cacheContent = fs$8.readFileSync(cacheFilePath, 'utf8');
|
|
14172
|
+
const cache = JSON.parse(cacheContent);
|
|
14173
|
+
// Check if cache is still valid (24 hours)
|
|
14174
|
+
const age = Date.now() - cache.timestamp;
|
|
14175
|
+
const CACHE_TTL_MS = 24 * 60 * 60 * 1000;
|
|
14176
|
+
if (age < CACHE_TTL_MS && cache.models && cache.models.length > 0) {
|
|
14177
|
+
return cache.models;
|
|
14178
|
+
}
|
|
14179
|
+
return [];
|
|
14180
|
+
}
|
|
14181
|
+
catch (error) {
|
|
14182
|
+
// Silently fail - return empty array
|
|
14183
|
+
return [];
|
|
14184
|
+
}
|
|
14185
|
+
}
|
|
14186
|
+
/**
|
|
14187
|
+
* Static utility to get the fastest model for a provider from cache
|
|
14188
|
+
*/
|
|
14189
|
+
static getFastestModelSync(provider) {
|
|
14190
|
+
const cachedModels = this.getCachedModelsSync();
|
|
14191
|
+
const providerModels = cachedModels
|
|
14192
|
+
.filter(m => m.provider.toLowerCase() === provider.toLowerCase())
|
|
14193
|
+
.sort((a, b) => (a.computeWeight ?? 0.5) - (b.computeWeight ?? 0.5));
|
|
14194
|
+
return providerModels.length > 0 ? providerModels[0].id : null;
|
|
14195
|
+
}
|
|
14196
|
+
/**
|
|
14197
|
+
* Get available models from API or use cached/defaults
|
|
14198
|
+
* Uses file-based cache that refreshes every 24 hours
|
|
13999
14199
|
*/
|
|
14000
14200
|
async getAvailableModels() {
|
|
14201
|
+
// Check if we have a valid cache
|
|
14202
|
+
if (this.modelsCache) {
|
|
14203
|
+
const age = Date.now() - this.modelsCache.timestamp;
|
|
14204
|
+
if (age < this.CACHE_TTL_MS) {
|
|
14205
|
+
this.log(`📦 Using cached models (${this.modelsCache.models.length} models, ${Math.round(age / 1000 / 60)} minutes old)`);
|
|
14206
|
+
return this.modelsCache.models;
|
|
14207
|
+
}
|
|
14208
|
+
this.log(`⏰ Cache expired (${Math.round(age / 1000 / 60 / 60)} hours old), fetching fresh models...`);
|
|
14209
|
+
}
|
|
14001
14210
|
try {
|
|
14002
14211
|
const allModels = [];
|
|
14003
14212
|
if (this.config.providers) {
|
|
@@ -14011,16 +14220,40 @@ ${additionalContext}
|
|
|
14011
14220
|
case 'claude':
|
|
14012
14221
|
try {
|
|
14013
14222
|
const claudeModels = await tempModel.models.list();
|
|
14014
|
-
providerModels = claudeModels.data
|
|
14015
|
-
|
|
14016
|
-
|
|
14017
|
-
|
|
14018
|
-
|
|
14019
|
-
|
|
14223
|
+
providerModels = claudeModels.data
|
|
14224
|
+
.filter((model) => model.id.includes('claude'))
|
|
14225
|
+
.map((model) => {
|
|
14226
|
+
// Determine compute weight based on model name (lower = cheaper)
|
|
14227
|
+
// Check in priority order: haiku (cheapest), sonnet (medium), opus (most expensive)
|
|
14228
|
+
let computeWeight = 0.5; // default balanced for unknown models
|
|
14229
|
+
const modelIdLower = model.id.toLowerCase();
|
|
14230
|
+
if (modelIdLower.includes('haiku')) {
|
|
14231
|
+
computeWeight = 0.2; // Cheapest - Haiku models (e.g., claude-3-5-haiku-20241022)
|
|
14232
|
+
}
|
|
14233
|
+
else if (modelIdLower.includes('sonnet')) {
|
|
14234
|
+
computeWeight = 0.6; // Medium cost - Sonnet models (e.g., claude-sonnet-4-20250514)
|
|
14235
|
+
}
|
|
14236
|
+
else if (modelIdLower.includes('opus')) {
|
|
14237
|
+
computeWeight = 1.2; // Most expensive - Opus models (e.g., claude-opus-4-20250514)
|
|
14238
|
+
}
|
|
14239
|
+
// Note: Models not matching above patterns default to 0.5 (balanced)
|
|
14240
|
+
// Auto-detect image support for this model
|
|
14241
|
+
const supportsImages = getModelSupportsImages(model.id, providerName);
|
|
14242
|
+
return {
|
|
14243
|
+
id: model.id,
|
|
14244
|
+
name: model.display_name || model.id,
|
|
14245
|
+
provider: providerName,
|
|
14246
|
+
available: true,
|
|
14247
|
+
computeWeight,
|
|
14248
|
+
supportsImages,
|
|
14249
|
+
};
|
|
14250
|
+
});
|
|
14020
14251
|
}
|
|
14021
14252
|
catch {
|
|
14253
|
+
// Fallback defaults with image support
|
|
14022
14254
|
providerModels = [
|
|
14023
|
-
{ id: 'claude-3-5-haiku-20241022', name: 'Claude 3.5 Haiku', provider: providerName, available: true },
|
|
14255
|
+
{ id: 'claude-3-5-haiku-20241022', name: 'Claude 3.5 Haiku', provider: providerName, available: true, computeWeight: 0.2, supportsImages: true },
|
|
14256
|
+
{ id: 'claude-3-5-sonnet-20241022', name: 'Claude 3.5 Sonnet', provider: providerName, available: true, computeWeight: 0.6, supportsImages: true },
|
|
14024
14257
|
];
|
|
14025
14258
|
}
|
|
14026
14259
|
break;
|
|
@@ -14028,26 +14261,62 @@ ${additionalContext}
|
|
|
14028
14261
|
try {
|
|
14029
14262
|
const openaiModels = await tempModel.models.list();
|
|
14030
14263
|
providerModels = openaiModels.data
|
|
14031
|
-
.filter((model) => model.id.includes('gpt'))
|
|
14032
|
-
.map((model) =>
|
|
14264
|
+
.filter((model) => model.id.includes('gpt') && !model.id.includes('instruct'))
|
|
14265
|
+
.map((model) => {
|
|
14266
|
+
// Determine compute weight
|
|
14267
|
+
let computeWeight = 0.5;
|
|
14268
|
+
if (model.id.includes('gpt-4-turbo') || model.id.includes('gpt-4o')) {
|
|
14269
|
+
computeWeight = model.id.includes('mini') ? 0.3 : 1.0;
|
|
14270
|
+
}
|
|
14271
|
+
else if (model.id.includes('gpt-3.5')) {
|
|
14272
|
+
computeWeight = 0.2;
|
|
14273
|
+
}
|
|
14274
|
+
// Auto-detect image support for this model
|
|
14275
|
+
const supportsImages = getModelSupportsImages(model.id, providerName);
|
|
14276
|
+
return {
|
|
14277
|
+
id: model.id,
|
|
14278
|
+
name: model.id,
|
|
14279
|
+
provider: providerName,
|
|
14280
|
+
available: true,
|
|
14281
|
+
computeWeight,
|
|
14282
|
+
supportsImages,
|
|
14283
|
+
};
|
|
14284
|
+
});
|
|
14285
|
+
}
|
|
14286
|
+
catch {
|
|
14287
|
+
// Fallback defaults with image support
|
|
14288
|
+
providerModels = [
|
|
14289
|
+
{ id: 'gpt-4o-mini', name: 'GPT-4o Mini', provider: providerName, available: true, computeWeight: 0.3, supportsImages: true },
|
|
14290
|
+
{ id: 'gpt-4o', name: 'GPT-4o', provider: providerName, available: true, computeWeight: 1.0, supportsImages: true },
|
|
14291
|
+
];
|
|
14292
|
+
}
|
|
14293
|
+
break;
|
|
14294
|
+
case 'gemini':
|
|
14295
|
+
try {
|
|
14296
|
+
// Gemini models are statically defined as API doesn't provide list endpoint
|
|
14297
|
+
// Auto-detect image support for each model
|
|
14298
|
+
const geminiModelList = [
|
|
14299
|
+
{ id: 'gemini-2.0-flash-exp', name: 'Gemini 2.0 Flash Exp', computeWeight: 0.2 },
|
|
14300
|
+
{ id: 'gemini-1.5-flash', name: 'Gemini 1.5 Flash', computeWeight: 0.2 },
|
|
14301
|
+
{ id: 'gemini-2.0-flash-thinking-exp-1219', name: 'Gemini 2.0 Flash Thinking', computeWeight: 0.5 },
|
|
14302
|
+
{ id: 'gemini-1.5-pro', name: 'Gemini 1.5 Pro', computeWeight: 0.8 },
|
|
14303
|
+
{ id: 'gemini-2.5-pro', name: 'Gemini 2.5 Pro', computeWeight: 1.0 },
|
|
14304
|
+
];
|
|
14305
|
+
providerModels = geminiModelList.map(model => ({
|
|
14033
14306
|
id: model.id,
|
|
14034
|
-
name: model.
|
|
14307
|
+
name: model.name,
|
|
14035
14308
|
provider: providerName,
|
|
14036
14309
|
available: true,
|
|
14310
|
+
computeWeight: model.computeWeight,
|
|
14311
|
+
supportsImages: getModelSupportsImages(model.id, providerName),
|
|
14037
14312
|
}));
|
|
14038
14313
|
}
|
|
14039
14314
|
catch {
|
|
14040
14315
|
providerModels = [
|
|
14041
|
-
{ id: '
|
|
14042
|
-
{ id: 'gpt-4o-mini', name: 'GPT-4O Mini', provider: providerName, available: true },
|
|
14316
|
+
{ id: 'gemini-1.5-flash', name: 'Gemini 1.5 Flash', provider: providerName, available: true, computeWeight: 0.2, supportsImages: true },
|
|
14043
14317
|
];
|
|
14044
14318
|
}
|
|
14045
14319
|
break;
|
|
14046
|
-
case 'gemini':
|
|
14047
|
-
providerModels = [
|
|
14048
|
-
{ id: 'gemini-1.5-flash', name: 'Gemini 1.5 Flash', provider: providerName, available: true },
|
|
14049
|
-
];
|
|
14050
|
-
break;
|
|
14051
14320
|
}
|
|
14052
14321
|
allModels.push(...providerModels);
|
|
14053
14322
|
}
|
|
@@ -14056,13 +14325,120 @@ ${additionalContext}
|
|
|
14056
14325
|
}
|
|
14057
14326
|
}
|
|
14058
14327
|
}
|
|
14328
|
+
// Save to cache for future use
|
|
14329
|
+
if (allModels.length > 0) {
|
|
14330
|
+
this.saveModelsCache(allModels);
|
|
14331
|
+
}
|
|
14059
14332
|
return allModels;
|
|
14060
14333
|
}
|
|
14061
14334
|
catch (error) {
|
|
14062
14335
|
this.handleError(error);
|
|
14336
|
+
// If we have a stale cache, use it as fallback
|
|
14337
|
+
if (this.modelsCache) {
|
|
14338
|
+
this.log('⚠️ Failed to fetch models, using stale cache as fallback');
|
|
14339
|
+
return this.modelsCache.models;
|
|
14340
|
+
}
|
|
14063
14341
|
return [];
|
|
14064
14342
|
}
|
|
14065
14343
|
}
|
|
14344
|
+
/**
|
|
14345
|
+
* Get the latest default model for a provider (balanced tier, or fallback to hardcoded)
|
|
14346
|
+
* This should be used instead of DEFAULT_CONFIG.model when possible
|
|
14347
|
+
*/
|
|
14348
|
+
async getLatestDefaultModel(provider = DEFAULT_CONFIG.service) {
|
|
14349
|
+
try {
|
|
14350
|
+
const balancedModel = await this.getDefaultModelByTier(provider, 'balanced');
|
|
14351
|
+
if (balancedModel) {
|
|
14352
|
+
return balancedModel;
|
|
14353
|
+
}
|
|
14354
|
+
}
|
|
14355
|
+
catch (error) {
|
|
14356
|
+
this.log(`⚠️ Could not get latest default model for ${provider}, using fallback`);
|
|
14357
|
+
}
|
|
14358
|
+
// Fallback to hardcoded defaults if dynamic lookup fails (using latest 4-5 models)
|
|
14359
|
+
const fallbackDefaults = {
|
|
14360
|
+
claude: 'claude-sonnet-4-5-20250929',
|
|
14361
|
+
openai: 'gpt-4o',
|
|
14362
|
+
gemini: 'gemini-2.0-flash-thinking-exp-1219',
|
|
14363
|
+
};
|
|
14364
|
+
return fallbackDefaults[provider.toLowerCase()] || DEFAULT_CONFIG.model;
|
|
14365
|
+
}
|
|
14366
|
+
/**
|
|
14367
|
+
* Get default models by tier for a provider
|
|
14368
|
+
* @param provider - Provider name
|
|
14369
|
+
* @param tier - 'fast' (lowest computeWeight = cheapest), 'balanced' (medium), or 'powerful' (highest = most expensive)
|
|
14370
|
+
*/
|
|
14371
|
+
async getDefaultModelByTier(provider, tier = 'fast') {
|
|
14372
|
+
const availableModels = await this.getAvailableModels();
|
|
14373
|
+
const providerModels = availableModels.filter((m) => m.provider.toLowerCase() === provider.toLowerCase());
|
|
14374
|
+
if (providerModels.length === 0) {
|
|
14375
|
+
this.log(`⚠️ [getDefaultModelByTier] No models found for provider ${provider}, using fallback`);
|
|
14376
|
+
// Fallback to hardcoded defaults (using latest 4-5 models)
|
|
14377
|
+
const defaults = {
|
|
14378
|
+
claude: {
|
|
14379
|
+
fast: 'claude-haiku-4-5-20251001',
|
|
14380
|
+
balanced: 'claude-sonnet-4-5-20250929',
|
|
14381
|
+
powerful: 'claude-opus-4-20250514',
|
|
14382
|
+
},
|
|
14383
|
+
openai: {
|
|
14384
|
+
fast: 'gpt-4o-mini',
|
|
14385
|
+
balanced: 'gpt-4o',
|
|
14386
|
+
powerful: 'gpt-4-turbo',
|
|
14387
|
+
},
|
|
14388
|
+
gemini: {
|
|
14389
|
+
fast: 'gemini-1.5-flash',
|
|
14390
|
+
balanced: 'gemini-2.0-flash-thinking-exp-1219',
|
|
14391
|
+
powerful: 'gemini-2.5-pro',
|
|
14392
|
+
},
|
|
14393
|
+
};
|
|
14394
|
+
const fallback = defaults[provider.toLowerCase()]?.[tier];
|
|
14395
|
+
if (fallback) {
|
|
14396
|
+
this.log(`⚠️ Using fallback model for ${provider} ${tier}: ${fallback}`);
|
|
14397
|
+
return fallback;
|
|
14398
|
+
}
|
|
14399
|
+
return null;
|
|
14400
|
+
}
|
|
14401
|
+
// Sort by computeWeight (ascending - lowest weight = cheapest)
|
|
14402
|
+
const sorted = providerModels.sort((a, b) => {
|
|
14403
|
+
const weightA = a.computeWeight ?? 0.5;
|
|
14404
|
+
const weightB = b.computeWeight ?? 0.5;
|
|
14405
|
+
return weightA - weightB;
|
|
14406
|
+
});
|
|
14407
|
+
// Select based on tier
|
|
14408
|
+
switch (tier) {
|
|
14409
|
+
case 'fast':
|
|
14410
|
+
// Cheapest model (lowest weight) - should be Haiku for Claude
|
|
14411
|
+
const cheapest = sorted[0];
|
|
14412
|
+
return cheapest.id;
|
|
14413
|
+
case 'powerful':
|
|
14414
|
+
// Most expensive/powerful model (highest weight) - should be Opus for Claude
|
|
14415
|
+
const mostExpensive = sorted[sorted.length - 1];
|
|
14416
|
+
return mostExpensive.id;
|
|
14417
|
+
case 'balanced':
|
|
14418
|
+
default:
|
|
14419
|
+
// Get middle model (rounded down)
|
|
14420
|
+
const midIndex = Math.floor(sorted.length / 2);
|
|
14421
|
+
const balanced = sorted[midIndex];
|
|
14422
|
+
return balanced.id;
|
|
14423
|
+
}
|
|
14424
|
+
}
|
|
14425
|
+
/**
|
|
14426
|
+
* Get latest models from each tier for all configured providers
|
|
14427
|
+
*/
|
|
14428
|
+
async getLatestModelsByTier() {
|
|
14429
|
+
const result = {};
|
|
14430
|
+
if (!this.config.providers)
|
|
14431
|
+
return result;
|
|
14432
|
+
for (const providerName of Object.keys(this.config.providers)) {
|
|
14433
|
+
const fast = await this.getDefaultModelByTier(providerName, 'fast');
|
|
14434
|
+
const balanced = await this.getDefaultModelByTier(providerName, 'balanced');
|
|
14435
|
+
const powerful = await this.getDefaultModelByTier(providerName, 'powerful');
|
|
14436
|
+
if (fast && balanced && powerful) {
|
|
14437
|
+
result[providerName] = { fast, balanced, powerful };
|
|
14438
|
+
}
|
|
14439
|
+
}
|
|
14440
|
+
return result;
|
|
14441
|
+
}
|
|
14066
14442
|
/**
|
|
14067
14443
|
* Get usage statistics
|
|
14068
14444
|
*/
|
|
@@ -14360,6 +14736,7 @@ class IntentDetectionPlugin {
|
|
|
14360
14736
|
}
|
|
14361
14737
|
/**
|
|
14362
14738
|
* Resolve model name with dynamic discovery support
|
|
14739
|
+
* Uses cached models when available, falls back to defaults
|
|
14363
14740
|
*/
|
|
14364
14741
|
resolveModelName() {
|
|
14365
14742
|
const { provider, model, enableDynamicModelDiscovery } = this.config;
|
|
@@ -14367,66 +14744,45 @@ class IntentDetectionPlugin {
|
|
|
14367
14744
|
if (model && model !== 'auto') {
|
|
14368
14745
|
return model;
|
|
14369
14746
|
}
|
|
14370
|
-
//
|
|
14747
|
+
// Try to get from cache first
|
|
14748
|
+
if (enableDynamicModelDiscovery) {
|
|
14749
|
+
const cachedFastest = ContextualCommandService.getFastestModelSync(provider);
|
|
14750
|
+
if (cachedFastest) {
|
|
14751
|
+
this.log(`✅ [MODEL RESOLUTION] Using cached fastest model for ${provider}: ${cachedFastest}`);
|
|
14752
|
+
return cachedFastest;
|
|
14753
|
+
}
|
|
14754
|
+
}
|
|
14755
|
+
// Fallback to defaults if cache unavailable (using latest 4-5 models)
|
|
14371
14756
|
const defaultModels = {
|
|
14372
14757
|
openai: 'gpt-4o-mini',
|
|
14373
|
-
claude: 'claude-
|
|
14374
|
-
gemini: 'gemini-flash
|
|
14758
|
+
claude: 'claude-haiku-4-5-20251001',
|
|
14759
|
+
gemini: 'gemini-1.5-flash',
|
|
14375
14760
|
};
|
|
14376
|
-
|
|
14377
|
-
|
|
14378
|
-
|
|
14379
|
-
}
|
|
14380
|
-
// For 'auto' or dynamic discovery, we'll resolve at runtime
|
|
14381
|
-
return defaultModels[provider.toLowerCase()] || 'gpt-3.5-turbo';
|
|
14761
|
+
const defaultModel = defaultModels[provider.toLowerCase()] || 'gpt-3.5-turbo';
|
|
14762
|
+
this.log(`⚠️ [MODEL RESOLUTION] Using fallback default for ${provider}: ${defaultModel}`);
|
|
14763
|
+
return defaultModel;
|
|
14382
14764
|
}
|
|
14383
14765
|
/**
|
|
14384
14766
|
* Dynamically discover and select the best model for the provider
|
|
14767
|
+
* Uses cached models when available
|
|
14385
14768
|
*/
|
|
14386
14769
|
async discoverBestModel() {
|
|
14387
|
-
const { provider
|
|
14388
|
-
try
|
|
14389
|
-
|
|
14390
|
-
|
|
14391
|
-
|
|
14392
|
-
|
|
14393
|
-
|
|
14394
|
-
|
|
14395
|
-
.filter((m) => m.name.includes('gemini'))
|
|
14396
|
-
.map((m) => m.name.replace('models/', ''));
|
|
14397
|
-
// Priority order: latest flash > any flash > latest pro > any pro
|
|
14398
|
-
const latestFlash = geminiModels.find((m) => m === 'gemini-flash-latest');
|
|
14399
|
-
const anyFlash = geminiModels.find((m) => m.includes('flash') && !m.includes('pro'));
|
|
14400
|
-
const latestPro = geminiModels.find((m) => m === 'gemini-pro-latest');
|
|
14401
|
-
const anyPro = geminiModels.find((m) => m.includes('pro'));
|
|
14402
|
-
const selectedModel = latestFlash || anyFlash || latestPro || anyPro || 'gemini-1.5-flash';
|
|
14403
|
-
this.log(`🔍 [DYNAMIC DISCOVERY] Found ${geminiModels.length} Gemini models, selected: ${selectedModel}`);
|
|
14404
|
-
return selectedModel;
|
|
14405
|
-
}
|
|
14406
|
-
break;
|
|
14407
|
-
}
|
|
14408
|
-
case 'openai': {
|
|
14409
|
-
// OpenAI models are more stable, use known fast models
|
|
14410
|
-
const fastModels = ['gpt-4o-mini', 'gpt-3.5-turbo', 'gpt-4o'];
|
|
14411
|
-
return fastModels[0]; // gpt-4o-mini is fastest
|
|
14412
|
-
}
|
|
14413
|
-
case 'claude': {
|
|
14414
|
-
// Claude models are stable, use known fast models
|
|
14415
|
-
const fastModels = ['claude-3-haiku-20240307', 'claude-3-5-haiku-20241022'];
|
|
14416
|
-
return fastModels[0]; // haiku is fastest
|
|
14417
|
-
}
|
|
14418
|
-
}
|
|
14419
|
-
}
|
|
14420
|
-
catch (error) {
|
|
14421
|
-
this.log('⚠️ Dynamic model discovery failed, using default:', error);
|
|
14422
|
-
}
|
|
14423
|
-
// Fallback to defaults
|
|
14770
|
+
const { provider } = this.config;
|
|
14771
|
+
// First, try to get from cache (fastest model for the provider)
|
|
14772
|
+
const cachedFastest = ContextualCommandService.getFastestModelSync(provider);
|
|
14773
|
+
if (cachedFastest) {
|
|
14774
|
+
this.log(`✅ [DYNAMIC DISCOVERY] Using cached fastest model for ${provider}: ${cachedFastest}`);
|
|
14775
|
+
return cachedFastest;
|
|
14776
|
+
}
|
|
14777
|
+
// Fallback to defaults if cache unavailable (using latest 4-5 models)
|
|
14424
14778
|
const defaults = {
|
|
14425
14779
|
openai: 'gpt-4o-mini',
|
|
14426
|
-
claude: 'claude-
|
|
14427
|
-
gemini: 'gemini-flash
|
|
14780
|
+
claude: 'claude-haiku-4-5-20251001',
|
|
14781
|
+
gemini: 'gemini-1.5-flash',
|
|
14428
14782
|
};
|
|
14429
|
-
|
|
14783
|
+
const defaultModel = defaults[provider.toLowerCase()] || 'gpt-3.5-turbo';
|
|
14784
|
+
this.log(`⚠️ [DYNAMIC DISCOVERY] Cache unavailable, using fallback: ${defaultModel}`);
|
|
14785
|
+
return defaultModel;
|
|
14430
14786
|
}
|
|
14431
14787
|
createModelInstance() {
|
|
14432
14788
|
const { provider, apiKey } = this.config;
|
|
@@ -14838,7 +15194,7 @@ class TypeScriptAnalyzer {
|
|
|
14838
15194
|
* Extract type definitions from a TypeScript file
|
|
14839
15195
|
*/
|
|
14840
15196
|
extractTypes(filePath) {
|
|
14841
|
-
const content =
|
|
15197
|
+
const content = fs__default.readFileSync(filePath, 'utf8');
|
|
14842
15198
|
const types = [];
|
|
14843
15199
|
// Extract interfaces
|
|
14844
15200
|
const interfaceMatches = content.matchAll(/(?:\/\*\*[\s\S]*?\*\/\s*)?export\s+interface\s+(\w+)(?:\s+extends\s+([\w,\s]+))?\s*\{([\s\S]*?)\n\}/g);
|
|
@@ -15084,7 +15440,7 @@ class MonasteryAnalyzer {
|
|
|
15084
15440
|
*/
|
|
15085
15441
|
extractModel(filePath) {
|
|
15086
15442
|
try {
|
|
15087
|
-
const content =
|
|
15443
|
+
const content = fs__default.readFileSync(filePath, 'utf8');
|
|
15088
15444
|
// Extract model name from filename
|
|
15089
15445
|
const fileName = filePath.split('/').pop()?.replace(/\.(js|ts)$/, '') || 'unknown';
|
|
15090
15446
|
const modelName = fileName.charAt(0).toUpperCase() + fileName.slice(1);
|
|
@@ -15604,13 +15960,13 @@ class SchemaGenerator extends CommandTrainingCollector {
|
|
|
15604
15960
|
}
|
|
15605
15961
|
}
|
|
15606
15962
|
// Look in pages directory (common pattern)
|
|
15607
|
-
const pagesDir =
|
|
15608
|
-
if (
|
|
15963
|
+
const pagesDir = path__default.join(this.getRootDir(), 'pages');
|
|
15964
|
+
if (fs__default.existsSync(pagesDir)) {
|
|
15609
15965
|
try {
|
|
15610
|
-
const pageFiles =
|
|
15966
|
+
const pageFiles = fs__default.readdirSync(pagesDir, { recursive: true });
|
|
15611
15967
|
for (const file of pageFiles) {
|
|
15612
15968
|
if (typeof file === 'string' && file.endsWith('.tsx')) {
|
|
15613
|
-
tsxFiles.push(
|
|
15969
|
+
tsxFiles.push(path__default.join('pages', file));
|
|
15614
15970
|
}
|
|
15615
15971
|
}
|
|
15616
15972
|
}
|
|
@@ -15776,12 +16132,12 @@ Provide a single sentence that describes what users can do in this tab.`;
|
|
|
15776
16132
|
async saveConfig(config, outputPath) {
|
|
15777
16133
|
this.log(`\n💾 Saving config to: ${outputPath}`);
|
|
15778
16134
|
// Ensure output directory exists
|
|
15779
|
-
const dir =
|
|
15780
|
-
if (!
|
|
15781
|
-
|
|
16135
|
+
const dir = path__default.dirname(outputPath);
|
|
16136
|
+
if (!fs__default.existsSync(dir)) {
|
|
16137
|
+
fs__default.mkdirSync(dir, { recursive: true });
|
|
15782
16138
|
}
|
|
15783
16139
|
// Write config file
|
|
15784
|
-
|
|
16140
|
+
fs__default.writeFileSync(outputPath, JSON.stringify(config, null, 2), 'utf8');
|
|
15785
16141
|
this.log(` ✅ Config saved successfully!`);
|
|
15786
16142
|
}
|
|
15787
16143
|
/**
|
|
@@ -15791,11 +16147,11 @@ Provide a single sentence that describes what users can do in this tab.`;
|
|
|
15791
16147
|
this.log('\n📝 Generating schemas/index.ts...');
|
|
15792
16148
|
// 1. Scan for Monastery models (server/models/*.js)
|
|
15793
16149
|
const monasteryModels = [];
|
|
15794
|
-
const modelsDir =
|
|
15795
|
-
if (
|
|
15796
|
-
const modelFiles =
|
|
16150
|
+
const modelsDir = path__default.join(this.getRootDir(), 'server/models');
|
|
16151
|
+
if (fs__default.existsSync(modelsDir)) {
|
|
16152
|
+
const modelFiles = fs__default.readdirSync(modelsDir).filter(f => f.endsWith('.js') || f.endsWith('.ts'));
|
|
15797
16153
|
for (const file of modelFiles) {
|
|
15798
|
-
const filePath =
|
|
16154
|
+
const filePath = path__default.join(modelsDir, file);
|
|
15799
16155
|
const extracted = this.monasteryAnalyzer.extractModel(filePath);
|
|
15800
16156
|
if (extracted) {
|
|
15801
16157
|
monasteryModels.push(extracted);
|
|
@@ -15809,7 +16165,7 @@ Provide a single sentence that describes what users can do in this tab.`;
|
|
|
15809
16165
|
try {
|
|
15810
16166
|
const types = this.tsAnalyzer.extractTypes(typeFile.filePath);
|
|
15811
16167
|
extractedTypes.push(...types);
|
|
15812
|
-
this.log(` ✅ Extracted ${types.length} types from ${
|
|
16168
|
+
this.log(` ✅ Extracted ${types.length} types from ${path__default.basename(typeFile.filePath)}`);
|
|
15813
16169
|
}
|
|
15814
16170
|
catch (error) {
|
|
15815
16171
|
this.log(` ⚠️ Failed to extract types from ${typeFile.filePath}: ${error.message}`);
|
|
@@ -16039,7 +16395,7 @@ module.exports = {
|
|
|
16039
16395
|
* Helper function to run schema generation
|
|
16040
16396
|
*/
|
|
16041
16397
|
async function generateSchemas(projectRoot, config, options = {}) {
|
|
16042
|
-
const { outputDir =
|
|
16398
|
+
const { outputDir = path__default.join(projectRoot, '.orchid-ai'), clientOutputFile = 'schemas.ts', serverOutputFile = 'command-config.json', schemasOutputPath = path__default.join(projectRoot, 'schemas.ts'), // Default: root level
|
|
16043
16399
|
separateSchemaFiles = false, verboseLogging = false, useAI = false, aiService = null, interactive = false, promptCallback, } = options;
|
|
16044
16400
|
console.log('🚀 Starting schema generation for project:', projectRoot);
|
|
16045
16401
|
// Create generator
|
|
@@ -16047,34 +16403,34 @@ async function generateSchemas(projectRoot, config, options = {}) {
|
|
|
16047
16403
|
// Generate config
|
|
16048
16404
|
const generatedConfig = await generator.generateConfig();
|
|
16049
16405
|
// Save server config (JSON)
|
|
16050
|
-
const serverConfigPath =
|
|
16406
|
+
const serverConfigPath = path__default.join(outputDir, serverOutputFile);
|
|
16051
16407
|
await generator.saveConfig(generatedConfig, serverConfigPath);
|
|
16052
16408
|
// Generate schemas file(s)
|
|
16053
16409
|
const schemasIndexContent = await generator.generateSchemasIndexFile(generatedConfig);
|
|
16054
16410
|
if (separateSchemaFiles) {
|
|
16055
16411
|
// Generate individual files per schema
|
|
16056
|
-
const schemasDir =
|
|
16057
|
-
if (!
|
|
16058
|
-
|
|
16412
|
+
const schemasDir = path__default.dirname(schemasOutputPath);
|
|
16413
|
+
if (!fs__default.existsSync(schemasDir)) {
|
|
16414
|
+
fs__default.mkdirSync(schemasDir, { recursive: true });
|
|
16059
16415
|
console.log(`📁 Created schemas directory: ${schemasDir}`);
|
|
16060
16416
|
}
|
|
16061
16417
|
// TODO: Implement individual file generation
|
|
16062
16418
|
console.log('⚠️ Separate schema files not yet implemented, using single file');
|
|
16063
|
-
|
|
16419
|
+
fs__default.writeFileSync(schemasOutputPath, schemasIndexContent, 'utf8');
|
|
16064
16420
|
}
|
|
16065
16421
|
else {
|
|
16066
16422
|
// Generate single schemas file
|
|
16067
|
-
const schemasDir =
|
|
16068
|
-
if (!
|
|
16069
|
-
|
|
16423
|
+
const schemasDir = path__default.dirname(schemasOutputPath);
|
|
16424
|
+
if (!fs__default.existsSync(schemasDir)) {
|
|
16425
|
+
fs__default.mkdirSync(schemasDir, { recursive: true });
|
|
16070
16426
|
}
|
|
16071
|
-
|
|
16427
|
+
fs__default.writeFileSync(schemasOutputPath, schemasIndexContent, 'utf8');
|
|
16072
16428
|
console.log(`📄 Generated schemas file: ${schemasOutputPath}`);
|
|
16073
16429
|
}
|
|
16074
16430
|
// Save client config (TypeScript) - legacy format
|
|
16075
|
-
const clientConfigPath =
|
|
16431
|
+
const clientConfigPath = path__default.join(outputDir, clientOutputFile);
|
|
16076
16432
|
const clientConfig = generator.generateClientConfig(generatedConfig);
|
|
16077
|
-
|
|
16433
|
+
fs__default.writeFileSync(clientConfigPath, clientConfig, 'utf8');
|
|
16078
16434
|
console.log('\n✨ Schema generation complete!');
|
|
16079
16435
|
console.log(`📁 Output directory: ${outputDir}`);
|
|
16080
16436
|
console.log(`📄 Schemas file: schemas/index.ts`);
|