├── icon.png ├── samples └── LangChainJSDemo │ ├── appsettings.json │ ├── Properties │ └── launchSettings.json │ ├── LangChainJSDemo.csproj │ └── Program.cs ├── src ├── LangChainJSDotNet.IntegrationTests │ ├── appsettings.json │ ├── OpenAITests.cs │ ├── LangChainJSDotNet.IntegrationTests.csproj │ └── mockoon-api.json └── LangChainJSDotNet │ ├── .gitignore │ ├── babel.config.json │ ├── Crypto.cs │ ├── src │ ├── template.js │ ├── browser.js │ └── consts.js │ ├── HostTimer.cs │ ├── package.json │ ├── LangChainJSDotNet.csproj │ ├── gulpfile.mjs │ ├── Http.cs │ ├── LangChainJS.cs │ └── dist │ └── url.js ├── .github ├── dependabot.yml └── workflows │ ├── build.yml │ ├── bump.yml │ └── publish.yml ├── LICENSE ├── LangChainJSDotNet.sln ├── README.md └── .gitignore /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iassafc/LangChainJSDotNet/HEAD/icon.png -------------------------------------------------------------------------------- /samples/LangChainJSDemo/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "OPENAI_API_KEY": "ADD YOUR OPENAI API KEY HERE OR IN YOUR USER SECRETS FILE" 3 | } 4 | -------------------------------------------------------------------------------- /src/LangChainJSDotNet.IntegrationTests/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "OPENAI_API_KEY": "ADD YOUR OPENAI API KEY HERE OR IN YOUR USER SECRETS FILE" 3 | } 4 | -------------------------------------------------------------------------------- /src/LangChainJSDotNet/.gitignore: -------------------------------------------------------------------------------- 1 | # autogenerated langchainjs imports 2 | src/autogen.js 3 | # autogenerated bundle file 4 | dist/bundle.js 5 | # node modules 6 | node_modules -------------------------------------------------------------------------------- /src/LangChainJSDotNet/babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "plugins": [ 3 | "@babel/plugin-transform-logical-assignment-operators", 4 | "@babel/plugin-transform-export-namespace-from" 5 | ] 6 | } -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: "src/LangChainJSDotNet" 5 | schedule: 6 | interval: "daily" 7 | allow: 8 | - dependency-name: "langchain" 9 | -------------------------------------------------------------------------------- /samples/LangChainJSDemo/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "LangChainJSDemo": { 4 | "commandName": "Project" 5 | }, 6 | "WSL2": { 7 | "commandName": "WSL2", 8 | "distributionName": "" 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /src/LangChainJSDotNet/Crypto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security.Cryptography; 3 | using Microsoft.ClearScript.JavaScript; 4 | 5 | namespace LangChainJSDotNet 6 | { 7 | internal sealed class Crypto 8 | { 9 | public static unsafe ITypedArray GetRandomValues(ITypedArray array) 10 | { 11 | var size = Convert.ToInt32(array.Size); 12 | array.InvokeWithDirectAccess(pBytes => { 13 | RandomNumberGenerator.Fill(new Span(pBytes.ToPointer(), size)); 14 | }); 15 | return array; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/LangChainJSDotNet/src/template.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs/promises'; 2 | 3 | export const header = `/* 4 | * This file was autogenerated. Do not commit to source control 5 | */ 6 | import { z } from "zod"; 7 | globalThis.z = z; 8 | 9 | // ********************* 10 | `; 11 | 12 | export const footer = ` 13 | // *********************`; 14 | 15 | export const getItems = async () => { 16 | let data = await fs.readFile('node_modules/langchain/package.json', 'utf8'); 17 | let pkg = JSON.parse(data); 18 | return Object.keys(pkg.exports); 19 | }; 20 | 21 | export const bodyItem = (key) => { 22 | while (key.startsWith('.') || key.startsWith('/')) { 23 | key = key.slice(1); 24 | } 25 | const id = key.replace(/[\/.]/g, '_') || '_'; 26 | return ` 27 | import * as ${id} from 'langchain/${key}'; 28 | for (const key in ${id}) { 29 | globalThis[key] = ${id}[key]; 30 | } 31 | `; 32 | }; 33 | -------------------------------------------------------------------------------- /src/LangChainJSDotNet/HostTimer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | namespace LangChainJSDotNet 5 | { 6 | internal sealed class HostTimer 7 | { 8 | private Timer _timer; 9 | private Func _callback = () => Timeout.Infinite; 10 | public void Initialize(dynamic callback) => _callback = () => (double)callback(); 11 | public void Schedule(double delay) 12 | { 13 | if (delay < 0) 14 | { 15 | if (_timer != null) 16 | { 17 | _timer.Dispose(); 18 | _timer = null; 19 | } 20 | } 21 | else 22 | { 23 | if (_timer == null) _timer = new Timer(_ => Schedule(_callback())); 24 | _timer.Change(TimeSpan.FromMilliseconds(delay), Timeout.InfiniteTimeSpan); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/LangChainJSDotNet/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module", 3 | "private": true, 4 | "dependencies": { 5 | "abortcontroller-polyfill": "^1.7.5", 6 | "blob-polyfill": "^7.0.20220408", 7 | "formdata-polyfill": "^4.0.10", 8 | "html-to-text": "^9.0.5", 9 | "langchain": "^0.1.37", 10 | "mock-xmlhttprequest": "^8.2.0", 11 | "text-encoding": "^0.7.0", 12 | "web-streams-polyfill": "^4.0.0-beta.3", 13 | "whatwg-fetch": "^3.6.2" 14 | }, 15 | "devDependencies": { 16 | "@babel/cli": "^7.22.9", 17 | "@babel/core": "^7.22.9", 18 | "@babel/plugin-transform-export-namespace-from": "^7.22.5", 19 | "@babel/plugin-transform-logical-assignment-operators": "^7.22.5", 20 | "babelify": "^10.0.0", 21 | "browserify": "^17.0.0", 22 | "esmify": "^2.1.1", 23 | "gulp": "^4.0.2", 24 | "gulp-replace": "^1.1.4", 25 | "vinyl-source-stream": "^2.0.0" 26 | }, 27 | "scripts": { 28 | "dotnet-prebuild": "gulp" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) Harrison Chase 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: "Build Branch" 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - synchronize 8 | - reopened 9 | branches: 10 | - 'main' 11 | push: 12 | branches: 13 | - 'main' 14 | 15 | jobs: 16 | build-branch: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: 'Install dotnet' 20 | uses: actions/setup-dotnet@v3 21 | with: 22 | dotnet-version: 7.x 23 | 24 | - name: 'Checkout branch' 25 | uses: actions/checkout@v3 26 | 27 | - name: 'Install npm dependencies' 28 | run: npm install 29 | working-directory: src/LangChainJSDotNet 30 | 31 | - name: 'Restore packages' 32 | run: dotnet restore ${{ env.PROJECT_PATH }} 33 | 34 | - name: 'Build project' 35 | run: dotnet build ${{ env.PROJECT_PATH }} --no-restore --configuration Release 36 | 37 | - name: 'Start testing API' 38 | uses: JarvusInnovations/background-action@v1 39 | with: 40 | run: | 41 | sudo echo "127.0.0.1 api.openai.com" | sudo tee -a /etc/hosts 42 | npm install -g @mockoon/cli 43 | sudo mockoon-cli start --port 443 --data ./src/LangChainJSDotNet.IntegrationTests/mockoon-api.json & 44 | wait-on: | 45 | tcp:localhost:443 46 | wait-for: 1m 47 | 48 | - name: 'Run Tests' 49 | run: dotnet test --runtime linux-x64 -------------------------------------------------------------------------------- /samples/LangChainJSDemo/LangChainJSDemo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net7.0 6 | enable 7 | enable 8 | 9cb8158c-9c33-430e-80c8-fcb8106996f9 9 | win-x64 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | PreserveNewest 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/LangChainJSDotNet.IntegrationTests/OpenAITests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using Xunit; 3 | 4 | namespace LangChainJSDotNet.IntegrationTests 5 | { 6 | public class OpenAITests 7 | { 8 | private IConfiguration Configuration { get; set; } 9 | 10 | private static HttpClient? _httpClient; 11 | 12 | public OpenAITests() 13 | { 14 | var builder = new ConfigurationBuilder() 15 | .AddJsonFile("appsettings.json", optional: false) 16 | .AddUserSecrets(); 17 | 18 | Configuration = builder.Build(); 19 | 20 | // Allow self signed certificates for integration testing with mock API 21 | var httpClientHandler = new HttpClientHandler(); 22 | httpClientHandler.ServerCertificateCustomValidationCallback = 23 | HttpClientHandler.DangerousAcceptAnyServerCertificateValidator; 24 | _httpClient = new HttpClient(httpClientHandler); 25 | } 26 | 27 | [Theory] 28 | [InlineData("1+1?", "2")] 29 | public async Task OpenAI_Returns_Expected(string text, string expected) 30 | { 31 | using var langchainjs = new LangChainJS(false, _httpClient); 32 | 33 | langchainjs.SetEnvironmentVariable("OPENAI_API_KEY", Configuration["OPENAI_API_KEY"]); 34 | 35 | langchainjs.Setup(@$" 36 | 37 | const model = new OpenAI({{ temperature: 0 }}); 38 | 39 | globalThis.run = async () => {{ 40 | 41 | const res = await model.call('{text}'); 42 | 43 | return res.trim(); 44 | }} 45 | "); 46 | 47 | var result = await langchainjs.InvokeAsync("run"); 48 | 49 | Assert.Equal(expected, result); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /src/LangChainJSDotNet/LangChainJSDotNet.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.1 5 | true 6 | true 7 | LangChainJSDotNet 8 | 9 | A thin .NET wrapper around the official LangChain.js library 10 | 11 | LangChain LangChainJS LLM OpenAI 12 | LangChainJSDotNet 13 | 0.1.37.1 14 | Assaf Cohen 15 | icon.png 16 | README.md 17 | MIT 18 | git 19 | https://github.com/iassafc/LangChainJSDotNet 20 | 5197df41-4abd-4a44-b5af-c48e5bca2feb 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/LangChainJSDotNet/gulpfile.mjs: -------------------------------------------------------------------------------- 1 | import gulp from 'gulp'; 2 | import replace from 'gulp-replace'; 3 | import browserify from 'browserify'; 4 | import source from 'vinyl-source-stream'; 5 | import fs from 'fs/promises'; 6 | import * as template from './src/template.js'; 7 | import { supportedImports, unsupportedImportPrefixes } from './src/consts.js'; 8 | 9 | export const generateImports = async () => { 10 | try { 11 | const keys = await template.getItems(); 12 | const lines = keys.map(key => { 13 | // only allow imports specifically listed in 'supportedImports' 14 | // or anything without an unsupported prefix, if above root level 15 | if ((key.split('/').length > 2 && 16 | !unsupportedImportPrefixes.some(prefix => key.startsWith(prefix))) || 17 | supportedImports.includes(key)) { 18 | return template.bodyItem(key); 19 | } else { 20 | console.log('Skipping: ' + key); 21 | } 22 | }); 23 | lines.unshift(template.header); 24 | lines.push(template.footer); 25 | await fs.writeFile('src/autogen.js', lines.join('')); 26 | } catch (err) { 27 | console.error(err); 28 | } 29 | }; 30 | 31 | export const createBundle = () => { 32 | return browserify([ 33 | // simulates browser environment 34 | 'src/browser.js', 35 | // autogenerated langchainjs imports 36 | 'src/autogen.js' 37 | ], 38 | { 39 | plugin: ['esmify'], 40 | transform: [['babelify', { global: true }]] 41 | }) 42 | .bundle() 43 | .pipe(source('bundle.js')) 44 | .pipe(gulp.dest('dist')); 45 | } 46 | 47 | export const editBundle = () => { 48 | return gulp.src('dist/bundle.js') 49 | .pipe(replace( 50 | // allows injecting environment variables 51 | 'process.env?.[name] : undefined;', 52 | 'globalThis.process.env?.[name] : undefined;' 53 | )) 54 | .pipe(gulp.dest('dist')); 55 | }; 56 | 57 | const allTasks = gulp.series(generateImports, createBundle, editBundle); 58 | 59 | export default allTasks; -------------------------------------------------------------------------------- /src/LangChainJSDotNet/src/browser.js: -------------------------------------------------------------------------------- 1 | // whatwg-fetch 2 | import { Headers, Request, Response, DOMException, fetch } from 'whatwg-fetch'; 3 | globalThis.Headers = Headers; 4 | globalThis.Request = Request; 5 | globalThis.Response = Response; 6 | globalThis.DOMException = DOMException; 7 | globalThis.fetch = fetch; 8 | 9 | // text-encoding 10 | import { TextEncoder, TextDecoder } from 'text-encoding'; 11 | globalThis.TextEncoder = TextEncoder; 12 | globalThis.TextDecoder = TextDecoder; 13 | 14 | // abortcontroller-polyfill 15 | import 'abortcontroller-polyfill/dist/polyfill-patch-fetch'; 16 | AbortSignal.timeout = (duration) => 17 | { 18 | const controller = new AbortController; 19 | setTimeout(() => controller.abort(), duration); 20 | return controller.signal; 21 | }; 22 | 23 | // web-streams-polyfill 24 | import 'web-streams-polyfill/polyfill'; 25 | 26 | // blob-polyfill 27 | import { Blob } from 'blob-polyfill'; 28 | globalThis.Blob = Blob; 29 | 30 | // formdata-polyfill 31 | import { FormData } from 'formdata-polyfill/formdata.min.js'; 32 | globalThis.FormData = FormData; 33 | 34 | // mock-xmlhttprequest 35 | import { newMockXhr } from 'mock-xmlhttprequest'; 36 | 37 | const MockXhr = newMockXhr(); 38 | 39 | MockXhr.onSend = async function (request) { 40 | try { 41 | let headers = request.requestHeaders.getHash(); 42 | 43 | let str_body = request.body; 44 | if (typeof request.body !== 'string') { 45 | // If request.body is not a string, decode it using TextDecoder 46 | let decoder = new TextDecoder("utf-8"); 47 | str_body = decoder.decode(request.body); 48 | } 49 | 50 | // asyn response from host HttpClient 51 | let jsonResponse = await HostHttp.SendAsync(request.url, request.method, headers, str_body); 52 | 53 | let response = JSON.parse(jsonResponse); 54 | 55 | request.respond(response.StatusCode, response.Headers, response.Content); 56 | } catch(err) { 57 | console.error(err); 58 | } 59 | } 60 | 61 | // Install in the global context so "new XMLHttpRequest()" creates MockXhr instances 62 | globalThis.XMLHttpRequest = MockXhr; -------------------------------------------------------------------------------- /.github/workflows/bump.yml: -------------------------------------------------------------------------------- 1 | name: "Bump Version [Dependabot PR]" 2 | 3 | on: 4 | workflow_run: 5 | workflows: 6 | - "Build Branch" 7 | types: 8 | - completed 9 | 10 | jobs: 11 | bump-version: 12 | permissions: 13 | contents: write 14 | pull-requests: write 15 | runs-on: ubuntu-latest 16 | if: > 17 | github.event.workflow_run.event == 'pull_request' && 18 | github.event.workflow_run.conclusion == 'success' && 19 | startsWith(github.event.workflow_run.head_branch, 'dependabot/') 20 | steps: 21 | - name: 'Checkout branch' 22 | uses: actions/checkout@v3 23 | with: 24 | ref: ${{ github.event.workflow_run.head_branch }} 25 | 26 | - name: 'Compute version' 27 | uses: actions-ecosystem/action-regex-match@main 28 | id: regex-match 29 | with: 30 | text: ${{ github.event.workflow_run.display_title }} 31 | regex: 'to (\d+\.\d+\.\d+)' 32 | 33 | - name: 'Update version' 34 | id: update 35 | uses: vers-one/dotnet-project-version-updater@v1.3 36 | with: 37 | file: "src/LangChainJSDotNet/LangChainJSDotNet.csproj" 38 | version: "${{ steps.regex-match.outputs.group1 }}.1" 39 | 40 | - name: 'Commit and push' 41 | run: | 42 | git config --local user.name "github-actions[bot]" 43 | git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" 44 | git add . 45 | git commit -m "Bump LangChainJSDotNet from ${{ steps.update.outputs.oldVersion }} to ${{ steps.update.outputs.newVersion }}" 46 | git push origin HEAD:${{ github.event.workflow_run.head_branch }} 47 | 48 | - name: Sleep for 5s 49 | uses: juliangruber/sleep-action@v2.0.0 50 | with: 51 | time: 5s 52 | 53 | - name: 'Auto-merge Dependabot PR' 54 | # Find the PR number based on the current branch name, and merge based on this number 55 | run: 'PR_NUM="$(gh pr list | grep $(git branch --show-current) | cut -f1)"; gh pr merge --merge $PR_NUM' 56 | env: 57 | GH_TOKEN: ${{secrets.GITHUB_TOKEN}} 58 | -------------------------------------------------------------------------------- /src/LangChainJSDotNet.IntegrationTests/LangChainJSDotNet.IntegrationTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | 9cb8158c-9c33-430e-80c8-fcb8106996f9 8 | win-x64 9 | 10 | 11 | false 12 | 13 | 14 | 15 | 16 | 17 | 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | all 20 | 21 | 22 | runtime; build; native; contentfiles; analyzers; buildtransitive 23 | all 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | PreserveNewest 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: "Publish NuGet" 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | env: 7 | PROJECT_PATH: 'src/LangChainJSDotNet/LangChainJSDotNet.csproj' 8 | PACKAGE_OUTPUT_DIRECTORY: ${{ github.workspace }}/output 9 | NUGET_SOURCE_URL: 'https://api.nuget.org/v3/index.json' 10 | 11 | jobs: 12 | publish: 13 | permissions: 14 | contents: write 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: 'Checkout branch' 18 | uses: actions/checkout@v3 19 | 20 | - name: 'Get version' 21 | id: get_version 22 | uses: greenygh0st/net-proj-release-version@v1 23 | with: 24 | PROJ_FILE: "src/LangChainJSDotNet/LangChainJSDotNet.csproj" 25 | 26 | - name: 'Install dotnet' 27 | uses: actions/setup-dotnet@v3 28 | with: 29 | dotnet-version: 7.x 30 | 31 | - name: 'Install npm dependencies' 32 | run: npm install 33 | working-directory: src/LangChainJSDotNet 34 | 35 | - name: 'Restore packages' 36 | run: dotnet restore ${{ env.PROJECT_PATH }} 37 | 38 | - name: 'Build project' 39 | run: dotnet build ${{ env.PROJECT_PATH }} --no-restore --configuration Release 40 | 41 | - name: 'Pack project' 42 | run: dotnet pack ${{ env.PROJECT_PATH }} --no-restore --no-build --configuration Release --include-symbols --output ${{ env.PACKAGE_OUTPUT_DIRECTORY }} 43 | 44 | - name: 'Push package' 45 | run: dotnet nuget push ${{ env.PACKAGE_OUTPUT_DIRECTORY }}/*.nupkg -k ${{ secrets.NUGET_API_KEY }} -s ${{ env.NUGET_SOURCE_URL }} --skip-duplicate 46 | 47 | - name: 'Create tag' 48 | run: | 49 | git config --local user.name "github-actions[bot]" 50 | git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" 51 | git tag -a v${{ steps.get_version.outputs.RELEASE_VERSION }} -m "v${{ steps.get_version.outputs.RELEASE_VERSION }}" 52 | git push origin v${{ steps.get_version.outputs.RELEASE_VERSION }} 53 | 54 | - name: 'Build Changelog' 55 | id: build_changelog 56 | uses: mikepenz/release-changelog-builder-action@v4 57 | env: 58 | toTag: v${{ steps.get_version.outputs.RELEASE_VERSION }} 59 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 60 | 61 | - name: 'Create Release' 62 | uses: ncipollo/release-action@v1 63 | with: 64 | body: ${{steps.build_changelog.outputs.changelog}} 65 | tag: v${{ steps.get_version.outputs.RELEASE_VERSION }} 66 | -------------------------------------------------------------------------------- /src/LangChainJSDotNet.IntegrationTests/mockoon-api.json: -------------------------------------------------------------------------------- 1 | { 2 | "uuid": "edaf93c7-2fa0-41ce-8a4c-42fc65980694", 3 | "lastMigration": 28, 4 | "name": "OpenAI", 5 | "endpointPrefix": "", 6 | "latency": 0, 7 | "port": 3001, 8 | "hostname": "", 9 | "folders": [], 10 | "routes": [ 11 | { 12 | "uuid": "2328e274-cf74-405c-9870-c15f415721e3", 13 | "type": "http", 14 | "documentation": "", 15 | "method": "post", 16 | "endpoint": "v1/completions", 17 | "responses": [ 18 | { 19 | "uuid": "6a278943-1b04-4674-a437-24a9f46fe6aa", 20 | "body": "{\r\n \"warning\": \"This model version is deprecated. Migrate before January 4, 2024 to avoid disruption of service. Learn more https://platform.openai.com/docs/deprecations\",\r\n \"id\": \"cmpl-7sGuJUxqVTcT7b0ZlzLzOPK2e1t76\",\r\n \"object\": \"text_completion\",\r\n \"created\": 1693169059,\r\n \"model\": \"text-davinci-003\",\r\n \"choices\": [{\r\n \"text\": \"2\",\r\n \"index\": 0,\r\n \"logprobs\": null,\r\n \"finish_reason\": \"stop\"\r\n }\r\n ],\r\n \"usage\": {\r\n \"prompt_tokens\": 4,\r\n \"completion_tokens\": 3,\r\n \"total_tokens\": 7\r\n }\r\n}", 21 | "latency": 0, 22 | "statusCode": 200, 23 | "label": "", 24 | "headers": [ 25 | { 26 | "key": "openai-model", 27 | "value": "text-davinci-003" 28 | } 29 | ], 30 | "bodyType": "INLINE", 31 | "filePath": "", 32 | "databucketID": "", 33 | "sendFileAsBody": false, 34 | "rules": [], 35 | "rulesOperator": "OR", 36 | "disableTemplating": false, 37 | "fallbackTo404": false, 38 | "default": true, 39 | "crudKey": "id" 40 | } 41 | ], 42 | "enabled": true, 43 | "responseMode": null 44 | } 45 | ], 46 | "rootChildren": [ 47 | { 48 | "type": "route", 49 | "uuid": "2328e274-cf74-405c-9870-c15f415721e3" 50 | } 51 | ], 52 | "proxyMode": false, 53 | "proxyHost": "", 54 | "proxyRemovePrefix": false, 55 | "tlsOptions": { 56 | "enabled": true, 57 | "type": "CERT", 58 | "pfxPath": "", 59 | "certPath": "", 60 | "keyPath": "", 61 | "caPath": "", 62 | "passphrase": "" 63 | }, 64 | "cors": true, 65 | "headers": [ 66 | { 67 | "key": "Content-Type", 68 | "value": "application/json" 69 | } 70 | ], 71 | "proxyReqHeaders": [ 72 | { 73 | "key": "", 74 | "value": "" 75 | } 76 | ], 77 | "proxyResHeaders": [ 78 | { 79 | "key": "", 80 | "value": "" 81 | } 82 | ], 83 | "data": [] 84 | } -------------------------------------------------------------------------------- /LangChainJSDotNet.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.33424.131 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LangChainJSDotNet", "src\LangChainJSDotNet\LangChainJSDotNet.csproj", "{A3207001-7911-43C5-AA03-F5CEA0715843}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{54529D6B-14B3-40CE-B089-0923D32A8A12}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LangChainJSDemo", "samples\LangChainJSDemo\LangChainJSDemo.csproj", "{74256735-871C-4CBF-AAC8-BE5B8B7FA78E}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{DDED28BB-5F61-4474-B9C4-AC16E6E76200}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LangChainJSDotNet.IntegrationTests", "src\LangChainJSDotNet.IntegrationTests\LangChainJSDotNet.IntegrationTests.csproj", "{4929CA20-496D-4A1F-9E82-F9519EEAE103}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {A3207001-7911-43C5-AA03-F5CEA0715843}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {A3207001-7911-43C5-AA03-F5CEA0715843}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {A3207001-7911-43C5-AA03-F5CEA0715843}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {A3207001-7911-43C5-AA03-F5CEA0715843}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {74256735-871C-4CBF-AAC8-BE5B8B7FA78E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {74256735-871C-4CBF-AAC8-BE5B8B7FA78E}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {74256735-871C-4CBF-AAC8-BE5B8B7FA78E}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {74256735-871C-4CBF-AAC8-BE5B8B7FA78E}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {4929CA20-496D-4A1F-9E82-F9519EEAE103}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {4929CA20-496D-4A1F-9E82-F9519EEAE103}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {4929CA20-496D-4A1F-9E82-F9519EEAE103}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {4929CA20-496D-4A1F-9E82-F9519EEAE103}.Release|Any CPU.Build.0 = Release|Any CPU 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | GlobalSection(NestedProjects) = preSolution 39 | {74256735-871C-4CBF-AAC8-BE5B8B7FA78E} = {54529D6B-14B3-40CE-B089-0923D32A8A12} 40 | {4929CA20-496D-4A1F-9E82-F9519EEAE103} = {DDED28BB-5F61-4474-B9C4-AC16E6E76200} 41 | EndGlobalSection 42 | GlobalSection(ExtensibilityGlobals) = postSolution 43 | SolutionGuid = {0CF6C815-573D-4DFE-B751-3F900CBCAC74} 44 | EndGlobalSection 45 | EndGlobal 46 | -------------------------------------------------------------------------------- /src/LangChainJSDotNet/Http.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Text; 4 | using System.Net.Http; 5 | using System.Net.Http.Headers; 6 | using System.Threading.Tasks; 7 | using System.Collections.Generic; 8 | using Newtonsoft.Json; 9 | 10 | namespace LangChainJSDotNet 11 | { 12 | internal sealed class Http 13 | { 14 | private readonly HttpClient _httpClient; 15 | 16 | internal class HttpResponse 17 | { 18 | public int StatusCode { get; set; } = 0; 19 | 20 | public Dictionary Headers { get; set; } = new Dictionary(); 21 | 22 | public string Content { get; set; } = ""; 23 | } 24 | 25 | public Http(HttpClient httpClient) 26 | { 27 | _httpClient = httpClient; 28 | } 29 | 30 | public async Task SendAsync(string url, string method, IDictionary headers, string body) 31 | { 32 | var response = new HttpResponse(); 33 | string contentType = null; 34 | try 35 | { 36 | HttpRequestMessage request = new HttpRequestMessage(new HttpMethod(method), url); 37 | foreach (var header in headers) 38 | { 39 | if (header.Key.ToLower() != "content-type") 40 | { 41 | if (!request.Headers.TryAddWithoutValidation(header.Key, header.Value.ToString())) 42 | { 43 | throw new Exception($"Couldn't add header {header.Key} with value {header.Value}"); 44 | } 45 | } 46 | else 47 | { 48 | contentType = header.Value.ToString(); 49 | } 50 | } 51 | if (!string.IsNullOrEmpty(body)) 52 | { 53 | request.Content = new StringContent(body, Encoding.UTF8); 54 | if (contentType != null) 55 | { 56 | request.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType); 57 | } 58 | } 59 | 60 | // send request 61 | HttpResponseMessage clientResponse = await _httpClient.SendAsync(request); 62 | 63 | response.StatusCode = (int)clientResponse.StatusCode; 64 | 65 | foreach (var header in clientResponse.Headers.Concat(clientResponse.Content.Headers)) 66 | { 67 | response.Headers[header.Key] = string.Join(",", header.Value); 68 | } 69 | 70 | if (clientResponse.IsSuccessStatusCode) 71 | { 72 | response.Content = await clientResponse.Content.ReadAsStringAsync(); 73 | } 74 | } 75 | catch(Exception ex) 76 | { 77 | Console.WriteLine(ex.ToString()); 78 | } 79 | 80 | //var jsonResponse = JsonSerializer.Serialize(response); 81 | var jsonResponse = JsonConvert.SerializeObject(response); 82 | return jsonResponse; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🦜️🔗🟪 - LangChainJSDotNet 2 | 3 | ⚡ A thin .NET wrapper around the official LangChain.js library⚡ 4 | 5 | Looking for the official JS/TS or Python versions of LangChain? Check out: 6 | 7 | * [LangChain.js](https://github.com/hwchase17/langchainjs) (JS/TS) 8 | * [LangChain](https://github.com/hwchase17/langchain) (Python) 9 | 10 | 11 | ## 🤔 What is this? 12 | 13 | **LangChainJSDotNet** provides a seamless interface for .NET developers to run LangChain based code with minimal adjustments. 14 | 15 | The official JS/TS version tracks the official Python version closely, therefore LangChain code could be easily ported and run in .NET using **LangChainJSDotNet**, potentially exposing all of the latest AI advancements and features from LangChain and its vast ecosystem to .NET developers. 16 | 17 | While integrating Python code in .NET presents challenges, Microsoft's [ClearScript](https://github.com/microsoft/ClearScript) library greatly simplifies the integration process with JavaScript code. Hence, for now, this library focuses exclusively on wrapping the JS version of LangChain. 18 | 19 | ### Features 20 | 21 | - No porting required: Use the official LangChain.js library in .NET. 22 | - The latest LangChain features are readily available. 23 | - Async support: LangChain agents can await .NET async methods. 24 | - Connect from .NET to the new [LangSmith Platform](https://blog.langchain.dev/announcing-langsmith/). 25 | - Debugging capability: Support for debugging LangChain.js code. 26 | 27 | ### Versioning 28 | 29 | This library employs a four-part SemVer-like version scheme. The initial three parts mirror the version of LangChain.js that the library embeds and wraps. The fourth part, always starting at 1, is reserved for incremental bug fixes or non-breaking feature additions. 30 | 31 | For instance, `v0.0.124.1` of this library embeds and wraps `v0.0.124` of LangChain.js. 32 | 33 | While the first part currently matches LangChain.js's major version, it might be repurposed in the future to also indicate major breaking changes specific to this library. 34 | 35 | ### Installation 36 | 37 | Install the [LangChainJSDotNet NuGet package](https://www.nuget.org/packages/LangChainJSDotNet#readme-body-tab). 38 | 39 | You may use the .NET command-line interface: 40 | 41 | dotnet add package LangChainJSDotNet 42 | 43 | This command will download and install LangChainJSDotNet along with all its required dependencies. 44 | 45 | ## 💡 Usage 46 | 47 | ```csharp 48 | using var langchainjs = new LangChainJS(); 49 | 50 | langchainjs.Setup(@" 51 | 52 | const model = new OpenAI({ openAIApiKey: 'API_KEY' }); 53 | 54 | globalThis.run = async () => { 55 | 56 | const result = await model.call('What is a good name for a company that makes colorful socks?'); 57 | 58 | console.log(result.trim()); 59 | } 60 | "); 61 | 62 | await langchainjs.InvokeAsync("run"); 63 | ``` 64 | ```shell 65 | Socktacular! 66 | ``` 67 | 68 | ### Chains 69 | 70 | ```csharp 71 | using var langchainjs = new LangChainJS(); 72 | 73 | langchainjs.SetEnvironmentVariable("OPENAI_API_KEY", "API_KEY"); 74 | 75 | langchainjs.Setup(@" 76 | 77 | const model = new OpenAI({ temperature: 0.9 }); 78 | 79 | const template = new PromptTemplate({ 80 | template: 'What is a good name for a company that makes {product}?', 81 | inputVariables: ['product'], 82 | }); 83 | 84 | chain = new LLMChain({ llm: model, prompt: template }); 85 | 86 | globalThis.run = async (prompt) => { 87 | const res = await chain.call({ product: prompt }); 88 | return res.text.trim(); 89 | } 90 | "); 91 | 92 | string result = await langchainjs.InvokeAsync("run", "colorful socks"); 93 | 94 | Console.WriteLine(result); 95 | ``` 96 | ```shell 97 | BrightSox 98 | ``` 99 | 100 | ### Agents 101 | 102 | See [sample code](./samples/LangChainJSDemo/Program.cs) for an example of a ReAct agent calling dynamic tools. 103 | 104 | ```shell 105 | Agent input: "What is the result if you substruct 8 by foo?"... 106 | The result is 3 107 | ``` 108 | 109 | -------------------------------------------------------------------------------- /src/LangChainJSDotNet/src/consts.js: -------------------------------------------------------------------------------- 1 | export const unsupportedImportPrefixes = [ 2 | "./agents/toolkits/", 3 | "./cache/", 4 | "./callbacks/handlers/", 5 | "./chat_models/", 6 | "./document_loaders/", 7 | "./document_transformers/", 8 | "./embeddings/", 9 | "./experimental/chat_models/anthropic_functions", 10 | "./experimental/hubs/", 11 | "./experimental/multimodal_embeddings/", 12 | "./experimental/prompts/handlebars", 13 | "./experimental/tools/pyinterpreter", 14 | "./graphs/", 15 | "./llms/", 16 | "./memory/", 17 | "./retrievers/", 18 | "./storage/", 19 | "./stores/", 20 | "./tools/", 21 | "./util/convex", 22 | "./vectorstores/", 23 | ] 24 | 25 | export const supportedImports = [ 26 | "./agents", 27 | "./agents/load", 28 | "./agents/toolkits", 29 | "./agents/toolkits/sql", 30 | "./base_language", 31 | "./tools", 32 | "./tools/calculator", 33 | "./tools/sql", 34 | "./chains", 35 | "./chains/load", 36 | "./chains/openai_functions", 37 | "./chains/query_constructor", 38 | "./chains/query_constructor/ir", 39 | "./chains/sql_db", 40 | "./embeddings/base", 41 | "./embeddings/fake", 42 | "./embeddings/openai", 43 | "./embeddings/cohere", 44 | "./llms/load", 45 | "./llms/base", 46 | "./llms/openai", 47 | "./llms/ai21", 48 | "./llms/aleph_alpha", 49 | "./llms/cohere", 50 | "./llms/hf", 51 | "./llms/ollama", 52 | "./llms/replicate", 53 | "./load/serializable", 54 | "./prompts", 55 | "./prompts/load", 56 | "./vectorstores/base", 57 | "./vectorstores/elasticsearch", 58 | "./vectorstores/memory", 59 | "./vectorstores/chroma", 60 | "./vectorstores/hnswlib", 61 | "./vectorstores/faiss", 62 | "./vectorstores/weaviate", 63 | "./vectorstores/lancedb", 64 | "./vectorstores/mongo", 65 | "./vectorstores/mongodb_atlas", 66 | "./vectorstores/pinecone", 67 | "./vectorstores/supabase", 68 | "./vectorstores/prisma", 69 | "./vectorstores/typesense", 70 | "./vectorstores/vectara", 71 | "./document", 72 | "./document_loaders/base", 73 | "./document_loaders/web/cheerio", 74 | "./document_loaders/web/puppeteer", 75 | "./document_loaders/web/playwright", 76 | "./document_loaders/web/college_confidential", 77 | "./document_loaders/web/gitbook", 78 | "./document_loaders/web/hn", 79 | "./document_loaders/web/imsdb", 80 | "./document_loaders/web/figma", 81 | "./document_loaders/web/notiondb", 82 | "./document_loaders/web/serpapi", 83 | "./document_loaders/web/sort_xyz_blockchain", 84 | "./document_loaders/fs/directory", 85 | "./document_loaders/fs/buffer", 86 | "./document_loaders/fs/text", 87 | "./document_loaders/fs/json", 88 | "./document_loaders/fs/pdf", 89 | "./document_loaders/fs/docx", 90 | "./document_loaders/fs/epub", 91 | "./document_loaders/fs/csv", 92 | "./document_loaders/fs/notion", 93 | "./document_loaders/fs/unstructured", 94 | "./document_transformers/html_to_text", 95 | "./document_transformers/openai_functions", 96 | "./chat_models/base", 97 | "./chat_models/openai", 98 | "./chat_models/baiduwenxin", 99 | "./chat_models/ollama", 100 | "./memory", 101 | "./schema", 102 | "./schema/output_parser", 103 | "./schema/query_constructor", 104 | "./schema/retriever", 105 | "./schema/runnable", 106 | "./sql_db", 107 | "./callbacks", 108 | "./output_parsers", 109 | "./output_parsers/expression", 110 | "./retrievers/remote", 111 | "./retrievers/supabase", 112 | "./retrievers/metal", 113 | "./retrievers/databerry", 114 | "./retrievers/contextual_compression", 115 | "./retrievers/document_compressors", 116 | "./retrievers/parent_document", 117 | "./retrievers/time_weighted", 118 | "./retrievers/document_compressors/chain_extract", 119 | "./retrievers/self_query", 120 | "./retrievers/self_query/chroma", 121 | "./retrievers/self_query/functional", 122 | "./retrievers/self_query/pinecone", 123 | "./retrievers/self_query/supabase", 124 | "./retrievers/self_query/weaviate", 125 | "./cache", 126 | "./storage/in_memory", 127 | "./stores/doc/in_memory", 128 | "./stores/file/in_memory", 129 | "./stores/message/in_memory", 130 | "./text_splitter", 131 | "./util/math", 132 | "./experimental/autogpt", 133 | "./experimental/babyagi", 134 | "./experimental/generative_agents", 135 | "./experimental/plan_and_execute", 136 | "./evaluation", 137 | ]; -------------------------------------------------------------------------------- /samples/LangChainJSDemo/Program.cs: -------------------------------------------------------------------------------- 1 | using LangChainJSDotNet; 2 | using Microsoft.Extensions.Configuration; 3 | 4 | namespace LangChainJSDemo 5 | { 6 | public class HostObject 7 | { 8 | public async Task FooAsync(string input) 9 | { 10 | // Simulate an async operation 11 | await Task.Delay(100); 12 | return "5"; 13 | } 14 | } 15 | 16 | internal class Program 17 | { 18 | private static IConfiguration Configuration { get; } = new ConfigurationBuilder() 19 | .AddJsonFile("appsettings.json", optional: false) 20 | .AddUserSecrets() 21 | .Build(); 22 | 23 | static async Task Main(string[] args) 24 | { 25 | //await RunModelAndPrint(); 26 | 27 | //await RunModelAndReturn(); 28 | 29 | //await RunChain(); 30 | 31 | await RunAgent(); 32 | } 33 | 34 | static async Task RunModelAndPrint() 35 | { 36 | using var langchainjs = new LangChainJS(); 37 | 38 | langchainjs.SetEnvironmentVariable("OPENAI_API_KEY", Configuration["OPENAI_API_KEY"]); 39 | 40 | langchainjs.Setup(@" 41 | 42 | const model = new OpenAI(); 43 | 44 | globalThis.run = async () => { 45 | 46 | const result = await model.call('What would be a good company name a company that makes colorful socks?'); 47 | 48 | console.log(result.trim()); 49 | } 50 | "); 51 | 52 | await langchainjs.InvokeAsync("run"); 53 | } 54 | 55 | static async Task RunModelAndReturn() 56 | { 57 | using var langchainjs = new LangChainJS(); 58 | 59 | langchainjs.SetEnvironmentVariable("OPENAI_API_KEY", Configuration["OPENAI_API_KEY"]); 60 | 61 | langchainjs.Setup(@" 62 | 63 | const model = new OpenAI({ temperature: 0.9 }); 64 | 65 | globalThis.run = async () => { 66 | 67 | const res = await model.call('What would be a good company name a company that makes colorful socks?'); 68 | 69 | return res.trim(); 70 | } 71 | "); 72 | 73 | var result = await langchainjs.InvokeAsync("run"); 74 | 75 | Console.WriteLine(result); 76 | } 77 | 78 | static async Task RunChain() 79 | { 80 | using var langchainjs = new LangChainJS(enableDebugging: false); 81 | 82 | langchainjs.SetEnvironmentVariable("OPENAI_API_KEY", Configuration["OPENAI_API_KEY"]); 83 | 84 | langchainjs.Setup(@" 85 | 86 | const model = new OpenAI({ temperature: 0.9 }); 87 | 88 | const template = new PromptTemplate({ 89 | template: 'What is a good name for a company that makes {product}?', 90 | inputVariables: ['product'], 91 | }); 92 | 93 | chain = new LLMChain({ llm: model, prompt: template }); 94 | 95 | globalThis.run = async (prompt) => { 96 | const res = await chain.call({ product: prompt }); 97 | return res.text.trim(); 98 | } 99 | "); 100 | 101 | string result = await langchainjs.InvokeAsync("run", "colorful socks"); 102 | 103 | Console.WriteLine(result); 104 | } 105 | 106 | static async Task RunAgent() 107 | { 108 | using var langchainjs = new LangChainJS(enableDebugging: false); 109 | 110 | langchainjs.SetEnvironmentVariable("OPENAI_API_KEY", Configuration["OPENAI_API_KEY"]); 111 | 112 | langchainjs.AddHostObject("host", new HostObject()); 113 | 114 | langchainjs.Setup(@" 115 | const model = new ChatOpenAI({ temperature: 0 }); 116 | 117 | const tools = [ 118 | new DynamicTool({ 119 | name: ""FOO"", 120 | description: 121 | ""call this to get the value of foo. input should be the name of the user."", 122 | func: async (input) => await host.FooAsync(input), 123 | }), 124 | new DynamicTool({ 125 | name: ""BAR"", 126 | description: 127 | ""call this to get the value of bar. input should be an empty string."", 128 | func: async () => ""baz"", 129 | }), 130 | // Input must be an object with 'high' and 'low' numbers. 131 | new DynamicStructuredTool({ 132 | name: ""number-substructor"", 133 | description: ""substructs one number by the other."", 134 | schema: z.object({ 135 | high: z.number().describe(""The upper number""), 136 | low: z.number().describe(""The lower number""), 137 | }), 138 | func: async ({ high, low }) => (high - low).toString() // Outputs must be strings 139 | }), 140 | ]; 141 | 142 | globalThis.run = async (input) => { 143 | 144 | // zero-shot-react-description 145 | const executor = await initializeAgentExecutorWithOptions(tools, model, { 146 | agentType: ""structured-chat-zero-shot-react-description"", 147 | /* verbose: true */ 148 | }); 149 | 150 | console.log(`Agent input: ""${input}""...`); 151 | 152 | const result = await executor.call({ input }); 153 | 154 | return result.output; 155 | }; 156 | "); 157 | 158 | string result = await langchainjs.InvokeAsync("run", "What is the result if you substruct 8 by foo?"); 159 | 160 | Console.WriteLine(result); 161 | } 162 | } 163 | } -------------------------------------------------------------------------------- /src/LangChainJSDotNet/LangChainJS.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.ClearScript.JavaScript; 2 | using Microsoft.ClearScript.V8; 3 | using Microsoft.ClearScript; 4 | using System; 5 | using System.IO; 6 | using System.Reflection; 7 | using System.Threading; 8 | using System.Threading.Tasks; 9 | using System.Net.Http; 10 | 11 | namespace LangChainJSDotNet 12 | { 13 | public class LangChainJS : IDisposable 14 | { 15 | protected readonly IScriptEngine _engine; 16 | 17 | protected readonly HttpClient _httpClient; 18 | 19 | public LangChainJS(bool enableDebugging = false, HttpClient httpClient = null) 20 | { 21 | _httpClient = httpClient ?? new HttpClient(); 22 | 23 | V8ScriptEngineFlags flags = V8ScriptEngineFlags.EnableTaskPromiseConversion; 24 | if (enableDebugging) 25 | { 26 | flags |= V8ScriptEngineFlags.EnableRemoteDebugging 27 | | V8ScriptEngineFlags.EnableDebugging 28 | | V8ScriptEngineFlags.AwaitDebuggerAndPauseOnStart; 29 | } 30 | _engine = new V8ScriptEngine(flags); 31 | 32 | // Enable file loading of any library type 33 | _engine.DocumentSettings.AccessFlags = DocumentAccessFlags.EnableFileLoading | DocumentAccessFlags.AllowCategoryMismatch; 34 | 35 | InitJSEnvironment(); 36 | } 37 | 38 | public void Dispose() 39 | { 40 | if (_engine != null) 41 | { 42 | _engine.Dispose(); 43 | } 44 | GC.SuppressFinalize(this); 45 | } 46 | 47 | public void Setup(string code) 48 | { 49 | _engine.Execute(code); 50 | } 51 | 52 | public void SetEnvironmentVariable(string name, string value) 53 | { 54 | _engine.Script.process.env[name] = value; 55 | } 56 | 57 | public void AddHostObject(string itemName, object target) 58 | { 59 | _engine.AddHostObject(itemName, target); 60 | } 61 | 62 | public void AddHostType(Type type) 63 | { 64 | _engine.AddHostType(type); 65 | } 66 | 67 | public T Invoke(string funcName, params object[] args) 68 | { 69 | var result = _engine.Invoke(funcName, args); 70 | 71 | // Convert the result to the desired type and return it 72 | return (T)Convert.ChangeType(result, typeof(T)); 73 | } 74 | 75 | public void Invoke(string funcName, params object[] args) 76 | { 77 | _engine.Invoke(funcName, args); 78 | } 79 | 80 | public async Task InvokeAsync(string funcName, params object[] args) 81 | { 82 | var result = await _engine.Invoke(funcName, args).ToTask(); 83 | 84 | // Convert the result to the desired type and return it 85 | return (T)Convert.ChangeType(result, typeof(T)); 86 | } 87 | 88 | public async Task InvokeAsync(string funcName, params object[] args) 89 | { 90 | await _engine.Invoke(funcName, args).ToTask(); 91 | } 92 | 93 | private void InitJSEnvironment() 94 | { 95 | // implement console 96 | _engine.AddHostType(typeof(Console)); 97 | _engine.Execute(@" 98 | console = { 99 | log: value => Console.WriteLine(value), 100 | warn: value => Console.WriteLine('WARNING: {0}', value), 101 | error: value => Console.WriteLine('ERROR: {0}', value) 102 | }; 103 | "); 104 | 105 | // implement setTimeout 106 | Action setTimeout = (func, delay) => { 107 | var timer = new Timer(_ => func.Invoke(false)); 108 | timer.Change(delay, Timeout.Infinite); 109 | }; 110 | _engine.Script._setTimeout = setTimeout; 111 | _engine.Execute(@" 112 | function setTimeout(func, delay) { 113 | let args = Array.prototype.slice.call(arguments, 2); 114 | _setTimeout(func.bind(undefined, ...args), delay || 0); 115 | } 116 | "); 117 | 118 | // Implement self 119 | _engine.Execute(@"globalThis.self = globalThis"); 120 | 121 | // Implement crypto API (getRandomValues) 122 | _engine.AddHostType("HostCrypto", HostItemFlags.PrivateAccess, typeof(Crypto)); 123 | _engine.Execute(@" 124 | crypto = { 125 | getRandomValues: array => HostCrypto.GetRandomValues(array) 126 | }; 127 | "); 128 | 129 | // Implement timers API 130 | _engine.AddHostObject("hostTimer", HostItemFlags.PrivateAccess, new HostTimer()); 131 | _engine.Execute(@" 132 | let queue = [], nextId = 0; 133 | const maxId = 1000000000000, getNextId = () => nextId = (nextId % maxId) + 1; 134 | const add = entry => { 135 | const index = queue.findIndex(element => element.due > entry.due); 136 | index >= 0 ? queue.splice(index, 0, entry) : queue.push(entry); 137 | } 138 | function set(periodic, func, delay) { 139 | const id = getNextId(), now = Date.now(), args = [...arguments].slice(3); 140 | add({ id, periodic, func: () => func(...args), delay, due: now + delay }); 141 | hostTimer.Schedule(queue[0].due - now); 142 | return id; 143 | }; 144 | function clear(id) { 145 | queue = queue.filter(entry => entry.id != id); 146 | hostTimer.Schedule(queue.length > 0 ? queue[0].due - Date.now() : -1); 147 | }; 148 | globalThis.setTimeout = set.bind(undefined, false); 149 | globalThis.setInterval = set.bind(undefined, true); 150 | globalThis.clearTimeout = globalThis.clearInterval = clear.bind(); 151 | hostTimer.Initialize(() => { 152 | const now = Date.now(); 153 | while ((queue.length > 0) && (now >= queue[0].due)) { 154 | const entry = queue.shift(); 155 | if (entry.periodic) add({ ...entry, due: now + entry.delay }); 156 | entry.func(); 157 | } 158 | return queue.length > 0 ? queue[0].due - now : -1; 159 | }); 160 | "); 161 | 162 | // Simulate process API globally for setting environment variables 163 | _engine.Execute(@" 164 | process = { 165 | env: {} 166 | }; 167 | "); 168 | 169 | // Required to implement XMLHttpRequest 170 | _engine.AddHostObject("HostHttp", HostItemFlags.PrivateAccess, new Http(_httpClient)); 171 | 172 | // Implement WHATWG URL Standard: 173 | _engine.Execute("url.js", LoadScript("LangChainJSDotNet.dist.url.js")); 174 | 175 | // Implement everything else: 176 | _engine.Execute("bundle.js", LoadScript("LangChainJSDotNet.dist.bundle.js")); 177 | } 178 | 179 | private string LoadScript(string name) 180 | { 181 | // Get the current assembly 182 | var assembly = Assembly.GetExecutingAssembly(); 183 | 184 | // Get the stream to the embedded resource 185 | using (var stream = assembly.GetManifestResourceStream(name)) 186 | { 187 | // Read the stream and convert it to a string 188 | using (var reader = new StreamReader(stream)) 189 | { 190 | var script = reader.ReadToEnd(); 191 | 192 | return script; 193 | } 194 | } 195 | } 196 | } 197 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # Tye 66 | .tye/ 67 | 68 | # ASP.NET Scaffolding 69 | ScaffoldingReadMe.txt 70 | 71 | # StyleCop 72 | StyleCopReport.xml 73 | 74 | # Files built by Visual Studio 75 | *_i.c 76 | *_p.c 77 | *_h.h 78 | *.ilk 79 | *.meta 80 | *.obj 81 | *.iobj 82 | *.pch 83 | *.pdb 84 | *.ipdb 85 | *.pgc 86 | *.pgd 87 | *.rsp 88 | *.sbr 89 | *.tlb 90 | *.tli 91 | *.tlh 92 | *.tmp 93 | *.tmp_proj 94 | *_wpftmp.csproj 95 | *.log 96 | *.tlog 97 | *.vspscc 98 | *.vssscc 99 | .builds 100 | *.pidb 101 | *.svclog 102 | *.scc 103 | 104 | # Chutzpah Test files 105 | _Chutzpah* 106 | 107 | # Visual C++ cache files 108 | ipch/ 109 | *.aps 110 | *.ncb 111 | *.opendb 112 | *.opensdf 113 | *.sdf 114 | *.cachefile 115 | *.VC.db 116 | *.VC.VC.opendb 117 | 118 | # Visual Studio profiler 119 | *.psess 120 | *.vsp 121 | *.vspx 122 | *.sap 123 | 124 | # Visual Studio Trace Files 125 | *.e2e 126 | 127 | # TFS 2012 Local Workspace 128 | $tf/ 129 | 130 | # Guidance Automation Toolkit 131 | *.gpState 132 | 133 | # ReSharper is a .NET coding add-in 134 | _ReSharper*/ 135 | *.[Rr]e[Ss]harper 136 | *.DotSettings.user 137 | 138 | # TeamCity is a build add-in 139 | _TeamCity* 140 | 141 | # DotCover is a Code Coverage Tool 142 | *.dotCover 143 | 144 | # AxoCover is a Code Coverage Tool 145 | .axoCover/* 146 | !.axoCover/settings.json 147 | 148 | # Coverlet is a free, cross platform Code Coverage Tool 149 | coverage*.json 150 | coverage*.xml 151 | coverage*.info 152 | 153 | # Visual Studio code coverage results 154 | *.coverage 155 | *.coveragexml 156 | 157 | # NCrunch 158 | _NCrunch_* 159 | .*crunch*.local.xml 160 | nCrunchTemp_* 161 | 162 | # MightyMoose 163 | *.mm.* 164 | AutoTest.Net/ 165 | 166 | # Web workbench (sass) 167 | .sass-cache/ 168 | 169 | # Installshield output folder 170 | [Ee]xpress/ 171 | 172 | # DocProject is a documentation generator add-in 173 | DocProject/buildhelp/ 174 | DocProject/Help/*.HxT 175 | DocProject/Help/*.HxC 176 | DocProject/Help/*.hhc 177 | DocProject/Help/*.hhk 178 | DocProject/Help/*.hhp 179 | DocProject/Help/Html2 180 | DocProject/Help/html 181 | 182 | # Click-Once directory 183 | publish/ 184 | 185 | # Publish Web Output 186 | *.[Pp]ublish.xml 187 | *.azurePubxml 188 | # Note: Comment the next line if you want to checkin your web deploy settings, 189 | # but database connection strings (with potential passwords) will be unencrypted 190 | *.pubxml 191 | *.publishproj 192 | 193 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 194 | # checkin your Azure Web App publish settings, but sensitive information contained 195 | # in these scripts will be unencrypted 196 | PublishScripts/ 197 | 198 | # NuGet Packages 199 | *.nupkg 200 | # NuGet Symbol Packages 201 | *.snupkg 202 | # The packages folder can be ignored because of Package Restore 203 | **/[Pp]ackages/* 204 | # except build/, which is used as an MSBuild target. 205 | !**/[Pp]ackages/build/ 206 | # Uncomment if necessary however generally it will be regenerated when needed 207 | #!**/[Pp]ackages/repositories.config 208 | # NuGet v3's project.json files produces more ignorable files 209 | *.nuget.props 210 | *.nuget.targets 211 | 212 | # Microsoft Azure Build Output 213 | csx/ 214 | *.build.csdef 215 | 216 | # Microsoft Azure Emulator 217 | ecf/ 218 | rcf/ 219 | 220 | # Windows Store app package directories and files 221 | AppPackages/ 222 | BundleArtifacts/ 223 | Package.StoreAssociation.xml 224 | _pkginfo.txt 225 | *.appx 226 | *.appxbundle 227 | *.appxupload 228 | 229 | # Visual Studio cache files 230 | # files ending in .cache can be ignored 231 | *.[Cc]ache 232 | # but keep track of directories ending in .cache 233 | !?*.[Cc]ache/ 234 | 235 | # Others 236 | ClientBin/ 237 | ~$* 238 | *~ 239 | *.dbmdl 240 | *.dbproj.schemaview 241 | *.jfm 242 | *.pfx 243 | *.publishsettings 244 | orleans.codegen.cs 245 | 246 | # Including strong name files can present a security risk 247 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 248 | #*.snk 249 | 250 | # Since there are multiple workflows, uncomment next line to ignore bower_components 251 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 252 | #bower_components/ 253 | 254 | # RIA/Silverlight projects 255 | Generated_Code/ 256 | 257 | # Backup & report files from converting an old project file 258 | # to a newer Visual Studio version. Backup files are not needed, 259 | # because we have git ;-) 260 | _UpgradeReport_Files/ 261 | Backup*/ 262 | UpgradeLog*.XML 263 | UpgradeLog*.htm 264 | ServiceFabricBackup/ 265 | *.rptproj.bak 266 | 267 | # SQL Server files 268 | *.mdf 269 | *.ldf 270 | *.ndf 271 | 272 | # Business Intelligence projects 273 | *.rdl.data 274 | *.bim.layout 275 | *.bim_*.settings 276 | *.rptproj.rsuser 277 | *- [Bb]ackup.rdl 278 | *- [Bb]ackup ([0-9]).rdl 279 | *- [Bb]ackup ([0-9][0-9]).rdl 280 | 281 | # Microsoft Fakes 282 | FakesAssemblies/ 283 | 284 | # GhostDoc plugin setting file 285 | *.GhostDoc.xml 286 | 287 | # Node.js Tools for Visual Studio 288 | .ntvs_analysis.dat 289 | node_modules/ 290 | 291 | # Visual Studio 6 build log 292 | *.plg 293 | 294 | # Visual Studio 6 workspace options file 295 | *.opt 296 | 297 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 298 | *.vbw 299 | 300 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 301 | *.vbp 302 | 303 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 304 | *.dsw 305 | *.dsp 306 | 307 | # Visual Studio 6 technical files 308 | *.ncb 309 | *.aps 310 | 311 | # Visual Studio LightSwitch build output 312 | **/*.HTMLClient/GeneratedArtifacts 313 | **/*.DesktopClient/GeneratedArtifacts 314 | **/*.DesktopClient/ModelManifest.xml 315 | **/*.Server/GeneratedArtifacts 316 | **/*.Server/ModelManifest.xml 317 | _Pvt_Extensions 318 | 319 | # Paket dependency manager 320 | .paket/paket.exe 321 | paket-files/ 322 | 323 | # FAKE - F# Make 324 | .fake/ 325 | 326 | # CodeRush personal settings 327 | .cr/personal 328 | 329 | # Python Tools for Visual Studio (PTVS) 330 | __pycache__/ 331 | *.pyc 332 | 333 | # Cake - Uncomment if you are using it 334 | # tools/** 335 | # !tools/packages.config 336 | 337 | # Tabs Studio 338 | *.tss 339 | 340 | # Telerik's JustMock configuration file 341 | *.jmconfig 342 | 343 | # BizTalk build output 344 | *.btp.cs 345 | *.btm.cs 346 | *.odx.cs 347 | *.xsd.cs 348 | 349 | # OpenCover UI analysis results 350 | OpenCover/ 351 | 352 | # Azure Stream Analytics local run output 353 | ASALocalRun/ 354 | 355 | # MSBuild Binary and Structured Log 356 | *.binlog 357 | 358 | # NVidia Nsight GPU debugger configuration file 359 | *.nvuser 360 | 361 | # MFractors (Xamarin productivity tool) working folder 362 | .mfractor/ 363 | 364 | # Local History for Visual Studio 365 | .localhistory/ 366 | 367 | # Visual Studio History (VSHistory) files 368 | .vshistory/ 369 | 370 | # BeatPulse healthcheck temp database 371 | healthchecksdb 372 | 373 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 374 | MigrationBackup/ 375 | 376 | # Ionide (cross platform F# VS Code tools) working folder 377 | .ionide/ 378 | 379 | # Fody - auto-generated XML schema 380 | FodyWeavers.xsd 381 | 382 | # VS Code files for those working on multiple tools 383 | .vscode/* 384 | !.vscode/settings.json 385 | !.vscode/tasks.json 386 | !.vscode/launch.json 387 | !.vscode/extensions.json 388 | *.code-workspace 389 | 390 | # Local History for Visual Studio Code 391 | .history/ 392 | 393 | # Windows Installer files from build outputs 394 | *.cab 395 | *.msi 396 | *.msix 397 | *.msm 398 | *.msp 399 | 400 | # JetBrains Rider 401 | *.sln.iml 402 | 403 | ## 404 | ## Visual studio for Mac 405 | ## 406 | 407 | 408 | # globs 409 | Makefile.in 410 | *.userprefs 411 | *.usertasks 412 | config.make 413 | config.status 414 | aclocal.m4 415 | install-sh 416 | autom4te.cache/ 417 | *.tar.gz 418 | tarballs/ 419 | test-results/ 420 | 421 | # Mac bundle stuff 422 | *.dmg 423 | *.app 424 | 425 | # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore 426 | # General 427 | .DS_Store 428 | .AppleDouble 429 | .LSOverride 430 | 431 | # Icon must end with two \r 432 | Icon 433 | 434 | 435 | # Thumbnails 436 | ._* 437 | 438 | # Files that might appear in the root of a volume 439 | .DocumentRevisions-V100 440 | .fseventsd 441 | .Spotlight-V100 442 | .TemporaryItems 443 | .Trashes 444 | .VolumeIcon.icns 445 | .com.apple.timemachine.donotpresent 446 | 447 | # Directories potentially created on remote AFP share 448 | .AppleDB 449 | .AppleDesktop 450 | Network Trash Folder 451 | Temporary Items 452 | .apdisk 453 | 454 | # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore 455 | # Windows thumbnail cache files 456 | Thumbs.db 457 | ehthumbs.db 458 | ehthumbs_vista.db 459 | 460 | # Dump file 461 | *.stackdump 462 | 463 | # Folder config file 464 | [Dd]esktop.ini 465 | 466 | # Recycle Bin used on file shares 467 | $RECYCLE.BIN/ 468 | 469 | # Windows Installer files 470 | *.cab 471 | *.msi 472 | *.msix 473 | *.msm 474 | *.msp 475 | 476 | # Windows shortcuts 477 | *.lnk 478 | -------------------------------------------------------------------------------- /src/LangChainJSDotNet/dist/url.js: -------------------------------------------------------------------------------- 1 | /* Inlined from https://github.com/kuoruan/v8go-polyfills 2 | /* 3 | * Copyright (c) 2021 Xingwang Liao 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in all 13 | * copies or substantial portions of the Software. 14 | */ 15 | (() => { var t = { 3916: t => { t.exports = function (t) { if ("function" != typeof t) throw TypeError(String(t) + " is not a function"); return t } }, 1851: (t, e, r) => { var n = r(941); t.exports = function (t) { if (!n(t) && null !== t) throw TypeError("Can't set " + String(t) + " as a prototype"); return t } }, 8479: t => { t.exports = function () { } }, 5743: t => { t.exports = function (t, e, r) { if (!(t instanceof e)) throw TypeError("Incorrect " + (r ? r + " " : "") + "invocation"); return t } }, 6059: (t, e, r) => { var n = r(941); t.exports = function (t) { if (!n(t)) throw TypeError(String(t) + " is not an object"); return t } }, 1354: (t, e, r) => { "use strict"; var n = r(6843), o = r(9678), a = r(5196), i = r(6782), u = r(3057), s = r(5449), c = r(2902); t.exports = function (t) { var e, r, f, l, p, h, v = o(t), g = "function" == typeof this ? this : Array, y = arguments.length, d = y > 1 ? arguments[1] : void 0, m = void 0 !== d, b = c(v), w = 0; if (m && (d = n(d, y > 2 ? arguments[2] : void 0, 2)), null == b || g == Array && i(b)) for (r = new g(e = u(v.length)); e > w; w++)h = m ? d(v[w], w) : v[w], s(r, w, h); else for (p = (l = b.call(v)).next, r = new g; !(f = p.call(l)).done; w++)h = m ? a(l, d, [f.value, w], !0) : f.value, s(r, w, h); return r.length = w, r } }, 1692: (t, e, r) => { var n = r(4529), o = r(3057), a = r(9413), i = function (t) { return function (e, r, i) { var u, s = n(e), c = o(s.length), f = a(i, c); if (t && r != r) { for (; c > f;)if ((u = s[f++]) != u) return !0 } else for (; c > f; f++)if ((t || f in s) && s[f] === r) return t || f || 0; return !t && -1 } }; t.exports = { includes: i(!0), indexOf: i(!1) } }, 5196: (t, e, r) => { var n = r(6059), o = r(7609); t.exports = function (t, e, r, a) { try { return a ? e(n(r)[0], r[1]) : e(r) } catch (e) { throw o(t), e } } }, 2532: t => { var e = {}.toString; t.exports = function (t) { return e.call(t).slice(8, -1) } }, 9697: (t, e, r) => { var n = r(2885), o = r(2532), a = r(9813)("toStringTag"), i = "Arguments" == o(function () { return arguments }()); t.exports = n ? o : function (t) { var e, r, n; return void 0 === t ? "Undefined" : null === t ? "Null" : "string" == typeof (r = function (t, e) { try { return t[e] } catch (t) { } }(e = Object(t), a)) ? r : i ? o(e) : "Object" == (n = o(e)) && "function" == typeof e.callee ? "Arguments" : n } }, 4160: (t, e, r) => { var n = r(5981); t.exports = !n((function () { function t() { } return t.prototype.constructor = null, Object.getPrototypeOf(new t) !== t.prototype })) }, 1046: (t, e, r) => { "use strict"; var n = r(5143).IteratorPrototype, o = r(9290), a = r(1887), i = r(904), u = r(2077), s = function () { return this }; t.exports = function (t, e, r) { var c = e + " Iterator"; return t.prototype = o(n, { next: a(1, r) }), i(t, c, !1, !0), u[c] = s, t } }, 2029: (t, e, r) => { var n = r(5746), o = r(5988), a = r(1887); t.exports = n ? function (t, e, r) { return o.f(t, e, a(1, r)) } : function (t, e, r) { return t[e] = r, t } }, 1887: t => { t.exports = function (t, e) { return { enumerable: !(1 & t), configurable: !(2 & t), writable: !(4 & t), value: e } } }, 5449: (t, e, r) => { "use strict"; var n = r(6935), o = r(5988), a = r(1887); t.exports = function (t, e, r) { var i = n(e); i in t ? o.f(t, i, a(0, r)) : t[i] = r } }, 7771: (t, e, r) => { "use strict"; var n = r(6887), o = r(1046), a = r(249), i = r(8929), u = r(904), s = r(2029), c = r(9754), f = r(9813), l = r(2529), p = r(2077), h = r(5143), v = h.IteratorPrototype, g = h.BUGGY_SAFARI_ITERATORS, y = f("iterator"), d = "keys", m = "values", b = "entries", w = function () { return this }; t.exports = function (t, e, r, f, h, x, S) { o(r, e, f); var j, k, A, R = function (t) { if (t === h && E) return E; if (!g && t in U) return U[t]; switch (t) { case d: case m: case b: return function () { return new r(this, t) } }return function () { return new r(this) } }, O = e + " Iterator", L = !1, U = t.prototype, P = U[y] || U["@@iterator"] || h && U[h], E = !g && P || R(h), I = "Array" == e && U.entries || P; if (I && (j = a(I.call(new t)), v !== Object.prototype && j.next && (l || a(j) === v || (i ? i(j, v) : "function" != typeof j[y] && s(j, y, w)), u(j, O, !0, !0), l && (p[O] = w))), h == m && P && P.name !== m && (L = !0, E = function () { return P.call(this) }), l && !S || U[y] === E || s(U, y, E), p[e] = E, h) if (k = { values: R(m), keys: x ? E : R(d), entries: R(b) }, S) for (A in k) (g || L || !(A in U)) && c(U, A, k[A]); else n({ target: e, proto: !0, forced: g || L }, k); return k } }, 5746: (t, e, r) => { var n = r(5981); t.exports = !n((function () { return 7 != Object.defineProperty({}, 1, { get: function () { return 7 } })[1] })) }, 1333: (t, e, r) => { var n = r(1899), o = r(941), a = n.document, i = o(a) && o(a.createElement); t.exports = function (t) { return i ? a.createElement(t) : {} } }, 2861: (t, e, r) => { var n = r(626); t.exports = n("navigator", "userAgent") || "" }, 3385: (t, e, r) => { var n, o, a = r(1899), i = r(2861), u = a.process, s = u && u.versions, c = s && s.v8; c ? o = (n = c.split("."))[0] < 4 ? 1 : n[0] + n[1] : i && (!(n = i.match(/Edge\/(\d+)/)) || n[1] >= 74) && (n = i.match(/Chrome\/(\d+)/)) && (o = n[1]), t.exports = o && +o }, 6759: t => { t.exports = ["constructor", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "toLocaleString", "toString", "valueOf"] }, 6887: (t, e, r) => { "use strict"; var n = r(1899), o = r(9677).f, a = r(7252), i = r(4058), u = r(6843), s = r(2029), c = r(7457), f = function (t) { var e = function (e, r, n) { if (this instanceof t) { switch (arguments.length) { case 0: return new t; case 1: return new t(e); case 2: return new t(e, r) }return new t(e, r, n) } return t.apply(this, arguments) }; return e.prototype = t.prototype, e }; t.exports = function (t, e) { var r, l, p, h, v, g, y, d, m = t.target, b = t.global, w = t.stat, x = t.proto, S = b ? n : w ? n[m] : (n[m] || {}).prototype, j = b ? i : i[m] || (i[m] = {}), k = j.prototype; for (p in e) r = !a(b ? p : m + (w ? "." : "#") + p, t.forced) && S && c(S, p), v = j[p], r && (g = t.noTargetGet ? (d = o(S, p)) && d.value : S[p]), h = r && g ? g : e[p], r && typeof v == typeof h || (y = t.bind && r ? u(h, n) : t.wrap && r ? f(h) : x && "function" == typeof h ? u(Function.call, h) : h, (t.sham || h && h.sham || v && v.sham) && s(y, "sham", !0), j[p] = y, x && (c(i, l = m + "Prototype") || s(i, l, {}), i[l][p] = h, t.real && k && !k[p] && s(k, p, h))) } }, 5981: t => { t.exports = function (t) { try { return !!t() } catch (t) { return !0 } } }, 6843: (t, e, r) => { var n = r(3916); t.exports = function (t, e, r) { if (n(t), void 0 === e) return t; switch (r) { case 0: return function () { return t.call(e) }; case 1: return function (r) { return t.call(e, r) }; case 2: return function (r, n) { return t.call(e, r, n) }; case 3: return function (r, n, o) { return t.call(e, r, n, o) } }return function () { return t.apply(e, arguments) } } }, 626: (t, e, r) => { var n = r(4058), o = r(1899), a = function (t) { return "function" == typeof t ? t : void 0 }; t.exports = function (t, e) { return arguments.length < 2 ? a(n[t]) || a(o[t]) : n[t] && n[t][e] || o[t] && o[t][e] } }, 2902: (t, e, r) => { var n = r(9697), o = r(2077), a = r(9813)("iterator"); t.exports = function (t) { if (null != t) return t[a] || t["@@iterator"] || o[n(t)] } }, 3476: (t, e, r) => { var n = r(6059), o = r(2902); t.exports = function (t) { var e = o(t); if ("function" != typeof e) throw TypeError(String(t) + " is not iterable"); return n(e.call(t)) } }, 1899: (t, e, r) => { var n = function (t) { return t && t.Math == Math && t }; t.exports = n("object" == typeof globalThis && globalThis) || n("object" == typeof window && window) || n("object" == typeof self && self) || n("object" == typeof r.g && r.g) || function () { return this }() || Function("return this")() }, 7457: (t, e, r) => { var n = r(9678), o = {}.hasOwnProperty; t.exports = function (t, e) { return o.call(n(t), e) } }, 7748: t => { t.exports = {} }, 5463: (t, e, r) => { var n = r(626); t.exports = n("document", "documentElement") }, 2840: (t, e, r) => { var n = r(5746), o = r(5981), a = r(1333); t.exports = !n && !o((function () { return 7 != Object.defineProperty(a("div"), "a", { get: function () { return 7 } }).a })) }, 7026: (t, e, r) => { var n = r(5981), o = r(2532), a = "".split; t.exports = n((function () { return !Object("z").propertyIsEnumerable(0) })) ? function (t) { return "String" == o(t) ? a.call(t, "") : Object(t) } : Object }, 1302: (t, e, r) => { var n = r(3030), o = Function.toString; "function" != typeof n.inspectSource && (n.inspectSource = function (t) { return o.call(t) }), t.exports = n.inspectSource }, 5402: (t, e, r) => { var n, o, a, i = r(8019), u = r(1899), s = r(941), c = r(2029), f = r(7457), l = r(3030), p = r(4262), h = r(7748), v = "Object already initialized", g = u.WeakMap; if (i || l.state) { var y = l.state || (l.state = new g), d = y.get, m = y.has, b = y.set; n = function (t, e) { if (m.call(y, t)) throw new TypeError(v); return e.facade = t, b.call(y, t, e), e }, o = function (t) { return d.call(y, t) || {} }, a = function (t) { return m.call(y, t) } } else { var w = p("state"); h[w] = !0, n = function (t, e) { if (f(t, w)) throw new TypeError(v); return e.facade = t, c(t, w, e), e }, o = function (t) { return f(t, w) ? t[w] : {} }, a = function (t) { return f(t, w) } } t.exports = { set: n, get: o, has: a, enforce: function (t) { return a(t) ? o(t) : n(t, {}) }, getterFor: function (t) { return function (e) { var r; if (!s(e) || (r = o(e)).type !== t) throw TypeError("Incompatible receiver, " + t + " required"); return r } } } }, 6782: (t, e, r) => { var n = r(9813), o = r(2077), a = n("iterator"), i = Array.prototype; t.exports = function (t) { return void 0 !== t && (o.Array === t || i[a] === t) } }, 7252: (t, e, r) => { var n = r(5981), o = /#|\.prototype\./, a = function (t, e) { var r = u[i(t)]; return r == c || r != s && ("function" == typeof e ? n(e) : !!e) }, i = a.normalize = function (t) { return String(t).replace(o, ".").toLowerCase() }, u = a.data = {}, s = a.NATIVE = "N", c = a.POLYFILL = "P"; t.exports = a }, 941: t => { t.exports = function (t) { return "object" == typeof t ? null !== t : "function" == typeof t } }, 2529: t => { t.exports = !0 }, 7609: (t, e, r) => { var n = r(6059); t.exports = function (t) { var e = t.return; if (void 0 !== e) return n(e.call(t)).value } }, 5143: (t, e, r) => { "use strict"; var n, o, a, i = r(5981), u = r(249), s = r(2029), c = r(7457), f = r(9813), l = r(2529), p = f("iterator"), h = !1;[].keys && ("next" in (a = [].keys()) ? (o = u(u(a))) !== Object.prototype && (n = o) : h = !0); var v = null == n || i((function () { var t = {}; return n[p].call(t) !== t })); v && (n = {}), l && !v || c(n, p) || s(n, p, (function () { return this })), t.exports = { IteratorPrototype: n, BUGGY_SAFARI_ITERATORS: h } }, 2077: t => { t.exports = {} }, 2497: (t, e, r) => { var n = r(3385), o = r(5981); t.exports = !!Object.getOwnPropertySymbols && !o((function () { return !String(Symbol()) || !Symbol.sham && n && n < 41 })) }, 8468: (t, e, r) => { var n = r(5981), o = r(9813), a = r(2529), i = o("iterator"); t.exports = !n((function () { var t = new URL("b?a=1&b=2&c=3", "http://a"), e = t.searchParams, r = ""; return t.pathname = "c%20d", e.forEach((function (t, n) { e.delete("b"), r += n + t })), a && !t.toJSON || !e.sort || "http://a/c%20d?a=1&c=3" !== t.href || "3" !== e.get("c") || "a=1" !== String(new URLSearchParams("?a=1")) || !e[i] || "a" !== new URL("https://a@b").username || "b" !== new URLSearchParams(new URLSearchParams("a=b")).get("a") || "xn--e1aybc" !== new URL("http://тест").host || "#%D0%B1" !== new URL("http://a#б").hash || "a1c3" !== r || "x" !== new URL("http://x", void 0).host })) }, 8019: (t, e, r) => { var n = r(1899), o = r(1302), a = n.WeakMap; t.exports = "function" == typeof a && /native code/.test(o(a)) }, 4420: (t, e, r) => { "use strict"; var n = r(5746), o = r(5981), a = r(4771), i = r(7857), u = r(6760), s = r(9678), c = r(7026), f = Object.assign, l = Object.defineProperty; t.exports = !f || o((function () { if (n && 1 !== f({ b: 1 }, f(l({}, "a", { enumerable: !0, get: function () { l(this, "b", { value: 3, enumerable: !1 }) } }), { b: 2 })).b) return !0; var t = {}, e = {}, r = Symbol(), o = "abcdefghijklmnopqrst"; return t[r] = 7, o.split("").forEach((function (t) { e[t] = t })), 7 != f({}, t)[r] || a(f({}, e)).join("") != o })) ? function (t, e) { for (var r = s(t), o = arguments.length, f = 1, l = i.f, p = u.f; o > f;)for (var h, v = c(arguments[f++]), g = l ? a(v).concat(l(v)) : a(v), y = g.length, d = 0; y > d;)h = g[d++], n && !p.call(v, h) || (r[h] = v[h]); return r } : f }, 9290: (t, e, r) => { var n, o = r(6059), a = r(9938), i = r(6759), u = r(7748), s = r(5463), c = r(1333), f = r(4262)("IE_PROTO"), l = function () { }, p = function (t) { return "