@aws/ml-container-creator 0.2.0 ā 0.2.2
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/bin/cli.js +88 -86
- package/config/bootstrap-stack.json +211 -0
- package/config/parameter-schema.json +88 -0
- package/infra/ci-harness/bin/ci-harness.ts +26 -0
- package/infra/ci-harness/buildspec.yml +352 -0
- package/infra/ci-harness/cdk.json +27 -0
- package/infra/ci-harness/lambda/scanner/index.ts +199 -0
- package/infra/ci-harness/lib/ci-harness-stack.ts +609 -0
- package/infra/ci-harness/package-lock.json +3979 -0
- package/infra/ci-harness/package.json +32 -0
- package/infra/ci-harness/tsconfig.json +38 -0
- package/package.json +19 -10
- package/src/app.js +318 -318
- package/src/copy-tpl.js +19 -19
- package/src/lib/asset-manager.js +74 -74
- package/src/lib/aws-profile-parser.js +45 -45
- package/src/lib/bootstrap-command-handler.js +560 -547
- package/src/lib/bootstrap-config.js +45 -45
- package/src/lib/ci-register-helpers.js +19 -19
- package/src/lib/ci-report-helpers.js +37 -37
- package/src/lib/ci-stage-helpers.js +49 -49
- package/src/lib/comment-generator.js +4 -4
- package/src/lib/config-manager.js +105 -105
- package/src/lib/deployment-config-resolver.js +10 -10
- package/src/lib/deployment-registry.js +153 -153
- package/src/lib/engine-prefix-resolver.js +8 -8
- package/src/lib/key-value-parser.js +6 -6
- package/src/lib/manifest-cli.js +108 -108
- package/src/lib/prompt-runner.js +224 -224
- package/src/lib/prompts.js +121 -121
- package/src/lib/registry-command-handler.js +174 -174
- package/src/lib/registry-loader.js +52 -52
- package/src/lib/sensitive-redactor.js +9 -9
- package/src/lib/template-engine.js +1 -1
- package/src/lib/template-manager.js +62 -62
- package/src/prompt-adapter.js +18 -18
package/src/lib/prompt-runner.js
CHANGED
|
@@ -60,9 +60,9 @@ export default class PromptRunner {
|
|
|
60
60
|
const buildTimestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
|
|
61
61
|
|
|
62
62
|
// Load catalog data via Registry_Loader
|
|
63
|
-
const registryLoader = new RegistryLoader()
|
|
64
|
-
this._tritonBackends = await registryLoader.loadTritonBackends()
|
|
65
|
-
this._instanceAcceleratorMapping = await registryLoader.loadInstanceAcceleratorMapping()
|
|
63
|
+
const registryLoader = new RegistryLoader();
|
|
64
|
+
this._tritonBackends = await registryLoader.loadTritonBackends();
|
|
65
|
+
this._instanceAcceleratorMapping = await registryLoader.loadInstanceAcceleratorMapping();
|
|
66
66
|
|
|
67
67
|
// Get existing configuration to use as defaults
|
|
68
68
|
const existingConfig = this.baseConfig || {};
|
|
@@ -77,8 +77,8 @@ export default class PromptRunner {
|
|
|
77
77
|
|
|
78
78
|
// 1a. Query region MCP, then prompt for region + deployment target
|
|
79
79
|
await this._queryMcpForRegion({}, explicitConfig);
|
|
80
|
-
const bootstrapRegion = existingConfig.awsRegion || explicitConfig.awsRegion
|
|
81
|
-
const regionPreviousAnswers = bootstrapRegion ? { _bootstrapRegion: bootstrapRegion } : {}
|
|
80
|
+
const bootstrapRegion = existingConfig.awsRegion || explicitConfig.awsRegion;
|
|
81
|
+
const regionPreviousAnswers = bootstrapRegion ? { _bootstrapRegion: bootstrapRegion } : {};
|
|
82
82
|
const regionAndTargetAnswers = await this._runPhase(infraRegionAndTargetPrompts, regionPreviousAnswers, explicitConfig, existingConfig);
|
|
83
83
|
|
|
84
84
|
// 1b. Instance type ā query MCP and prompt for managed-inference, async-inference, batch-transform, and hyperpod-eks
|
|
@@ -171,18 +171,18 @@ export default class PromptRunner {
|
|
|
171
171
|
|
|
172
172
|
// Query base-image-picker MCP server for base image choices
|
|
173
173
|
// Requirements: 5.1, 5.2, 5.3
|
|
174
|
-
await this._queryMcpForBaseImage(frameworkAnswers, explicitConfig)
|
|
174
|
+
await this._queryMcpForBaseImage(frameworkAnswers, explicitConfig);
|
|
175
175
|
const baseImagePreviousAnswers = {
|
|
176
176
|
...frameworkAnswers,
|
|
177
177
|
...engineAnswers,
|
|
178
178
|
...(this._mcpBaseImageChoices ? { _mcpBaseImageChoices: this._mcpBaseImageChoices } : {})
|
|
179
|
-
}
|
|
179
|
+
};
|
|
180
180
|
const baseImageAnswers = await this._runPhase(
|
|
181
181
|
baseImagePrompts,
|
|
182
182
|
baseImagePreviousAnswers,
|
|
183
183
|
explicitConfig,
|
|
184
184
|
existingConfig
|
|
185
|
-
)
|
|
185
|
+
);
|
|
186
186
|
|
|
187
187
|
// Populate framework version choices from registry
|
|
188
188
|
const frameworkVersionChoices = this._getFrameworkVersionChoices(frameworkAnswers.framework);
|
|
@@ -211,10 +211,10 @@ export default class PromptRunner {
|
|
|
211
211
|
);
|
|
212
212
|
|
|
213
213
|
// Query model-picker MCP server for model choices
|
|
214
|
-
this._queryMcpForModels(frameworkAnswers.architecture)
|
|
214
|
+
this._queryMcpForModels(frameworkAnswers.architecture);
|
|
215
215
|
if (this._mcpModelChoices) {
|
|
216
|
-
console.log(
|
|
217
|
-
console.log(` ā ${this._mcpModelChoices.length} model(s) available from catalog`)
|
|
216
|
+
console.log(' š Querying model-picker...');
|
|
217
|
+
console.log(` ā ${this._mcpModelChoices.length} model(s) available from catalog`);
|
|
218
218
|
}
|
|
219
219
|
const modelFormatPreviousAnswers = {
|
|
220
220
|
...frameworkAnswers,
|
|
@@ -222,7 +222,7 @@ export default class PromptRunner {
|
|
|
222
222
|
...frameworkVersionAnswers,
|
|
223
223
|
...frameworkProfileAnswers,
|
|
224
224
|
...(this._mcpModelChoices ? { _mcpModelChoices: this._mcpModelChoices } : {})
|
|
225
|
-
}
|
|
225
|
+
};
|
|
226
226
|
const modelFormatAnswers = await this._runPhase(
|
|
227
227
|
modelFormatPrompts,
|
|
228
228
|
modelFormatPreviousAnswers,
|
|
@@ -392,7 +392,7 @@ export default class PromptRunner {
|
|
|
392
392
|
// Registry models ā note about InferenceSpecification requirement
|
|
393
393
|
if (combinedAnswers.modelSource === 'registry') {
|
|
394
394
|
if (!combinedAnswers.artifactUri) {
|
|
395
|
-
console.log(
|
|
395
|
+
console.log('\n ā ļø Model source is \'registry\' but no artifact URI was resolved.');
|
|
396
396
|
console.log(' The model package must have an InferenceSpecification with a valid');
|
|
397
397
|
console.log(' ModelDataUrl or S3DataSource for the runtime resolver to work.');
|
|
398
398
|
console.log(' If your model package was registered without an InferenceSpecification,');
|
|
@@ -421,7 +421,7 @@ export default class PromptRunner {
|
|
|
421
421
|
// Apply auto-set model format for Triton backends with single format
|
|
422
422
|
// Requirements: 3.3, 3.4, 3.5
|
|
423
423
|
if (tritonAutoFormat) {
|
|
424
|
-
combinedAnswers.modelFormat = tritonAutoFormat
|
|
424
|
+
combinedAnswers.modelFormat = tritonAutoFormat;
|
|
425
425
|
}
|
|
426
426
|
|
|
427
427
|
// Handle custom model name for transformers, diffusors, and Triton LLM backends
|
|
@@ -464,14 +464,14 @@ export default class PromptRunner {
|
|
|
464
464
|
|
|
465
465
|
// Handle custom base image
|
|
466
466
|
if (combinedAnswers.customBaseImage) {
|
|
467
|
-
combinedAnswers.baseImage = combinedAnswers.customBaseImage
|
|
468
|
-
combinedAnswers._baseImageSource = 'custom'
|
|
469
|
-
delete combinedAnswers.customBaseImage
|
|
467
|
+
combinedAnswers.baseImage = combinedAnswers.customBaseImage;
|
|
468
|
+
combinedAnswers._baseImageSource = 'custom';
|
|
469
|
+
delete combinedAnswers.customBaseImage;
|
|
470
470
|
}
|
|
471
471
|
|
|
472
472
|
// Handle --base-image CLI override
|
|
473
473
|
if (this.options['base-image']) {
|
|
474
|
-
combinedAnswers.baseImage = this.options['base-image']
|
|
474
|
+
combinedAnswers.baseImage = this.options['base-image'];
|
|
475
475
|
}
|
|
476
476
|
|
|
477
477
|
// Map awsRoleArn to roleArn for templates
|
|
@@ -576,17 +576,17 @@ export default class PromptRunner {
|
|
|
576
576
|
* @private
|
|
577
577
|
*/
|
|
578
578
|
_getTritonAutoModelFormat(architecture, backend) {
|
|
579
|
-
if (architecture !== 'triton') return null
|
|
579
|
+
if (architecture !== 'triton') return null;
|
|
580
580
|
|
|
581
|
-
const meta = this._tritonBackends[backend]
|
|
582
|
-
if (!meta || !meta.modelFormats) return null
|
|
581
|
+
const meta = this._tritonBackends[backend];
|
|
582
|
+
if (!meta || !meta.modelFormats) return null;
|
|
583
583
|
|
|
584
584
|
// Only auto-set if there's exactly one format
|
|
585
585
|
if (meta.modelFormats.length === 1) {
|
|
586
|
-
return meta.modelFormats[0]
|
|
586
|
+
return meta.modelFormats[0];
|
|
587
587
|
}
|
|
588
588
|
|
|
589
|
-
return null
|
|
589
|
+
return null;
|
|
590
590
|
}
|
|
591
591
|
|
|
592
592
|
/**
|
|
@@ -725,52 +725,52 @@ export default class PromptRunner {
|
|
|
725
725
|
* Requirements: 5.1, 5.2, 5.3, 5.4, 9.1, 9.2, 9.3
|
|
726
726
|
* @private
|
|
727
727
|
*/
|
|
728
|
-
async _queryMcpForBaseImage(frameworkAnswers,
|
|
728
|
+
async _queryMcpForBaseImage(frameworkAnswers, _explicitConfig) {
|
|
729
729
|
// Skip if base image provided via CLI --base-image flag
|
|
730
|
-
if (this.options['base-image']) return
|
|
730
|
+
if (this.options['base-image']) return;
|
|
731
731
|
|
|
732
|
-
const cm = this.configManager
|
|
733
|
-
if (!cm) return
|
|
732
|
+
const cm = this.configManager;
|
|
733
|
+
if (!cm) return;
|
|
734
734
|
|
|
735
|
-
const mcpServers = cm.getMcpServerNames()
|
|
736
|
-
if (!mcpServers.includes('base-image-picker')) return
|
|
735
|
+
const mcpServers = cm.getMcpServerNames();
|
|
736
|
+
if (!mcpServers.includes('base-image-picker')) return;
|
|
737
737
|
|
|
738
|
-
const smart = this.options.smart === true
|
|
739
|
-
const discover = this.options.discover === true
|
|
740
|
-
const framework = frameworkAnswers.framework
|
|
741
|
-
const modelServer = frameworkAnswers.modelServer
|
|
742
|
-
const architecture = frameworkAnswers.architecture || frameworkAnswers.deploymentConfig?.split('-')[0]
|
|
743
|
-
const isTransformer = framework === 'transformers'
|
|
744
|
-
const isTriton = architecture === 'triton'
|
|
745
|
-
const isDiffusors = architecture === 'diffusors'
|
|
738
|
+
const smart = this.options.smart === true;
|
|
739
|
+
const discover = this.options.discover === true;
|
|
740
|
+
const framework = frameworkAnswers.framework;
|
|
741
|
+
const modelServer = frameworkAnswers.modelServer;
|
|
742
|
+
const architecture = frameworkAnswers.architecture || frameworkAnswers.deploymentConfig?.split('-')[0];
|
|
743
|
+
const isTransformer = framework === 'transformers';
|
|
744
|
+
const isTriton = architecture === 'triton';
|
|
745
|
+
const isDiffusors = architecture === 'diffusors';
|
|
746
746
|
|
|
747
747
|
// For non-transformer, non-triton, non-diffusors frameworks, prompt for optional search criteria
|
|
748
|
-
let searchCriteria
|
|
748
|
+
let searchCriteria;
|
|
749
749
|
if (!isTransformer && !isTriton && !isDiffusors) {
|
|
750
750
|
const searchAnswer = await this._runPrompts(baseImageSearchPrompts.map(p => ({
|
|
751
751
|
...p,
|
|
752
752
|
when: () => true // Always show for non-transformer since we already checked
|
|
753
|
-
})))
|
|
754
|
-
searchCriteria = searchAnswer.baseImageSearch
|
|
753
|
+
})));
|
|
754
|
+
searchCriteria = searchAnswer.baseImageSearch;
|
|
755
755
|
}
|
|
756
756
|
|
|
757
|
-
const modeLabel = [smart && '[smart]', discover && '[discover]'].filter(Boolean).join(' ')
|
|
758
|
-
console.log(` š Querying base-image-picker${modeLabel ? ` ${modeLabel}` : ''}...`)
|
|
757
|
+
const modeLabel = [smart && '[smart]', discover && '[discover]'].filter(Boolean).join(' ');
|
|
758
|
+
console.log(` š Querying base-image-picker${modeLabel ? ` ${modeLabel}` : ''}...`);
|
|
759
759
|
|
|
760
|
-
const context = { framework, modelServer, architecture }
|
|
760
|
+
const context = { framework, modelServer, architecture };
|
|
761
761
|
if (searchCriteria && searchCriteria.trim()) {
|
|
762
|
-
context.searchCriteria = searchCriteria.trim()
|
|
762
|
+
context.searchCriteria = searchCriteria.trim();
|
|
763
763
|
}
|
|
764
764
|
|
|
765
|
-
const result = await cm.queryMcpServer('base-image-picker', context)
|
|
765
|
+
const result = await cm.queryMcpServer('base-image-picker', context);
|
|
766
766
|
|
|
767
767
|
if (result && result.metadata?.baseImage?.length > 0) {
|
|
768
|
-
const entries = result.metadata.baseImage
|
|
769
|
-
this._mcpBaseImageChoices = formatImageChoices(entries, isTransformer || isTriton || isDiffusors)
|
|
770
|
-
const count = entries.length
|
|
771
|
-
console.log(` ā ${count} base image(s) available`)
|
|
768
|
+
const entries = result.metadata.baseImage;
|
|
769
|
+
this._mcpBaseImageChoices = formatImageChoices(entries, isTransformer || isTriton || isDiffusors);
|
|
770
|
+
const count = entries.length;
|
|
771
|
+
console.log(` ā ${count} base image(s) available`);
|
|
772
772
|
} else {
|
|
773
|
-
console.log(' ā³ No MCP results, using default image')
|
|
773
|
+
console.log(' ā³ No MCP results, using default image');
|
|
774
774
|
}
|
|
775
775
|
}
|
|
776
776
|
|
|
@@ -782,47 +782,47 @@ export default class PromptRunner {
|
|
|
782
782
|
* @private
|
|
783
783
|
*/
|
|
784
784
|
_queryMcpForModels(architecture) {
|
|
785
|
-
const cm = this.configManager
|
|
786
|
-
if (!cm) return
|
|
785
|
+
const cm = this.configManager;
|
|
786
|
+
if (!cm) return;
|
|
787
787
|
|
|
788
|
-
const mcpServers = cm.getMcpServerNames()
|
|
789
|
-
if (!mcpServers.includes('model-picker')) return
|
|
788
|
+
const mcpServers = cm.getMcpServerNames();
|
|
789
|
+
if (!mcpServers.includes('model-picker')) return;
|
|
790
790
|
|
|
791
791
|
try {
|
|
792
|
-
const mcpConfigPath = path.join(GENERATOR_ROOT, 'config', 'mcp.json')
|
|
793
|
-
if (!fs.existsSync(mcpConfigPath)) return
|
|
792
|
+
const mcpConfigPath = path.join(GENERATOR_ROOT, 'config', 'mcp.json');
|
|
793
|
+
if (!fs.existsSync(mcpConfigPath)) return;
|
|
794
794
|
|
|
795
|
-
const mcpConfig = JSON.parse(fs.readFileSync(mcpConfigPath, 'utf8'))
|
|
796
|
-
const serverConfig = mcpConfig.mcpServers?.['model-picker']
|
|
797
|
-
if (!serverConfig?.args?.length) return
|
|
795
|
+
const mcpConfig = JSON.parse(fs.readFileSync(mcpConfigPath, 'utf8'));
|
|
796
|
+
const serverConfig = mcpConfig.mcpServers?.['model-picker'];
|
|
797
|
+
if (!serverConfig?.args?.length) return;
|
|
798
798
|
|
|
799
799
|
// Resolve the server entry point directory from the args
|
|
800
|
-
const serverEntryPoint = serverConfig.args[serverConfig.args.length - 1]
|
|
801
|
-
const serverDir = path.dirname(serverEntryPoint)
|
|
800
|
+
const serverEntryPoint = serverConfig.args[serverConfig.args.length - 1];
|
|
801
|
+
const serverDir = path.dirname(serverEntryPoint);
|
|
802
802
|
|
|
803
803
|
// Read manifest to find catalog path
|
|
804
|
-
const manifestPath = path.join(serverDir, 'manifest.json')
|
|
805
|
-
if (!fs.existsSync(manifestPath)) return
|
|
804
|
+
const manifestPath = path.join(serverDir, 'manifest.json');
|
|
805
|
+
if (!fs.existsSync(manifestPath)) return;
|
|
806
806
|
|
|
807
|
-
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'))
|
|
807
|
+
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
|
808
808
|
|
|
809
809
|
// Select catalog based on architecture
|
|
810
810
|
const catalogKey = architecture === 'diffusors'
|
|
811
811
|
? 'popular-diffusors'
|
|
812
|
-
: 'popular-transformers'
|
|
813
|
-
const catalogRelPath = manifest.catalogs?.[catalogKey]
|
|
814
|
-
if (!catalogRelPath) return
|
|
812
|
+
: 'popular-transformers';
|
|
813
|
+
const catalogRelPath = manifest.catalogs?.[catalogKey];
|
|
814
|
+
if (!catalogRelPath) return;
|
|
815
815
|
|
|
816
|
-
const catalogPath = path.resolve(serverDir, catalogRelPath)
|
|
817
|
-
if (!fs.existsSync(catalogPath)) return
|
|
816
|
+
const catalogPath = path.resolve(serverDir, catalogRelPath);
|
|
817
|
+
if (!fs.existsSync(catalogPath)) return;
|
|
818
818
|
|
|
819
|
-
const catalog = JSON.parse(fs.readFileSync(catalogPath, 'utf8'))
|
|
819
|
+
const catalog = JSON.parse(fs.readFileSync(catalogPath, 'utf8'));
|
|
820
820
|
|
|
821
821
|
// Extract model IDs, filtering out glob patterns (entries with *)
|
|
822
|
-
const modelIds = Object.keys(catalog).filter(id => !id.includes('*'))
|
|
822
|
+
const modelIds = Object.keys(catalog).filter(id => !id.includes('*'));
|
|
823
823
|
|
|
824
824
|
if (modelIds.length > 0) {
|
|
825
|
-
this._mcpModelChoices = modelIds
|
|
825
|
+
this._mcpModelChoices = modelIds;
|
|
826
826
|
}
|
|
827
827
|
} catch {
|
|
828
828
|
// Silently fall back to hardcoded defaults
|
|
@@ -999,186 +999,186 @@ export default class PromptRunner {
|
|
|
999
999
|
* @private
|
|
1000
1000
|
*/
|
|
1001
1001
|
async _fetchAndDisplayModelInfo(modelId) {
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
}
|
|
1083
|
-
if (sources.length === 0) {
|
|
1084
|
-
sources.push('model-picker');
|
|
1085
|
-
}
|
|
1086
|
-
console.log(` ā Resolved: ${modelId}`);
|
|
1087
|
-
} else if (parsed.message) {
|
|
1088
|
-
console.log(` ā³ ${parsed.message}`);
|
|
1002
|
+
console.log('\n š Querying model-picker [discover]...');
|
|
1003
|
+
|
|
1004
|
+
const sources = [];
|
|
1005
|
+
let chatTemplate = null;
|
|
1006
|
+
let modelFamily = null;
|
|
1007
|
+
let mcpUsed = false;
|
|
1008
|
+
|
|
1009
|
+
// Try model-picker MCP server in discover mode (queries HuggingFace + merges with catalog)
|
|
1010
|
+
const cm = this.configManager;
|
|
1011
|
+
if (cm) {
|
|
1012
|
+
const mcpServers = cm.getMcpServerNames();
|
|
1013
|
+
if (mcpServers.includes('model-picker')) {
|
|
1014
|
+
try {
|
|
1015
|
+
const mcpConfigPath = path.join(GENERATOR_ROOT, 'config', 'mcp.json');
|
|
1016
|
+
if (fs.existsSync(mcpConfigPath)) {
|
|
1017
|
+
const mcpConfig = JSON.parse(fs.readFileSync(mcpConfigPath, 'utf8'));
|
|
1018
|
+
const serverConfig = mcpConfig.mcpServers?.['model-picker'];
|
|
1019
|
+
if (serverConfig) {
|
|
1020
|
+
const { McpClient } = await import('./mcp-client.js');
|
|
1021
|
+
const client = new McpClient(serverConfig, { timeout: 15000 });
|
|
1022
|
+
|
|
1023
|
+
// Override _buildContext to pass model_id and mode directly
|
|
1024
|
+
client._getUnboundedParameterNames = () => [];
|
|
1025
|
+
client._buildContext = () => ({});
|
|
1026
|
+
|
|
1027
|
+
// Connect and call get_models directly
|
|
1028
|
+
const { Client } = await import('@modelcontextprotocol/sdk/client/index.js');
|
|
1029
|
+
const { StdioClientTransport } = await import('@modelcontextprotocol/sdk/client/stdio.js');
|
|
1030
|
+
|
|
1031
|
+
const transport = new StdioClientTransport({
|
|
1032
|
+
command: serverConfig.command,
|
|
1033
|
+
args: serverConfig.args || [],
|
|
1034
|
+
env: { ...process.env, ...(serverConfig.env || {}) },
|
|
1035
|
+
stderr: 'pipe'
|
|
1036
|
+
});
|
|
1037
|
+
|
|
1038
|
+
const mcpClient = new Client(
|
|
1039
|
+
{ name: 'ml-container-creator', version: '1.0.0' },
|
|
1040
|
+
{ capabilities: {} }
|
|
1041
|
+
);
|
|
1042
|
+
|
|
1043
|
+
await mcpClient.connect(transport);
|
|
1044
|
+
|
|
1045
|
+
const result = await mcpClient.callTool({
|
|
1046
|
+
name: 'get_models',
|
|
1047
|
+
arguments: { model_id: modelId, mode: 'discover' }
|
|
1048
|
+
});
|
|
1049
|
+
|
|
1050
|
+
await mcpClient.close();
|
|
1051
|
+
|
|
1052
|
+
// Parse the response
|
|
1053
|
+
const textBlock = result?.content?.find(b => b.type === 'text');
|
|
1054
|
+
if (textBlock) {
|
|
1055
|
+
const parsed = JSON.parse(textBlock.text);
|
|
1056
|
+
if (parsed.values && Object.keys(parsed.values).length > 0) {
|
|
1057
|
+
mcpUsed = true;
|
|
1058
|
+
const vals = parsed.values;
|
|
1059
|
+
|
|
1060
|
+
if (vals.chat_template) {
|
|
1061
|
+
chatTemplate = vals.chat_template;
|
|
1062
|
+
}
|
|
1063
|
+
if (vals.family) {
|
|
1064
|
+
modelFamily = vals.family;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
// Extract model source metadata for loading adapter
|
|
1068
|
+
// Requirements: 2.1, 2.2, 2.3, 2.4
|
|
1069
|
+
if (vals.provider) {
|
|
1070
|
+
this._mcpModelSource = vals.provider;
|
|
1071
|
+
}
|
|
1072
|
+
if (vals.artifactUri) {
|
|
1073
|
+
this._mcpArtifactUri = vals.artifactUri;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
// Determine sources based on what was returned
|
|
1077
|
+
if (vals.tags || vals.pipeline_tag) {
|
|
1078
|
+
sources.push('HuggingFace_Hub_API');
|
|
1079
|
+
}
|
|
1080
|
+
if (vals.validation_level || vals.framework_compatibility) {
|
|
1081
|
+
sources.push('Model_Picker_Catalog');
|
|
1089
1082
|
}
|
|
1083
|
+
if (sources.length === 0) {
|
|
1084
|
+
sources.push('model-picker');
|
|
1085
|
+
}
|
|
1086
|
+
console.log(` ā Resolved: ${modelId}`);
|
|
1087
|
+
} else if (parsed.message) {
|
|
1088
|
+
console.log(` ā³ ${parsed.message}`);
|
|
1090
1089
|
}
|
|
1091
1090
|
}
|
|
1092
1091
|
}
|
|
1093
|
-
} catch (err) {
|
|
1094
|
-
console.log(' ā³ model-picker unavailable, using fallback');
|
|
1095
1092
|
}
|
|
1093
|
+
} catch (err) {
|
|
1094
|
+
console.log(' ā³ model-picker unavailable, using fallback');
|
|
1096
1095
|
}
|
|
1097
1096
|
}
|
|
1097
|
+
}
|
|
1098
1098
|
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1099
|
+
// Fallback to legacy path if MCP didn't resolve
|
|
1100
|
+
if (!mcpUsed) {
|
|
1101
|
+
const registryConfigManager = this.registryConfigManager;
|
|
1102
|
+
if (registryConfigManager) {
|
|
1103
|
+
// Only try HuggingFace API for bare model IDs (not prefixed URIs)
|
|
1104
|
+
const isNonHfUri = modelId.startsWith('jumpstart://') ||
|
|
1105
1105
|
modelId.startsWith('jumpstart-hub://') ||
|
|
1106
1106
|
modelId.startsWith('s3://') ||
|
|
1107
1107
|
modelId.startsWith('registry://');
|
|
1108
1108
|
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
}
|
|
1118
|
-
console.log(' ā
Found on HuggingFace Hub');
|
|
1119
|
-
} else {
|
|
1120
|
-
console.log(' ā¹ļø Not found on HuggingFace Hub (may be private or offline)');
|
|
1109
|
+
if (!isNonHfUri) {
|
|
1110
|
+
// Try HuggingFace API directly
|
|
1111
|
+
try {
|
|
1112
|
+
const hfData = await registryConfigManager._fetchHuggingFaceData(modelId);
|
|
1113
|
+
if (hfData) {
|
|
1114
|
+
sources.push('HuggingFace_Hub_API');
|
|
1115
|
+
if (hfData.chatTemplate) {
|
|
1116
|
+
chatTemplate = hfData.chatTemplate;
|
|
1121
1117
|
}
|
|
1122
|
-
|
|
1123
|
-
|
|
1118
|
+
console.log(' ā
Found on HuggingFace Hub');
|
|
1119
|
+
} else {
|
|
1120
|
+
console.log(' ā¹ļø Not found on HuggingFace Hub (may be private or offline)');
|
|
1124
1121
|
}
|
|
1125
|
-
}
|
|
1126
|
-
|
|
1127
|
-
// The summary at the end of this function will report "No additional model information"
|
|
1122
|
+
} catch (error) {
|
|
1123
|
+
console.log(' ā ļø HuggingFace API unavailable');
|
|
1128
1124
|
}
|
|
1125
|
+
} else {
|
|
1126
|
+
// Non-HF URI (jumpstart://, s3://, etc.) ā skip HF lookup silently
|
|
1127
|
+
// The summary at the end of this function will report "No additional model information"
|
|
1128
|
+
}
|
|
1129
1129
|
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
}
|
|
1130
|
+
// Check Model Registry for overrides
|
|
1131
|
+
if (registryConfigManager.modelRegistry) {
|
|
1132
|
+
let modelConfig = registryConfigManager.modelRegistry[modelId];
|
|
1133
|
+
|
|
1134
|
+
if (!modelConfig) {
|
|
1135
|
+
for (const [pattern, config] of Object.entries(registryConfigManager.modelRegistry)) {
|
|
1136
|
+
if (pattern.includes('*')) {
|
|
1137
|
+
const regex = new RegExp(`^${ pattern.replace(/\*/g, '.*') }$`);
|
|
1138
|
+
if (regex.test(modelId)) {
|
|
1139
|
+
modelConfig = config;
|
|
1140
|
+
console.log(` ā
Matched pattern in Model_Registry: ${pattern}`);
|
|
1141
|
+
break;
|
|
1143
1142
|
}
|
|
1144
1143
|
}
|
|
1145
|
-
} else {
|
|
1146
|
-
console.log(' ā
Found in Model_Registry');
|
|
1147
1144
|
}
|
|
1145
|
+
} else {
|
|
1146
|
+
console.log(' ā
Found in Model_Registry');
|
|
1147
|
+
}
|
|
1148
1148
|
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
}
|
|
1149
|
+
if (modelConfig) {
|
|
1150
|
+
sources.push('Model_Registry');
|
|
1151
|
+
if (modelConfig.chatTemplate) {
|
|
1152
|
+
chatTemplate = modelConfig.chatTemplate;
|
|
1153
|
+
}
|
|
1154
|
+
if (modelConfig.family) {
|
|
1155
|
+
modelFamily = modelConfig.family;
|
|
1157
1156
|
}
|
|
1158
1157
|
}
|
|
1159
1158
|
}
|
|
1160
1159
|
}
|
|
1160
|
+
}
|
|
1161
1161
|
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
} else {
|
|
1173
|
-
console.log(' ⢠Chat Template: ā Not available');
|
|
1174
|
-
console.log(' (Chat endpoints may require manual configuration)');
|
|
1175
|
-
}
|
|
1176
|
-
console.log(` ⢠Sources: ${sources.join(', ')}`);
|
|
1162
|
+
// Display information
|
|
1163
|
+
if (sources.length > 0) {
|
|
1164
|
+
console.log('\nš Model Information:');
|
|
1165
|
+
console.log(` ⢠Model ID: ${modelId}`);
|
|
1166
|
+
if (modelFamily) {
|
|
1167
|
+
console.log(` ⢠Family: ${modelFamily}`);
|
|
1168
|
+
}
|
|
1169
|
+
if (chatTemplate) {
|
|
1170
|
+
console.log(' ⢠Chat Template: ā
Available');
|
|
1171
|
+
console.log(' (Will be injected into generated files)');
|
|
1177
1172
|
} else {
|
|
1178
|
-
console.log('
|
|
1179
|
-
console.log('
|
|
1173
|
+
console.log(' ⢠Chat Template: ā Not available');
|
|
1174
|
+
console.log(' (Chat endpoints may require manual configuration)');
|
|
1180
1175
|
}
|
|
1176
|
+
console.log(` ⢠Sources: ${sources.join(', ')}`);
|
|
1177
|
+
} else {
|
|
1178
|
+
console.log(' ā¹ļø No additional model information available');
|
|
1179
|
+
console.log(' Proceeding with default configuration');
|
|
1181
1180
|
}
|
|
1181
|
+
}
|
|
1182
1182
|
|
|
1183
1183
|
|
|
1184
1184
|
|