Skip to content

Commit 887849c

Browse files
authored
Merge pull request #179 from forcedotcom/phale/llmservice-release
W-17969813: feat: add a4d llm service as an api
2 parents 480b846 + 013a72f commit 887849c

File tree

9 files changed

+116
-46
lines changed

9 files changed

+116
-46
lines changed

.husky/pre-commit

+1-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1 @@
1-
#!/usr/bin/env sh
2-
. "$(dirname -- "$0")/_/husky.sh"
3-
4-
yarn lint-staged
1+
yarn test

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@salesforce/vscode-service-provider",
3-
"version": "1.2.2",
3+
"version": "1.3.0-rc.6.6",
44
"description": "Library that provides access to Salesforce VSCode Service Provider",
55
"main": "lib/src/index.js",
66
"author": "Peter Hale <peter.hale@salesforce.com>",
@@ -52,7 +52,7 @@
5252
"package": "yarn pack",
5353
"prettier": "prettier ./**/*.{js,json,ts,md} --write",
5454
"format:check": "prettier ./**/*.{js,json,ts,md} --debug-check",
55-
"prepare": "husky install"
55+
"prepare": "husky"
5656
},
5757
"config": {
5858
"commitizen": {

src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,5 @@ export * from './types';
1010

1111
export const telemetryCommand = 'sf.vscode.core.get.telemetry';
1212
export const loggerCommand = 'sf.vscode.core.logger.get.instance';
13+
export const llmServiceCommand =
14+
'salesforcedx-einstein-gpt.getLLMServiceInstance';

src/services/serviceProvider.ts

+18-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
ServiceValidators
1313
} from '../types';
1414
import * as vscode from 'vscode';
15-
import { loggerCommand, telemetryCommand } from '../index';
15+
import { llmServiceCommand, loggerCommand, telemetryCommand } from '../index';
1616

1717
/**
1818
* The ServiceProvider class is a utility class that provides services of different types.
@@ -25,6 +25,19 @@ export class ServiceProvider {
2525
Map<string, ServiceReturnType<ServiceType>>
2626
> = new Map();
2727

28+
/**
29+
* Checks if the service is available to be created and returned from the {@link getService} method.
30+
* Specifically, this method checks if there even is a command associated with the specified
31+
* @{link ServiceType} registered within VS Code.
32+
* @param type - The type of the service.
33+
* @returns The value true if the service is available and false otherwise.
34+
*/
35+
static async isServiceAvailable<T extends ServiceType>(
36+
type: T
37+
): Promise<boolean> {
38+
return (await this.getCommands()).includes(this.getCommandString(type));
39+
}
40+
2841
/**
2942
* Retrieves a service instance of the specified type and instance name.
3043
* If the service instance does not exist, it will be created.
@@ -99,7 +112,7 @@ export class ServiceProvider {
99112
}
100113

101114
/**
102-
* Checks if a service of the specified type exists.
115+
* Checks if a service of the specified type exists yet within the cache of the ServiceProvider.
103116
* @param type - The type of the service.
104117
* @returns True if the service exists, false otherwise.
105118
*/
@@ -108,7 +121,7 @@ export class ServiceProvider {
108121
}
109122

110123
/**
111-
* Checks if a service instance of the specified type and instance name exists.
124+
* Checks if a service instance of the specified type and instance name exists yet within the cache of the ServiceProvider.
112125
* @param type - The type of the service.
113126
* @param instanceName - The name of the service instance.
114127
* @returns True if the service instance exists, false otherwise.
@@ -195,6 +208,8 @@ export class ServiceProvider {
195208
return loggerCommand;
196209
case ServiceType.Telemetry:
197210
return telemetryCommand;
211+
case ServiceType.LLMService:
212+
return llmServiceCommand;
198213
default:
199214
throw new Error(`Unsupported service type: ${type}`);
200215
}

src/types/index.ts

+28-8
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,28 @@
77

88
import { LoggerInterface } from './logger/loggerTypes';
99
import { TelemetryServiceInterface } from './telemetry/telemetryTypes';
10+
import { LLMServiceInterface } from './llmService';
1011

1112
export const SFDX_CORE_EXTENSION_NAME = 'salesforcedx-vscode-core';
1213

1314
export enum ServiceType {
1415
Logger = 'Logger',
15-
Telemetry = 'Telemetry'
16+
Telemetry = 'Telemetry',
17+
LLMService = 'LLMService'
1618
}
1719

1820
// Define a mapping from service types to their corresponding parameter types
1921
interface ServiceParamsMap {
2022
[ServiceType.Logger]: [string]; // Logger requires a string parameter
2123
[ServiceType.Telemetry]: [string | undefined];
24+
[ServiceType.LLMService]: [string];
25+
}
26+
27+
// Define a mapping from service types to their corresponding return types
28+
interface ServiceReturnTypeMap {
29+
[ServiceType.Telemetry]: TelemetryServiceInterface;
30+
[ServiceType.Logger]: LoggerInterface;
31+
[ServiceType.LLMService]: LLMServiceInterface;
2232
}
2333

2434
// Define a type that represents the parameter types for a given service type
@@ -27,11 +37,7 @@ export type ServiceParams<T extends ServiceType> =
2737

2838
// Define a type that represents the return type for a given service type
2939
export type ServiceReturnType<T extends ServiceType> =
30-
T extends ServiceType.Telemetry
31-
? TelemetryServiceInterface
32-
: T extends ServiceType.Logger
33-
? LoggerInterface
34-
: never;
40+
T extends keyof ServiceReturnTypeMap ? ServiceReturnTypeMap[T] : never;
3541

3642
// Define a ServiceValidator interface
3743
interface ServiceValidator<T extends ServiceType> {
@@ -55,8 +61,14 @@ export const ServiceValidators: {
5561
): ServiceParams<ServiceType.Telemetry> {
5662
return params;
5763
}
64+
},
65+
[ServiceType.LLMService]: {
66+
validateAndCorrect(
67+
params: ServiceParams<ServiceType.LLMService>
68+
): ServiceParams<ServiceType.LLMService> {
69+
return params;
70+
}
5871
}
59-
// Add more validators as needed
6072
};
6173

6274
// Define a ServiceInstanceValidator interface
@@ -78,8 +90,16 @@ export const ServiceInstanceValidators: {
7890
validateAndCorrect(instanceName: string): string {
7991
return instanceName || SFDX_CORE_EXTENSION_NAME;
8092
}
93+
},
94+
[ServiceType.LLMService]: {
95+
validateAndCorrect(extensionName: string): string {
96+
if (!extensionName) {
97+
throw new Error('Extension name is required for LLM service');
98+
}
99+
return extensionName;
100+
}
81101
}
82-
// Add more validators as needed
83102
};
84103
export * from './logger/loggerTypes';
85104
export * from './telemetry/telemetryTypes';
105+
export * from './llmService';

src/types/llmService/LLMService.ts

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright (c) 2025, salesforce.com, inc.
3+
* All rights reserved.
4+
* Licensed under the BSD 3-Clause license.
5+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6+
*/
7+
8+
/**
9+
* Interface representing a service for calling a Large Language Model (LLM).
10+
*/
11+
export interface LLMServiceInterface {
12+
/**
13+
* Calls the LLM with the provided engineered prompt, prompt ID, and input token limit.
14+
* @param engineeredPrompt - The prompt that has been engineered for the LLM.
15+
* @param promptId - The ID of the prompt (optional).
16+
* @param outputTokenLimit - The limit on the number of output tokens (optional).
17+
* @param options - The object of other options in the request (optional)
18+
* @returns A promise that resolves to the LLM's response as a string.
19+
*/
20+
callLLM(
21+
engineeredPrompt: string,
22+
promptId?: string,
23+
outputTokenLimit?: number,
24+
options?: CallLLMOptions
25+
): Promise<string>;
26+
}
27+
28+
export type CallLLMOptions = {
29+
// Values to be added to the parameters property on the request.
30+
parameters?: {
31+
guided_json?: string; // TODO: define the type in detail
32+
};
33+
// Properties to be added to the body of the request.
34+
properties?: {
35+
stop_sequence?: string[]; // TODO: define the type in detail
36+
};
37+
};

src/types/llmService/index.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/*
2+
* Copyright (c) 2025, salesforce.com, inc.
3+
* All rights reserved.
4+
* Licensed under the BSD 3-Clause license.
5+
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
6+
*/
7+
export * from './LLMService';

test/services/serviceProvider.test.ts

+20
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,26 @@ describe('ServiceProvider', () => {
110110
});
111111
});
112112

