Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add Langchain integration #120

Merged
merged 115 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from 99 commits
Commits
Show all changes
115 commits
Select commit Hold shift + click to select a range
bcea967
add boilerplate
tomfrenken Aug 28, 2024
47c99e8
add dependencies
tomfrenken Aug 28, 2024
4e04a33
commit temp
tomfrenken Aug 29, 2024
57f1763
Merge branch 'main' of https://github.com/SAP/ai-sdk-js into langchai…
tomfrenken Aug 29, 2024
4ab7b4e
fix lockfile
tomfrenken Aug 29, 2024
b9bde16
change structure
tomfrenken Aug 30, 2024
ae95a75
WIP
tomfrenken Aug 30, 2024
7f2fbc2
temp
tomfrenken Sep 2, 2024
14a84d0
Merge branch 'main' of https://github.com/SAP/ai-sdk-js into langchai…
tomfrenken Sep 2, 2024
739f287
replace most types
tomfrenken Sep 2, 2024
f8025f1
adjust most types
tomfrenken Sep 2, 2024
c4a4467
add dependency and update methods
tomfrenken Sep 3, 2024
f8184ab
remove redundant exports and change names
tomfrenken Sep 3, 2024
2dfd962
Merge branch 'main' of https://github.com/SAP/ai-sdk-js into langchai…
tomfrenken Sep 3, 2024
2402f3b
merge main
tomfrenken Sep 3, 2024
810284f
save
tomfrenken Sep 3, 2024
3b67a7c
fix 99% problems
tomfrenken Sep 3, 2024
92c63ef
add typedoc
tomfrenken Sep 3, 2024
ba8dec0
restructure
tomfrenken Sep 3, 2024
7102712
1.0
tomfrenken Sep 3, 2024
d98e1c7
rename etc
tomfrenken Sep 3, 2024
0b309a9
lint
tomfrenken Sep 4, 2024
dc9ba61
merge
tomfrenken Sep 5, 2024
0277157
update tests
tomfrenken Sep 5, 2024
f4f771a
save
tomfrenken Sep 5, 2024
f020e2b
Merge branch 'main' of https://github.com/SAP/ai-sdk-js into langchai…
tomfrenken Sep 5, 2024
c6ac615
refactor
tomfrenken Sep 5, 2024
13439ee
stash
tomfrenken Sep 6, 2024
fbf6e9a
update chat client
tomfrenken Sep 6, 2024
fd18586
adjust api
tomfrenken Sep 9, 2024
737c6df
adjust structure
tomfrenken Sep 9, 2024
8e2c2ac
final refactor before pr
tomfrenken Sep 9, 2024
1ad6524
merge
tomfrenken Sep 9, 2024
002b904
fix most type issues
tomfrenken Sep 9, 2024
5421643
anotha one
tomfrenken Sep 9, 2024
41e644b
'final' cleanup
tomfrenken Sep 9, 2024
57d6884
fix: Changes from lint
Sep 9, 2024
74f1460
switch to azure types
tomfrenken Sep 9, 2024
ea2037f
lint an new lines
tomfrenken Sep 9, 2024
9685842
dumbo
tomfrenken Sep 9, 2024
8be3fbc
merge main
tomfrenken Sep 9, 2024
4c077ae
adjust
tomfrenken Sep 9, 2024
e71bcb0
Merge branch 'main' of https://github.com/SAP/ai-sdk-js into langchai…
tomfrenken Sep 10, 2024
48ad22a
Merge branch 'main' of https://github.com/SAP/ai-sdk-js into langchai…
tomfrenken Sep 10, 2024
b2f40a0
change visibility, merge main
tomfrenken Sep 10, 2024
40c933a
simplify
tomfrenken Sep 10, 2024
7e6d928
update docs
tomfrenken Sep 10, 2024
187daee
add public api check
tomfrenken Sep 10, 2024
5c826ff
add baseline docs
tomfrenken Sep 10, 2024
de5fdd7
adjust type
tomfrenken Sep 11, 2024
4405f25
rename clients
tomfrenken Sep 11, 2024
9680f53
update docs
tomfrenken Sep 12, 2024
62c3e92
fix: Changes from lint
Sep 12, 2024
e04298d
add docs
tomfrenken Sep 12, 2024
9f6904c
lint
tomfrenken Sep 12, 2024
8536a17
add type tests
tomfrenken Sep 12, 2024
f28693a
fix: Changes from lint
Sep 12, 2024
6811213
add docs
tomfrenken Sep 12, 2024
212e2f6
merge
tomfrenken Sep 12, 2024
bab7d81
improve chunking
tomfrenken Sep 12, 2024
4c46d34
move another mapping
tomfrenken Sep 12, 2024
a4ef25c
add sample code and e2e tests
tomfrenken Sep 12, 2024
8d96f55
lint
tomfrenken Sep 12, 2024
f22a3f0
Merge branch 'main' of https://github.com/SAP/ai-sdk-js into langchai…
tomfrenken Sep 13, 2024
f80afcc
merge and rename
tomfrenken Sep 13, 2024
cd81c73
update types
tomfrenken Sep 13, 2024
115d6e9
start with snapshot tests
tomfrenken Sep 13, 2024
87a7cde
add another mapping test
tomfrenken Sep 13, 2024
43a4db8
finish unit tests
tomfrenken Sep 13, 2024
1902dec
lint
tomfrenken Sep 13, 2024
2625cd2
fix exports
tomfrenken Sep 13, 2024
bc66a45
update readme
tomfrenken Sep 16, 2024
3e97d8f
Merge branch 'main' of https://github.com/SAP/ai-sdk-js into langchai…
tomfrenken Sep 16, 2024
a62dba0
add ultility and merge main
tomfrenken Sep 16, 2024
2d41b66
bump version and other suggestions
tomfrenken Sep 16, 2024
21907d1
fix: Changes from lint
Sep 16, 2024
e64243e
change visibility, naming, docs
tomfrenken Sep 16, 2024
bf5d5d6
fix: Changes from lint
Sep 16, 2024
198cabd
move to basechatmodel
tomfrenken Sep 17, 2024
50b902a
adjust input
tomfrenken Sep 17, 2024
e8dd09f
almost there
tomfrenken Sep 17, 2024
19c8ba5
update visibiltiy and mapping
tomfrenken Sep 18, 2024
d0c50f2
fix mocking function, improve tests, update mapping
tomfrenken Sep 18, 2024
a0c44e3
fix mocking function, improve tests, update mapping
tomfrenken Sep 18, 2024
cc3a007
remove redundant dependencies
tomfrenken Sep 18, 2024
728e81b
adjust api
tomfrenken Sep 18, 2024
d5606a8
merge
tomfrenken Sep 18, 2024
d4b5344
fix: Changes from lint
Sep 18, 2024
addf4de
review
tomfrenken Sep 18, 2024
9d2abcc
fix: Changes from lint
Sep 18, 2024
9cb5195
naming
tomfrenken Sep 18, 2024
e5f50bc
Merge branch 'langchain-integration' of https://github.com/SAP/ai-sdk…
tomfrenken Sep 18, 2024
3e7a25e
fix: Changes from lint
Sep 18, 2024
03c1b52
adjust everything
tomfrenken Sep 18, 2024
2311225
lint
tomfrenken Sep 18, 2024
16d771f
adjust mapping test
tomfrenken Sep 18, 2024
db7477a
update docs
tomfrenken Sep 19, 2024
1262796
update typedocs
tomfrenken Sep 19, 2024
e91e0c5
Update packages/ai-api/src/utils/deployment-resolver.ts
marikaner Sep 19, 2024
2370aa3
Update packages/langchain/README.md
deekshas8 Sep 19, 2024
925b9d6
Update packages/langchain/README.md
deekshas8 Sep 19, 2024
2522a9a
review
tomfrenken Sep 19, 2024
643412f
merge
tomfrenken Sep 19, 2024
c97c22f
Apply suggestions from code review
deekshas8 Sep 19, 2024
659f8fb
Update packages/langchain/README.md
deekshas8 Sep 19, 2024
e04d63a
more review comments
tomfrenken Sep 19, 2024
94c7f61
merge
tomfrenken Sep 19, 2024
dfd2689
merge with main
tomfrenken Sep 19, 2024
5e9debe
update everything
tomfrenken Sep 19, 2024
e7a7abd
Merge branch 'main' into langchain-integration
tomfrenken Sep 19, 2024
e4155c7
lockfile and lint
tomfrenken Sep 19, 2024
3118383
snap
tomfrenken Sep 19, 2024
facc79c
update snapshot
tomfrenken Sep 19, 2024
5be9a50
add langchain to root readme
tomfrenken Sep 19, 2024
09f8699
fix root readme ...
tomfrenken Sep 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,20 @@ export default [
'jsdoc/require-jsdoc': 'off'
}
},
{
files: [
'**/packages/orchestration/src/client/api/default-api.ts'
deekshas8 marked this conversation as resolved.
Show resolved Hide resolved
],
rules: {
'@typescript-eslint/explicit-module-boundary-types': 'off'
}
},
MatKuhr marked this conversation as resolved.
Show resolved Hide resolved
tomfrenken marked this conversation as resolved.
Show resolved Hide resolved
{
files: ['packages/langchain/**/*.ts'],
rules: {
'import/no-internal-modules': 'off'
}
},
{
ignores: ['**/dist-cjs/**/*']
}
Expand Down
3 changes: 2 additions & 1 deletion packages/ai-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"check:public-api": "node --loader ts-node/esm ../../scripts/check-public-api-cli.ts"
},
"dependencies": {
"@sap-ai-sdk/core": "workspace:^"
"@sap-ai-sdk/core": "workspace:^",
"@sap-cloud-sdk/util": "^3.20.0"
tomfrenken marked this conversation as resolved.
Show resolved Hide resolved
},
"devDependencies": {
"typescript": "^5.5.4",
Expand Down
47 changes: 47 additions & 0 deletions packages/foundation-models/src/openai/openai-response.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { parseMockResponse } from '../../../../test-util/mock-http.js';
import { OpenAiChatCompletionResponse } from './openai-response.js';
import { OpenAiChatCompletionOutput } from './openai-types.js';

describe('OpenAI response', () => {
const mockResponse = parseMockResponse<OpenAiChatCompletionOutput>(
'foundation-models',
'openai-chat-completion-success-response.json'
);
const rawResponse = {
data: mockResponse,
status: 200,
headers: {},
request: {}
};
const openAiChatClientResponse = new OpenAiChatCompletionResponse(
rawResponse
);

it('should initialize with raw response', () => {
expect(openAiChatClientResponse.rawResponse).toBe(rawResponse);
});

it('should return the completion response', () => {
expect(openAiChatClientResponse.data).toBe(mockResponse);
});

it('should get token usage', () => {
expect(openAiChatClientResponse.getTokenUsage()).toMatchObject({
completion_tokens: expect.any(Number),
prompt_tokens: expect.any(Number),
total_tokens: expect.any(Number)
});
});

it('should return default choice index with convenience functions', () => {
expect(openAiChatClientResponse.getFinishReason()).toBe('stop');
expect(openAiChatClientResponse.getContent()).toBe(
'The deepest place on Earth is located in the Western Pacific Ocean and is known as the Mariana Trench.'
);
});

it('should return undefined when convenience function is called with incorrect index', () => {
expect(openAiChatClientResponse.getFinishReason(1)).toBeUndefined();
expect(openAiChatClientResponse.getContent(1)).toBeUndefined();
});
});
102 changes: 102 additions & 0 deletions packages/langchain/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# @sap-ai-sdk/langchain
This package provides LangChain model clients, built on top of the `@sap-ai-sdk`.
deekshas8 marked this conversation as resolved.
Show resolved Hide resolved

## Table of Contents
1. [Installation](#installation)
2. [Pre-requisites](#pre-requisites)
3. [Usage](#usage)
- [Client Initialization](#client-initialization)
- [Chat Clients](#chat-clients)
- [Embedding Clients](#embedding-clients)
4. [Support, Feedback, Contribution](#support-feedback-contribution)
5. [License](#license)
tomfrenken marked this conversation as resolved.
Show resolved Hide resolved

## Installation
```
$ npm install @sap-ai-sdk/langchain
```

## Pre-requisites
- [Enable the AI Core service in BTP](https://help.sap.com/docs/sap-ai-core/sap-ai-core-service-guide/initial-setup).
deekshas8 marked this conversation as resolved.
Show resolved Hide resolved
- Bind the service to your application.
- Ensure the project is configured with Node.js v20 or higher, along with native ESM support.
- For testing your application locally:
- Download a service key for your AI Core service instance.
- Create a `.env` file in the sample-code directory.
tomfrenken marked this conversation as resolved.
Show resolved Hide resolved
tomfrenken marked this conversation as resolved.
Show resolved Hide resolved
- Add an entry `AICORE_SERVICE_KEY='<content-of-service-key>'`.

## Usage
This package provides both chat and embedding clients, currently supporting Azure OpenAI.
tomfrenken marked this conversation as resolved.
Show resolved Hide resolved
All clients comply with [LangChain's interface](https://js.langchain.com/docs/introduction).

### Client Initialization
To initialize a client, you only need to provide the model name:
deekshas8 marked this conversation as resolved.
Show resolved Hide resolved

```ts
import { AzureOpenAiChatClient } from '@sap-ai-sdk/langchain';
const chatClient = new AzureOpenAiChatClient({ modelName: 'gpt-4o' });
```

In addition to the default parameters of the model vendor (e.g. OpenAI) and LangChain, there are also SDK-specific parameters, which you can use to narrow down the search for the model you want to use:
deekshas8 marked this conversation as resolved.
Show resolved Hide resolved

```ts
const chatClient = new AzureOpenAiChatClient({
modelName: 'gpt-4o',
modelVersion: '24-07-2021',
resourceGroup: 'my-resource-group'
});
```

### Chat Clients
tomfrenken marked this conversation as resolved.
Show resolved Hide resolved
tomfrenken marked this conversation as resolved.
Show resolved Hide resolved
The chat clients allow you to interact with Azure OpenAI chat models, accessible via SAP Gen AI Hub.
deekshas8 marked this conversation as resolved.
Show resolved Hide resolved
To invoke the client, you only have a to pass a prompt.
tomfrenken marked this conversation as resolved.
Show resolved Hide resolved

#### Simple Example
tomfrenken marked this conversation as resolved.
Show resolved Hide resolved
```ts
const response = await chatClient.invoke("What's the capital of France?");
```

#### Advanced Example with Templating and Output Parsing
```ts
import { AzureOpenAiChatClient } from '@sap-ai-sdk/langchain';
import { StringOutputParser } from '@langchain/core/output_parsers';
import { ChatPromptTemplate } from '@langchain/core/prompts';

const client = new AzureOpenAiChatClient({ modelName: 'gpt-35-turbo' });
const promptTemplate = ChatPromptTemplate.fromMessages([
['system', 'Answer the following in {language}:'],
['user', '{text}']
]);
const parser = new StringOutputParser();
const llmChain = promptTemplate.pipe(client).pipe(parser);
const response = await llmChain.invoke({
language: 'german',
text: 'What is the capital of France?'
});
```

### Embedding Clients
Embedding clients allow embedding either text or documents (represented as arrays of strings).
tomfrenken marked this conversation as resolved.
Show resolved Hide resolved

#### Embed Text
```ts
const embeddedText = await embeddingClient.embedQuery(
'Paris is the capital of France.'
);
```

#### Embed Documents
```ts
const embeddedDocument = await embeddingClient.embedDocuments([
'Page 1: Paris is the capital of France.',
'Page 2: It is a beautiful city.'
]);
```

## Support, Feedback, Contribution
This project is open to feature requests/suggestions, bug reports etc. via [GitHub issues](https://github.com/SAP/ai-sdk-js/issues).

Contribution and feedback are encouraged and always welcome. For more information about how to contribute, the project structure, as well as additional contribution information, see our [Contribution Guidelines](https://github.com/SAP/ai-sdk-js/blob/main/CONTRIBUTING.md).

## License
The SAP Cloud SDK for AI is released under the [Apache License Version 2.0.](http://www.apache.org/licenses/)
deekshas8 marked this conversation as resolved.
Show resolved Hide resolved
3 changes: 3 additions & 0 deletions packages/langchain/internal.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// eslint-disable-next-line import/no-internal-modules
export * from './dist/internal.js';
// # sourceMappingURL=internal.d.ts.map
2 changes: 2 additions & 0 deletions packages/langchain/internal.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions packages/langchain/jest.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import config from '../../jest.config.mjs';
export default {
...config,
displayName: 'langchain',
};
39 changes: 39 additions & 0 deletions packages/langchain/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"name": "@sap-ai-sdk/langchain",
"version": "0.0.0",
tomfrenken marked this conversation as resolved.
Show resolved Hide resolved
"description": "LangChain clients based on the @sap-ai-sdk",
"license": "Apache-2.0",
"keywords": [
"sap-ai-sdk",
tomfrenken marked this conversation as resolved.
Show resolved Hide resolved
"langchain"
],
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"dist/**/*.js",
"dist/**/*.js.map",
"dist/**/*.d.ts",
"dist/**/*.d.ts.map",
"internal.js",
"internal.d.ts"
],
"scripts": {
"compile": "tsc",
"compile:cjs": "tsc -p tsconfig.cjs.json",
"test": "NODE_OPTIONS=--experimental-vm-modules jest",
"lint": "eslint \"**/*.ts\" && prettier . --config ../../.prettierrc --ignore-path ../../.prettierignore -c",
"lint:fix": "eslint \"**/*.ts\" --fix && prettier . --config ../../.prettierrc --ignore-path ../../.prettierignore -w --log-level error",
"check:public-api": "node --loader ts-node/esm ../../scripts/check-public-api-cli.ts"
},
"dependencies": {
"@sap-ai-sdk/ai-api": "workspace:^",
"@sap-ai-sdk/foundation-models": "workspace:^",
"@langchain/core": "0.3.1",
"zod-to-json-schema": "^3.23.2",
"@sap-cloud-sdk/util": "^3.20.0"
},
"devDependencies": {
"typescript": "^5.5.4"
}
}
9 changes: 9 additions & 0 deletions packages/langchain/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export {
AzureOpenAiChatClient,
AzureOpenAiEmbeddingClient
} from './openai/index.js';
export type {
AzureOpenAiChatModelParams,
AzureOpenAiEmbeddingModelParams,
AzureOpenAiChatCallOptions
} from './openai/index.js';
1 change: 1 addition & 0 deletions packages/langchain/src/internal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './openai/index.js';
50 changes: 50 additions & 0 deletions packages/langchain/src/openai/__snapshots__/util.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Mapping Functions should parse an OpenAi response to a (Langchain) chat response 1`] = `
{
"generations": [
{
"generationInfo": {
"finish_reason": "stop",
"function_call": undefined,
"index": 0,
"tool_calls": undefined,
},
"message": {
"id": [
"langchain_core",
"messages",
"AIMessage",
],
"kwargs": {
"additional_kwargs": {
"finish_reason": "stop",
"function_call": undefined,
"index": 0,
"tool_call_id": "",
"tool_calls": undefined,
},
"content": "The deepest place on Earth is located in the Western Pacific Ocean and is known as the Mariana Trench.",
"invalid_tool_calls": [],
"response_metadata": {},
"tool_calls": [],
},
"lc": 1,
"type": "constructor",
},
"text": "The deepest place on Earth is located in the Western Pacific Ocean and is known as the Mariana Trench.",
},
],
"llmOutput": {
"created": 1725457796,
"id": "chatcmpl-A3kgOwg9B6j87n0IkoCFCUCxRSwQZ",
"model": "gpt-4-32k",
"object": "chat.completion",
"tokenUsage": {
"completionTokens": 22,
"promptTokens": 15,
"totalTokens": 37,
},
},
}
`;
78 changes: 78 additions & 0 deletions packages/langchain/src/openai/chat.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';
import { BaseMessage } from '@langchain/core/messages';
import type { ChatResult } from '@langchain/core/outputs';
import { AzureOpenAiChatClient as AzureOpenAiChatClientBase } from '@sap-ai-sdk/foundation-models';
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
import { AzureOpenAiChatModel } from '@sap-ai-sdk/core';
import { mapLangchainToAiClient, mapOutputToChatResult } from './util.js';
import type {
AzureOpenAiChatCallOptions,
AzureOpenAiChatModelParams
} from './types.js';

/**
* LangChain chat client for Azure OpenAI consumption on SAP BTP.
*/
export class AzureOpenAiChatClient
extends BaseChatModel<AzureOpenAiChatCallOptions>
implements AzureOpenAiChatModelParams
{
modelName: AzureOpenAiChatModel;
modelVersion?: string;
resourceGroup?: string;
tomfrenken marked this conversation as resolved.
Show resolved Hide resolved
temperature?: number;
top_p?: number;
logit_bias?: Record<string, unknown>;
user?: string;
n?: number;
presence_penalty?: number;
frequency_penalty?: number;
stop?: string | string[];
max_tokens?: number;
private openAiChatClient: AzureOpenAiChatClientBase;

constructor(fields: AzureOpenAiChatModelParams) {
super(fields);
this.openAiChatClient = new AzureOpenAiChatClientBase(fields);
this.modelName = fields.modelName;
this.modelVersion = fields.modelVersion;
this.resourceGroup = fields.resourceGroup;
this.temperature = fields.temperature;
this.top_p = fields.top_p;
this.logit_bias = fields.logit_bias;
this.user = fields.user;
this.n = fields.n;
this.stop = fields.stop;
this.presence_penalty = fields.presence_penalty;
this.frequency_penalty = fields.frequency_penalty;
this.max_tokens = fields.max_tokens;
tomfrenken marked this conversation as resolved.
Show resolved Hide resolved
}

_llmType(): string {
return 'azure_openai';
}

override async _generate(
messages: BaseMessage[],
options: typeof this.ParsedCallOptions,
runManager?: CallbackManagerForLLMRun
): Promise<ChatResult> {
const res = await this.caller.callWithOptions(
{
signal: options.signal
},
() =>
this.openAiChatClient.run(
mapLangchainToAiClient(this, options, messages),
options.requestConfig
)
);

// we currently do not support streaming
await runManager?.handleLLMNewToken(
typeof res.getContent() === 'string' ? (res.getContent() as string) : ''
);
tomfrenken marked this conversation as resolved.
Show resolved Hide resolved

return mapOutputToChatResult(res.data);
}
}
Loading