@equinor/fusion-framework-cli-plugin-ai-base 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +51 -0
- package/LICENSE +21 -0
- package/README.md +76 -0
- package/dist/esm/config.js +58 -0
- package/dist/esm/config.js.map +1 -0
- package/dist/esm/index.js +14 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/options/index.js +4 -0
- package/dist/esm/options/index.js.map +1 -0
- package/dist/esm/options/options.js +60 -0
- package/dist/esm/options/options.js.map +1 -0
- package/dist/esm/options/schema.js +62 -0
- package/dist/esm/options/schema.js.map +1 -0
- package/dist/esm/options/types.js +2 -0
- package/dist/esm/options/types.js.map +1 -0
- package/dist/esm/options/with-options.js +105 -0
- package/dist/esm/options/with-options.js.map +1 -0
- package/dist/esm/register.js +34 -0
- package/dist/esm/register.js.map +1 -0
- package/dist/esm/setup-framework.js +72 -0
- package/dist/esm/setup-framework.js.map +1 -0
- package/dist/esm/version.js +3 -0
- package/dist/esm/version.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types/config.d.ts +62 -0
- package/dist/types/index.d.ts +13 -0
- package/dist/types/options/index.d.ts +4 -0
- package/dist/types/options/options.d.ts +57 -0
- package/dist/types/options/schema.d.ts +52 -0
- package/dist/types/options/types.d.ts +32 -0
- package/dist/types/options/with-options.d.ts +37 -0
- package/dist/types/register.d.ts +25 -0
- package/dist/types/setup-framework.d.ts +33 -0
- package/dist/types/version.d.ts +1 -0
- package/package.json +64 -0
- package/src/config.ts +87 -0
- package/src/index.ts +19 -0
- package/src/options/index.ts +4 -0
- package/src/options/options.ts +92 -0
- package/src/options/schema.ts +71 -0
- package/src/options/types.ts +32 -0
- package/src/options/with-options.ts +161 -0
- package/src/register.ts +38 -0
- package/src/setup-framework.ts +107 -0
- package/src/version.ts +2 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration options for AI-related CLI commands.
|
|
3
|
+
*
|
|
4
|
+
* This interface defines all available options for configuring Azure OpenAI services
|
|
5
|
+
* and Azure Cognitive Search integration. Required fields must be provided either
|
|
6
|
+
* via command-line arguments or environment variables. Optional fields enable
|
|
7
|
+
* specific features (chat, embeddings, vector search) when provided.
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* - All required fields (apiKey, apiVersion, instance) must be provided for any AI operation
|
|
11
|
+
* - Chat operations require `openaiChatDeployment`
|
|
12
|
+
* - Embedding operations require `openaiEmbeddingDeployment`
|
|
13
|
+
* - Vector search requires all three Azure Search fields plus `openaiEmbeddingDeployment`
|
|
14
|
+
*/
|
|
15
|
+
export interface AiOptions {
|
|
16
|
+
/** Azure OpenAI API key for authentication with Azure OpenAI services */
|
|
17
|
+
openaiApiKey: string;
|
|
18
|
+
/** Azure OpenAI API version (e.g., '2024-02-15-preview') */
|
|
19
|
+
openaiApiVersion: string;
|
|
20
|
+
/** Azure OpenAI instance name (the resource name in Azure) */
|
|
21
|
+
openaiInstance: string;
|
|
22
|
+
/** Azure OpenAI chat model deployment name. Required for chat operations */
|
|
23
|
+
openaiChatDeployment?: string;
|
|
24
|
+
/** Azure OpenAI embedding model deployment name. Required for embedding and vector search operations */
|
|
25
|
+
openaiEmbeddingDeployment?: string;
|
|
26
|
+
/** Azure Cognitive Search endpoint URL. Required for vector search operations */
|
|
27
|
+
azureSearchEndpoint?: string;
|
|
28
|
+
/** Azure Cognitive Search API key. Required for vector search operations */
|
|
29
|
+
azureSearchApiKey?: string;
|
|
30
|
+
/** Azure Cognitive Search index name. Required for vector search operations */
|
|
31
|
+
azureSearchIndexName?: string;
|
|
32
|
+
}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { type Command, InvalidOptionArgumentError } from 'commander';
|
|
2
|
+
import {
|
|
3
|
+
apiInstanceOption,
|
|
4
|
+
apiKeyOption,
|
|
5
|
+
apiVersionOption,
|
|
6
|
+
azureSearchApiKeyOption,
|
|
7
|
+
azureSearchEndpointOption,
|
|
8
|
+
azureSearchIndexNameOption,
|
|
9
|
+
chatDeploymentOption,
|
|
10
|
+
embeddingDeploymentOption,
|
|
11
|
+
} from './options.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Enhances a Commander command with AI-related options and validation.
|
|
15
|
+
*
|
|
16
|
+
* This function adds Azure OpenAI and Azure Cognitive Search options to the provided
|
|
17
|
+
* command, along with pre-action validation hooks to ensure required options are provided.
|
|
18
|
+
* The function allows selective inclusion of chat, embedding, and search capabilities
|
|
19
|
+
* based on the command's requirements.
|
|
20
|
+
*
|
|
21
|
+
* Options added:
|
|
22
|
+
* - Core: `openaiApiKey`, `openaiApiVersion`, `openaiInstance` (always included)
|
|
23
|
+
* - Chat: `openaiChatDeployment` (if includeChat is true)
|
|
24
|
+
* - Embedding: `openaiEmbeddingDeployment` (if includeEmbedding is true)
|
|
25
|
+
* - Search: `azureSearchEndpoint`, `azureSearchApiKey`, `azureSearchIndexName` (if includeSearch is true)
|
|
26
|
+
*
|
|
27
|
+
* @param command - The Commander command instance to enhance with AI options
|
|
28
|
+
* @param args - Optional configuration object for selective feature inclusion
|
|
29
|
+
* @param args.includeEmbedding - Whether to include and require embedding deployment option (default: false)
|
|
30
|
+
* @param args.includeChat - Whether to include and require chat deployment option (default: false)
|
|
31
|
+
* @param args.includeSearch - Whether to include and require Azure Search options (default: false)
|
|
32
|
+
* @returns The enhanced command with AI options and validation hooks attached
|
|
33
|
+
* @throws {InvalidOptionArgumentError} During command execution if required options are missing or invalid
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* const chatCommand = createCommand('chat')
|
|
38
|
+
* .description('Start a chat session');
|
|
39
|
+
*
|
|
40
|
+
* withOptions(chatCommand, { includeChat: true });
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export const withOptions = (
|
|
44
|
+
command: Command,
|
|
45
|
+
args?: Partial<{
|
|
46
|
+
includeEmbedding: boolean;
|
|
47
|
+
includeChat: boolean;
|
|
48
|
+
includeSearch: boolean;
|
|
49
|
+
}>,
|
|
50
|
+
): Command => {
|
|
51
|
+
// Core authentication options
|
|
52
|
+
command.addOption(apiKeyOption);
|
|
53
|
+
command.addOption(apiVersionOption);
|
|
54
|
+
command.addOption(apiInstanceOption);
|
|
55
|
+
|
|
56
|
+
// Deployment options
|
|
57
|
+
if (args?.includeChat === true) {
|
|
58
|
+
command.addOption(chatDeploymentOption);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (args?.includeEmbedding === true) {
|
|
62
|
+
command.addOption(embeddingDeploymentOption);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Azure Search options
|
|
66
|
+
if (args?.includeSearch === true) {
|
|
67
|
+
command.addOption(azureSearchEndpointOption);
|
|
68
|
+
command.addOption(azureSearchApiKeyOption);
|
|
69
|
+
command.addOption(azureSearchIndexNameOption);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Validation hook
|
|
73
|
+
command.hook('preAction', (thisCommand) => {
|
|
74
|
+
const options = thisCommand.opts();
|
|
75
|
+
|
|
76
|
+
// Validate API key
|
|
77
|
+
if (
|
|
78
|
+
!options.openaiApiKey ||
|
|
79
|
+
typeof options.openaiApiKey !== 'string' ||
|
|
80
|
+
options.openaiApiKey.trim() === ''
|
|
81
|
+
) {
|
|
82
|
+
throw new InvalidOptionArgumentError('API key is required and must be a non-empty string.');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Validate API version
|
|
86
|
+
if (!options.openaiApiVersion || typeof options.openaiApiVersion !== 'string') {
|
|
87
|
+
throw new InvalidOptionArgumentError('API version must be a non-empty string.');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Validate instance name
|
|
91
|
+
if (
|
|
92
|
+
!options.openaiInstance ||
|
|
93
|
+
typeof options.openaiInstance !== 'string' ||
|
|
94
|
+
options.openaiInstance.trim() === ''
|
|
95
|
+
) {
|
|
96
|
+
throw new InvalidOptionArgumentError(
|
|
97
|
+
'API instance name is required and must be a non-empty string.',
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (args?.includeChat === true) {
|
|
102
|
+
if (
|
|
103
|
+
!options.openaiChatDeployment ||
|
|
104
|
+
typeof options.openaiChatDeployment !== 'string' ||
|
|
105
|
+
options.openaiChatDeployment.trim() === ''
|
|
106
|
+
) {
|
|
107
|
+
throw new InvalidOptionArgumentError(
|
|
108
|
+
'Chat deployment name is required and must be a non-empty string.',
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (args?.includeEmbedding === true) {
|
|
114
|
+
if (
|
|
115
|
+
!options.openaiEmbeddingDeployment ||
|
|
116
|
+
typeof options.openaiEmbeddingDeployment !== 'string' ||
|
|
117
|
+
options.openaiEmbeddingDeployment.trim() === ''
|
|
118
|
+
) {
|
|
119
|
+
throw new InvalidOptionArgumentError(
|
|
120
|
+
'Embedding deployment name is required and must be a non-empty string.',
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (args?.includeSearch === true) {
|
|
126
|
+
if (
|
|
127
|
+
!options.azureSearchEndpoint ||
|
|
128
|
+
typeof options.azureSearchEndpoint !== 'string' ||
|
|
129
|
+
options.azureSearchEndpoint.trim() === ''
|
|
130
|
+
) {
|
|
131
|
+
throw new InvalidOptionArgumentError(
|
|
132
|
+
'Azure Search endpoint is required and must be a non-empty string.',
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (
|
|
137
|
+
!options.azureSearchApiKey ||
|
|
138
|
+
typeof options.azureSearchApiKey !== 'string' ||
|
|
139
|
+
options.azureSearchApiKey.trim() === ''
|
|
140
|
+
) {
|
|
141
|
+
throw new InvalidOptionArgumentError(
|
|
142
|
+
'Azure Search API key is required and must be a non-empty string.',
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
if (
|
|
147
|
+
!options.azureSearchIndexName ||
|
|
148
|
+
typeof options.azureSearchIndexName !== 'string' ||
|
|
149
|
+
options.azureSearchIndexName.trim() === ''
|
|
150
|
+
) {
|
|
151
|
+
throw new InvalidOptionArgumentError(
|
|
152
|
+
'Azure Search index name is required and must be a non-empty string.',
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
return command;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
export default withOptions;
|
package/src/register.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Command } from 'commander';
|
|
2
|
+
import { createCommand } from 'commander';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Registers an AI plugin command with the CLI program.
|
|
6
|
+
*
|
|
7
|
+
* This function ensures the 'ai' command group exists in the CLI program and adds
|
|
8
|
+
* the provided command as a subcommand. If the 'ai' group doesn't exist, it creates
|
|
9
|
+
* it with a standard description. This allows multiple AI-related plugins to register
|
|
10
|
+
* their commands under a common namespace.
|
|
11
|
+
*
|
|
12
|
+
* @param program - The Commander program instance to register commands with
|
|
13
|
+
* @param command - The command to add to the 'ai' command group
|
|
14
|
+
* @returns void
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* const myAiCommand = createCommand('chat')
|
|
19
|
+
* .description('Start an AI chat session')
|
|
20
|
+
* .action(() => { ... });
|
|
21
|
+
*
|
|
22
|
+
* registerAiPlugin(program, myAiCommand);
|
|
23
|
+
* // Results in: fusion-cli ai chat
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function registerAiPlugin(program: Command, command: Command): void {
|
|
27
|
+
// Create 'ai' command group if it doesn't exist
|
|
28
|
+
let aiCommand = program.commands.find((cmd) => cmd.name() === 'ai');
|
|
29
|
+
if (!aiCommand) {
|
|
30
|
+
aiCommand = createCommand('ai').description(
|
|
31
|
+
'Commands for interacting with AI models and Azure OpenAI services',
|
|
32
|
+
);
|
|
33
|
+
program.addCommand(aiCommand);
|
|
34
|
+
}
|
|
35
|
+
aiCommand.addCommand(command);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default registerAiPlugin;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { enableAI, type IAIConfigurator, type AIModule } from '@equinor/fusion-framework-module-ai';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
AzureOpenAiEmbed,
|
|
5
|
+
AzureOpenAIModel,
|
|
6
|
+
AzureVectorStore,
|
|
7
|
+
} from '@equinor/fusion-framework-module-ai/azure';
|
|
8
|
+
|
|
9
|
+
import type { AiOptions } from './options/index.js';
|
|
10
|
+
import { ModulesConfigurator, type ModulesInstance } from '@equinor/fusion-framework-module';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Framework instance with AI module capabilities.
|
|
14
|
+
*
|
|
15
|
+
* This type represents an initialized Fusion Framework instance that includes
|
|
16
|
+
* the AI module, providing access to chat models, embedding services, and
|
|
17
|
+
* vector stores configured via the setup process.
|
|
18
|
+
*/
|
|
19
|
+
export type FrameworkInstance = ModulesInstance<[AIModule]>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Initializes and configures the Fusion Framework with AI module capabilities.
|
|
23
|
+
*
|
|
24
|
+
* Sets up the framework with Azure OpenAI chat models, embedding services, and
|
|
25
|
+
* optionally Azure Cognitive Search vector stores. The function handles the complete
|
|
26
|
+
* initialization process including service registration and dependency injection.
|
|
27
|
+
*
|
|
28
|
+
* @param options - AI configuration options
|
|
29
|
+
* @param options.openaiApiKey - Azure OpenAI API key for authentication
|
|
30
|
+
* @param options.openaiApiVersion - Azure OpenAI API version (e.g., '2024-02-15-preview')
|
|
31
|
+
* @param options.openaiInstance - Azure OpenAI instance name
|
|
32
|
+
* @param options.openaiChatDeployment - Optional chat model deployment name
|
|
33
|
+
* @param options.openaiEmbeddingDeployment - Optional embedding model deployment name
|
|
34
|
+
* @param options.azureSearchEndpoint - Optional Azure Search service endpoint URL
|
|
35
|
+
* @param options.azureSearchApiKey - Optional Azure Search API key
|
|
36
|
+
* @param options.azureSearchIndexName - Optional Azure Search index name
|
|
37
|
+
* @returns Promise resolving to an initialized framework instance with AI module configured
|
|
38
|
+
* @throws {Error} If embedding deployment is required but not provided when configuring vector store
|
|
39
|
+
* @throws {Error} If embedding service cannot be retrieved for vector store configuration
|
|
40
|
+
*/
|
|
41
|
+
export const setupFramework = async (options: AiOptions): Promise<FrameworkInstance> => {
|
|
42
|
+
// Create a new module configurator for the framework
|
|
43
|
+
const configurator = new ModulesConfigurator<[AIModule]>();
|
|
44
|
+
|
|
45
|
+
// Configure AI module with provided options
|
|
46
|
+
enableAI(configurator, (aiConfig: IAIConfigurator) => {
|
|
47
|
+
// Configure chat model if deployment name is provided
|
|
48
|
+
if (options.openaiChatDeployment) {
|
|
49
|
+
aiConfig.setModel(
|
|
50
|
+
options.openaiChatDeployment,
|
|
51
|
+
new AzureOpenAIModel({
|
|
52
|
+
azureOpenAIApiKey: options.openaiApiKey,
|
|
53
|
+
azureOpenAIApiDeploymentName: options.openaiChatDeployment,
|
|
54
|
+
azureOpenAIApiInstanceName: options.openaiInstance,
|
|
55
|
+
azureOpenAIApiVersion: options.openaiApiVersion,
|
|
56
|
+
}),
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Configure embedding model if deployment name is provided
|
|
61
|
+
if (options.openaiEmbeddingDeployment) {
|
|
62
|
+
aiConfig.setEmbedding(
|
|
63
|
+
options.openaiEmbeddingDeployment,
|
|
64
|
+
new AzureOpenAiEmbed({
|
|
65
|
+
azureOpenAIApiKey: options.openaiApiKey,
|
|
66
|
+
azureOpenAIApiDeploymentName: options.openaiEmbeddingDeployment,
|
|
67
|
+
azureOpenAIApiInstanceName: options.openaiInstance,
|
|
68
|
+
azureOpenAIApiVersion: options.openaiApiVersion,
|
|
69
|
+
}),
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Configure vector store if Azure Search options are provided
|
|
74
|
+
// Vector store requires an embedding service to generate embeddings for documents
|
|
75
|
+
if (options.azureSearchEndpoint && options.azureSearchApiKey && options.azureSearchIndexName) {
|
|
76
|
+
if (!options.openaiEmbeddingDeployment) {
|
|
77
|
+
throw new Error('Embedding deployment is required to configure the vector store');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Retrieve the embedding service to pass to the vector store
|
|
81
|
+
// The vector store uses embeddings to index and search documents
|
|
82
|
+
const embeddingService = aiConfig.getService('embeddings', options.openaiEmbeddingDeployment);
|
|
83
|
+
|
|
84
|
+
// Check that the embedding service was successfully retrieved
|
|
85
|
+
if (!embeddingService) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
`Embedding service '${options.openaiEmbeddingDeployment}' not found for vector store configuration`,
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
aiConfig.setVectorStore(
|
|
92
|
+
options.azureSearchIndexName,
|
|
93
|
+
new AzureVectorStore(embeddingService, {
|
|
94
|
+
endpoint: options.azureSearchEndpoint,
|
|
95
|
+
key: options.azureSearchApiKey,
|
|
96
|
+
indexName: options.azureSearchIndexName,
|
|
97
|
+
}),
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// Initialize the framework with all configured modules
|
|
103
|
+
const framework = await configurator.initialize();
|
|
104
|
+
return framework;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export default setupFramework;
|
package/src/version.ts
ADDED
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../../tsconfig.base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"outDir": "dist/esm",
|
|
7
|
+
"rootDir": "src",
|
|
8
|
+
"declarationDir": "./dist/types",
|
|
9
|
+
"baseUrl": "."
|
|
10
|
+
},
|
|
11
|
+
"references": [
|
|
12
|
+
{
|
|
13
|
+
"path": "../../modules/ai"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"path": "../../modules/module"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"include": ["src/**/*"],
|
|
20
|
+
"exclude": ["node_modules"]
|
|
21
|
+
}
|