113+
it('should correctly identify that a service is available if the associated command is registered', async () => {
114+
const isAvailable = await ServiceProvider.isServiceAvailable(
115+
ServiceType.Telemetry
116+
);
117+
expect(isAvailable).toBe(true);
118+
});
119+
120+
it('should correctly identify that a service is not available if the associated command is not registered', async () => {
121+
jest
122+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
123+
.spyOn(ServiceProvider as any, 'getCommands')
124+
.mockImplementation(() => {
125+
return Promise.resolve([loggerCommand]);
126+
});
127+
const isAvailable = await ServiceProvider.isServiceAvailable(
128+
ServiceType.Telemetry
129+
);
130+
expect(isAvailable).toBe(false);
131+
});
132+
113133
it('should get a service', async () => {
114134
(vscode.commands.executeCommand as jest.Mock).mockResolvedValue(
115135
'mockService'

yarn.lock

+1-29
Original file line numberDiff line numberDiff line change
@@ -375,23 +375,7 @@
375375
"@commitlint/rules" "^19.6.0"
376376
"@commitlint/types" "^19.5.0"
377377

378-
"@commitlint/load@>6.1.1":
379-
version "19.5.0"
380-
resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-19.5.0.tgz#67f90a294894d1f99b930b6152bed2df44a81794"
381-
integrity sha512-INOUhkL/qaKqwcTUvCE8iIUf5XHsEPCLY9looJ/ipzi7jtGhgmtH7OOFiNvwYgH7mA8osUWOUDV8t4E2HAi4xA==
382-
dependencies:
383-
"@commitlint/config-validator" "^19.5.0"
384-
"@commitlint/execute-rule" "^19.5.0"
385-
"@commitlint/resolve-extends" "^19.5.0"
386-
"@commitlint/types" "^19.5.0"
387-
chalk "^5.3.0"
388-
cosmiconfig "^9.0.0"
389-
cosmiconfig-typescript-loader "^5.0.0"
390-
lodash.isplainobject "^4.0.6"
391-
lodash.merge "^4.6.2"
392-
lodash.uniq "^4.5.0"
393-
394-
"@commitlint/load@^19.6.1":
378+
"@commitlint/load@>6.1.1", "@commitlint/load@^19.6.1":
395379
version "19.6.1"
396380
resolved "https://registry.yarnpkg.com/@commitlint/load/-/load-19.6.1.tgz#5fae8843a6048a2d3d1cc16da0af8ee532fa9db4"
397381
integrity sha512-kE4mRKWWNju2QpsCWt428XBvUH55OET2N4QKQ0bF85qS/XbsRGG1MiTByDNlEVpEPceMkDr46LNH95DtRwcsfA==
@@ -1655,13 +1639,6 @@ core-util-is@~1.0.0:
16551639
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
16561640
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
16571641

1658-
cosmiconfig-typescript-loader@^5.0.0:
1659-
version "5.0.0"
1660-
resolved "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-5.0.0.tgz"
1661-
integrity sha512-+8cK7jRAReYkMwMiG+bxhcNKiHJDM6bR9FD/nGBXOWdMLuYawjF5cGrtLilJ+LGd3ZjCXnJjR5DkfWPoIVlqJA==
1662-
dependencies:
1663-
jiti "^1.19.1"
1664-
16651642
cosmiconfig-typescript-loader@^6.1.0:
16661643
version "6.1.0"
16671644
resolved "https://registry.yarnpkg.com/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-6.1.0.tgz#7f644503e1c2bff90aed2d29a637008f279646bb"
@@ -3113,11 +3090,6 @@ jest@^29.7.0:
31133090
import-local "^3.0.2"
31143091
jest-cli "^29.7.0"
31153092

3116-
jiti@^1.19.1:
3117-
version "1.21.0"
3118-
resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz"
3119-
integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==
3120-
31213093
jiti@^2.4.1:
31223094
version "2.4.2"
31233095
resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.4.2.tgz#d19b7732ebb6116b06e2038da74a55366faef560"

0 commit comments

Comments
 (0)