Migrate to LangChainJS (#17)

* Migrate to LangChainJS

* Add wasmPlugin to solve tiktoken wasm loading issue in esbuild

* Wire in default system prompt for langchain params

* Implement stop generation for langchain

* Remove the streaming mode toggle in settings
This commit is contained in:
Logan Yang 2023-05-16 14:52:45 -07:00 committed by GitHub
parent b94cd90d3f
commit 7eafa110eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 603 additions and 38 deletions

View file

@ -2,6 +2,7 @@ import builtins from "builtin-modules";
import esbuild from "esbuild";
import svgPlugin from "esbuild-plugin-svg";
import process from "process";
import wasmPlugin from "./wasmPlugin.mjs";
const banner =
`/*
@ -39,7 +40,7 @@ const context = await esbuild.context({
sourcemap: prod ? false : "inline",
treeShaking: true,
outfile: "main.js",
plugins: [svgPlugin()],
plugins: [svgPlugin(), wasmPlugin],
});
if (prod) {

451
package-lock.json generated
View file

@ -13,6 +13,7 @@
"axios": "^1.3.4",
"esbuild-plugin-svg": "^0.1.0",
"eventsource-parser": "^1.0.0",
"langchain": "^0.0.75",
"next-i18next": "^13.2.2",
"prop-types": "^15.8.1",
"react": "^18.2.0",
@ -61,6 +62,15 @@
"node": ">=6.0.0"
}
},
"node_modules/@anthropic-ai/sdk": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.4.3.tgz",
"integrity": "sha512-SZrlXvjUUYT9rPmSzlTtmVk1OjVNpkCzILRluhiYwNcxXfQyvPJDi0CI6PyymygcgtqEF5EVqhKmC/PtPsNEIw==",
"dependencies": {
"@fortaine/fetch-event-source": "^3.0.6",
"cross-fetch": "^3.1.5"
}
},
"node_modules/@babel/code-frame": {
"version": "7.21.4",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz",
@ -677,6 +687,11 @@
"w3c-keyname": "^2.2.4"
}
},
"node_modules/@dqbd/tiktoken": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/@dqbd/tiktoken/-/tiktoken-1.0.7.tgz",
"integrity": "sha512-bhR5k5W+8GLzysjk8zTMVygQZsgvf7W1F0IlL4ZQ5ugjo5rCyiwGM5d8DYriXspytfu98tv59niang3/T+FoDw=="
},
"node_modules/@esbuild/android-arm": {
"version": "0.17.3",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.3.tgz",
@ -1089,6 +1104,14 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
"node_modules/@fortaine/fetch-event-source": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/@fortaine/fetch-event-source/-/fetch-event-source-3.0.6.tgz",
"integrity": "sha512-621GAuLMvKtyZQ3IA6nlDWhV1V/7PGOTNIGLUifxt0KzM+dZIweJ6F3XvQF3QnqeNfS1N7WQ0Kil1Di/lhChEw==",
"engines": {
"node": ">=16.15"
}
},
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.8",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
@ -2255,6 +2278,11 @@
"@types/react": "*"
}
},
"node_modules/@types/retry": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
"integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA=="
},
"node_modules/@types/scheduler": {
"version": "0.16.3",
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
@ -2808,6 +2836,19 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"node_modules/binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
"engines": {
"node": ">=8"
}
},
"node_modules/binary-search": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/binary-search/-/binary-search-1.3.6.tgz",
"integrity": "sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA=="
},
"node_modules/boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
@ -2835,6 +2876,11 @@
"node": ">=8"
}
},
"node_modules/browser-or-node": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/browser-or-node/-/browser-or-node-2.1.1.tgz",
"integrity": "sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg=="
},
"node_modules/browserslist": {
"version": "4.21.5",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz",
@ -3138,6 +3184,14 @@
"url": "https://opencollective.com/core-js"
}
},
"node_modules/cross-fetch": {
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.6.tgz",
"integrity": "sha512-riRvo06crlE8HiqOwIpQhxwdOk4fOeR7FVM/wXoxchFEqMNUjvbs3bfo4OTgMEMHzppd4DxFBDbyySj8Cv781g==",
"dependencies": {
"node-fetch": "^2.6.11"
}
},
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@ -3963,6 +4017,11 @@
"node": ">=0.10.0"
}
},
"node_modules/eventemitter3": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
},
"node_modules/eventsource-parser": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-1.0.0.tgz",
@ -4019,6 +4078,11 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/expr-eval": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/expr-eval/-/expr-eval-2.0.2.tgz",
"integrity": "sha512-4EMSHGOPSwAfBiibw3ndnP0AvjDWLsMvGOvWEZ2F96IGk0bIVdjQisOHxReSkE13mHcfbuCiXw+G4y0zv6N8Eg=="
},
"node_modules/extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
@ -4143,6 +4207,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/flat": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
"integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
"bin": {
"flat": "cli.js"
}
},
"node_modules/flat-cache": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
@ -4773,6 +4845,11 @@
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/is-any-array": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-any-array/-/is-any-array-2.0.1.tgz",
"integrity": "sha512-UtilS7hLRu++wb/WBAw9bNuP1Eg04Ivn1vERJck8zJthEvXCBEBpGR/33u/xLKWEQf95803oalHrVDptcAvFdQ=="
},
"node_modules/is-arguments": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
@ -6437,6 +6514,14 @@
"node": ">=6"
}
},
"node_modules/jsonpointer": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz",
"integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/kleur": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
@ -6446,6 +6531,172 @@
"node": ">=6"
}
},
"node_modules/langchain": {
"version": "0.0.75",
"resolved": "https://registry.npmjs.org/langchain/-/langchain-0.0.75.tgz",
"integrity": "sha512-5bulBe3pEDnCuO3W84E+pmns6+7oKdNomsApPD1PqjplEwT3szSYaY8bvqJVxYz2Hq1wcS3sL1OyL9rbC/s0NA==",
"dependencies": {
"@anthropic-ai/sdk": "^0.4.3",
"@dqbd/tiktoken": "^1.0.7",
"ansi-styles": "^5.0.0",
"binary-extensions": "^2.2.0",
"browser-or-node": "^2.1.1",
"expr-eval": "^2.0.2",
"flat": "^5.0.2",
"jsonpointer": "^5.0.1",
"ml-distance": "^4.0.0",
"object-hash": "^3.0.0",
"openai": "^3.2.0",
"p-queue": "^6.6.2",
"p-retry": "4",
"uuid": "^9.0.0",
"yaml": "^2.2.1",
"zod": "^3.21.4",
"zod-to-json-schema": "^3.20.4"
},
"engines": {
"node": ">=18"
},
"peerDependencies": {
"@aws-sdk/client-dynamodb": "^3.310.0",
"@aws-sdk/client-lambda": "^3.310.0",
"@aws-sdk/client-s3": "^3.310.0",
"@clickhouse/client": "^0.0.14",
"@getmetal/metal-sdk": "*",
"@huggingface/inference": "^1.5.1",
"@opensearch-project/opensearch": "*",
"@pinecone-database/pinecone": "*",
"@supabase/supabase-js": "^2.10.0",
"@tensorflow-models/universal-sentence-encoder": "*",
"@tensorflow/tfjs-converter": "*",
"@tensorflow/tfjs-core": "*",
"@zilliz/milvus2-sdk-node": "^2.2.0",
"axios": "*",
"cheerio": "^1.0.0-rc.12",
"chromadb": "^1.4.0",
"cohere-ai": "^5.0.2",
"d3-dsv": "^2.0.0",
"epub2": "^3.0.1",
"hnswlib-node": "^1.4.2",
"html-to-text": "^9.0.5",
"mammoth": "*",
"mongodb": "^5.2.0",
"pdf-parse": "1.1.1",
"playwright": "^1.32.1",
"puppeteer": "^19.7.2",
"redis": "^4.6.4",
"replicate": "^0.9.0",
"srt-parser-2": "^1.2.2",
"typeorm": "^0.3.12",
"weaviate-ts-client": "^1.0.0"
},
"peerDependenciesMeta": {
"@aws-sdk/client-dynamodb": {
"optional": true
},
"@aws-sdk/client-lambda": {
"optional": true
},
"@aws-sdk/client-s3": {
"optional": true
},
"@clickhouse/client": {
"optional": true
},
"@getmetal/metal-sdk": {
"optional": true
},
"@huggingface/inference": {
"optional": true
},
"@opensearch-project/opensearch": {
"optional": true
},
"@pinecone-database/pinecone": {
"optional": true
},
"@supabase/supabase-js": {
"optional": true
},
"@tensorflow-models/universal-sentence-encoder": {
"optional": true
},
"@tensorflow/tfjs-converter": {
"optional": true
},
"@tensorflow/tfjs-core": {
"optional": true
},
"@zilliz/milvus2-sdk-node": {
"optional": true
},
"axios": {
"optional": true
},
"cheerio": {
"optional": true
},
"chromadb": {
"optional": true
},
"cohere-ai": {
"optional": true
},
"d3-dsv": {
"optional": true
},
"epub2": {
"optional": true
},
"hnswlib-node": {
"optional": true
},
"html-to-text": {
"optional": true
},
"mammoth": {
"optional": true
},
"mongodb": {
"optional": true
},
"pdf-parse": {
"optional": true
},
"playwright": {
"optional": true
},
"puppeteer": {
"optional": true
},
"redis": {
"optional": true
},
"replicate": {
"optional": true
},
"srt-parser-2": {
"optional": true
},
"typeorm": {
"optional": true
},
"weaviate-ts-client": {
"optional": true
}
}
},
"node_modules/langchain/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/leven": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
@ -7163,6 +7414,46 @@
"node": "*"
}
},
"node_modules/ml-array-mean": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/ml-array-mean/-/ml-array-mean-1.1.6.tgz",
"integrity": "sha512-MIdf7Zc8HznwIisyiJGRH9tRigg3Yf4FldW8DxKxpCCv/g5CafTw0RRu51nojVEOXuCQC7DRVVu5c7XXO/5joQ==",
"dependencies": {
"ml-array-sum": "^1.1.6"
}
},
"node_modules/ml-array-sum": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/ml-array-sum/-/ml-array-sum-1.1.6.tgz",
"integrity": "sha512-29mAh2GwH7ZmiRnup4UyibQZB9+ZLyMShvt4cH4eTK+cL2oEMIZFnSyB3SS8MlsTh6q/w/yh48KmqLxmovN4Dw==",
"dependencies": {
"is-any-array": "^2.0.0"
}
},
"node_modules/ml-distance": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/ml-distance/-/ml-distance-4.0.0.tgz",
"integrity": "sha512-zj7+UGZpHk3uL7n79XTfGNUjIGnhLn8xVvrxYvBHvXFxo3jq1q+/UjP311hZxnLVhbxbXCjUniThX8gozjacYA==",
"dependencies": {
"ml-array-mean": "^1.1.6",
"ml-distance-euclidean": "^2.0.0",
"ml-tree-similarity": "^1.0.0"
}
},
"node_modules/ml-distance-euclidean": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ml-distance-euclidean/-/ml-distance-euclidean-2.0.0.tgz",
"integrity": "sha512-yC9/2o8QF0A3m/0IXqCTXCzz2pNEzvmcE/9HFKOZGnTjatvBbsn4lWYJkxENkA4Ug2fnYl7PXQxnPi21sgMy/Q=="
},
"node_modules/ml-tree-similarity": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/ml-tree-similarity/-/ml-tree-similarity-1.0.0.tgz",
"integrity": "sha512-XJUyYqjSuUQkNQHMscr6tcjldsOoAekxADTplt40QKfwW6nd++1wHWV9AArl0Zvw/TIHgNaZZNvr8QGvE8wLRg==",
"dependencies": {
"binary-search": "^1.3.5",
"num-sort": "^2.0.0"
}
},
"node_modules/moment": {
"version": "2.29.4",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
@ -7297,6 +7588,44 @@
"react-i18next": "^12.2.0"
}
},
"node_modules/node-fetch": {
"version": "2.6.11",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz",
"integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/node-fetch/node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/node-fetch/node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/node-fetch/node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
},
"node_modules/node-int64": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz",
@ -7341,6 +7670,17 @@
"url": "https://github.com/fb55/nth-check?sponsor=1"
}
},
"node_modules/num-sort": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/num-sort/-/num-sort-2.1.0.tgz",
"integrity": "sha512-1MQz1Ed8z2yckoBeSfkQHHO9K1yDRxxtotKSJ9yvcTUUxSvfvzEq5GwBrjjHEpMlq/k5gvXdmJ1SbYxWtpNoVg==",
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/nwsapi": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.4.tgz",
@ -7355,6 +7695,14 @@
"node": ">=0.10.0"
}
},
"node_modules/object-hash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
"engines": {
"node": ">= 6"
}
},
"node_modules/object-inspect": {
"version": "1.12.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
@ -7445,6 +7793,23 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/openai": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/openai/-/openai-3.2.1.tgz",
"integrity": "sha512-762C9BNlJPbjjlWZi4WYK9iM2tAVAv0uUp1UmI34vb0CN5T2mjB/qM6RYBmNKMh/dN9fC+bxqPwWJZUTWW052A==",
"dependencies": {
"axios": "^0.26.0",
"form-data": "^4.0.0"
}
},
"node_modules/openai/node_modules/axios": {
"version": "0.26.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz",
"integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==",
"dependencies": {
"follow-redirects": "^1.14.8"
}
},
"node_modules/optionator": {
"version": "0.9.1",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
@ -7463,6 +7828,14 @@
"node": ">= 0.8.0"
}
},
"node_modules/p-finally": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
"integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==",
"engines": {
"node": ">=4"
}
},
"node_modules/p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@ -7494,6 +7867,44 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-queue": {
"version": "6.6.2",
"resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz",
"integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==",
"dependencies": {
"eventemitter3": "^4.0.4",
"p-timeout": "^3.2.0"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-retry": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz",
"integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==",
"dependencies": {
"@types/retry": "0.12.0",
"retry": "^0.13.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/p-timeout": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz",
"integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==",
"dependencies": {
"p-finally": "^1.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
@ -8133,6 +8544,14 @@
"node": ">=10"
}
},
"node_modules/retry": {
"version": "0.13.1",
"resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
"integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==",
"engines": {
"node": ">= 4"
}
},
"node_modules/reusify": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
@ -8932,6 +9351,14 @@
"requires-port": "^1.0.0"
}
},
"node_modules/uuid": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
"integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==",
"bin": {
"uuid": "dist/bin/uuid"
}
},
"node_modules/uvu": {
"version": "0.5.6",
"resolved": "https://registry.npmjs.org/uvu/-/uvu-0.5.6.tgz",
@ -9255,6 +9682,14 @@
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
"dev": true
},
"node_modules/yaml": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
"integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==",
"engines": {
"node": ">= 14"
}
},
"node_modules/yargs": {
"version": "17.7.1",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz",
@ -9293,6 +9728,22 @@
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/zod": {
"version": "3.21.4",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",
"integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
},
"node_modules/zod-to-json-schema": {
"version": "3.21.1",
"resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.21.1.tgz",
"integrity": "sha512-y5g0MPxDq+YG/T+cHGPYH4PcBpyCqwK6wxeJ76MR563y0gk/14HKfebq8xHiItY7lkc9GDFygCnkvNDTvAhYAg==",
"peerDependencies": {
"zod": "^3.21.4"
}
}
}
}

View file

@ -37,6 +37,7 @@
"axios": "^1.3.4",
"esbuild-plugin-svg": "^0.1.0",
"eventsource-parser": "^1.0.0",
"langchain": "^0.0.75",
"next-i18next": "^13.2.2",
"prop-types": "^15.8.1",
"react": "^18.2.0",

View file

@ -1,10 +1,10 @@
import ChatIcons from '@/components/ChatComponents/ChatIcons';
import ChatInput from '@/components/ChatComponents/ChatInput';
import ChatMessages from '@/components/ChatComponents/ChatMessages';
import { USER_SENDER } from '@/constants';
import { DEFAULT_SYSTEM_PROMPT, USER_SENDER } from '@/constants';
import { AppContext } from '@/context';
import { LangChainParams, getAIResponse } from '@/langchainStream';
import { CopilotSettings } from '@/main';
import { OpenAIRequestManager, OpenAiParams, getAIResponse } from '@/openAiStream';
import SharedState, { ChatMessage, useSharedState } from '@/sharedState';
import {
createChangeToneSelectionPrompt,
@ -43,7 +43,6 @@ interface ChatProps {
settings: CopilotSettings;
model: string;
emitter: EventEmitter;
streamManager: OpenAIRequestManager;
stream: boolean;
getChatVisibility: () => Promise<boolean>;
userSystemPrompt: string;
@ -51,7 +50,7 @@ interface ChatProps {
}
const Chat: React.FC<ChatProps> = ({
sharedState, settings, model, emitter, streamManager, stream, getChatVisibility,
sharedState, settings, model, emitter, stream, getChatVisibility,
userSystemPrompt, debug
}) => {
const [
@ -60,6 +59,7 @@ const Chat: React.FC<ChatProps> = ({
const [inputMessage, setInputMessage] = useState('');
const [currentAiMessage, setCurrentAiMessage] = useState('');
const [currentModel, setCurrentModel] = useState(model);
const [abortController, setAbortController] = useState<AbortController | null>(null);
const app = useContext(AppContext);
const {
@ -68,11 +68,14 @@ const Chat: React.FC<ChatProps> = ({
maxTokens,
contextTurns,
} = sanitizeSettings(settings);
const openAiParams: OpenAiParams = {
const systemPrompt = userSystemPrompt || DEFAULT_SYSTEM_PROMPT;
const langChainParams: LangChainParams = {
key: openAiApiKey,
model: currentModel,
temperature: Number(temperature),
maxTokens: Number(maxTokens),
systemMessage: systemPrompt,
}
// The number of past conversation turns to use as context for the AI
// The number of messages is doubled.
@ -96,13 +99,12 @@ const Chat: React.FC<ChatProps> = ({
await getAIResponse(
userMessage,
chatContext,
openAiParams,
streamManager,
langChainParams,
setCurrentAiMessage,
addMessage,
setAbortController,
stream,
debug,
userSystemPrompt,
);
};
@ -161,13 +163,12 @@ const Chat: React.FC<ChatProps> = ({
await getAIResponse(
promptMessage,
chatContext,
openAiParams,
streamManager,
langChainParams,
setCurrentAiMessage,
addMessage,
setAbortController,
stream,
debug,
userSystemPrompt,
);
};
@ -176,7 +177,10 @@ const Chat: React.FC<ChatProps> = ({
};
const handleStopGenerating = () => {
streamManager.stopStreaming();
if (abortController) {
console.log("User stopping generation...");
abortController.abort();
}
};
// Create an effect for each event type (command)
@ -195,18 +199,18 @@ const Chat: React.FC<ChatProps> = ({
};
// Have a hardcoded custom temperature for some commands that need more strictness
const updatedOpenAiParams = {
...openAiParams,
const updatedLangChainParams = {
...langChainParams,
...(custom_temperature && { temperature: custom_temperature }),
};
await getAIResponse(
promptMessage,
[],
updatedOpenAiParams,
streamManager,
updatedLangChainParams,
setCurrentAiMessage,
addMessage,
setAbortController,
stream,
debug,
);

View file

@ -2,7 +2,6 @@ import Chat from '@/components/Chat';
import { CHAT_VIEWTYPE } from '@/constants';
import { AppContext } from '@/context';
import CopilotPlugin, { CopilotSettings } from '@/main';
import { OpenAIRequestManager } from '@/openAiStream';
import SharedState from '@/sharedState';
import { EventEmitter } from 'events';
import { ItemView, WorkspaceLeaf } from 'obsidian';
@ -18,7 +17,6 @@ export default class CopilotView extends ItemView {
private stream = true;
private debug = false;
emitter: EventEmitter;
streamManager: OpenAIRequestManager;
userSystemPrompt = '';
useNotesAsContext = false;
@ -31,7 +29,6 @@ export default class CopilotView extends ItemView {
this.stream = plugin.settings.stream;
this.debug = plugin.settings.debug;
this.emitter = new EventEmitter();
this.streamManager = new OpenAIRequestManager();
this.getChatVisibility = this.getChatVisibility.bind(this);
this.userSystemPrompt = plugin.settings.userSystemPrompt;
this.useNotesAsContext = plugin.settings.useNotesAsContext;
@ -72,7 +69,6 @@ export default class CopilotView extends ItemView {
settings={this.settings}
model={this.model}
emitter={this.emitter}
streamManager={this.streamManager}
stream={this.stream}
getChatVisibility={this.getChatVisibility}
userSystemPrompt={this.userSystemPrompt}

View file

@ -1,10 +1,10 @@
import { CopilotSettings } from '@/main';
export const CHAR_LENGTH_LIMIT = 5800;
export const CHAR_LENGTH_LIMIT = 5800; // TODO: Remove this after unlimited context support
export const CHAT_VIEWTYPE = 'copilot-chat-view';
export const USER_SENDER = 'user';
export const AI_SENDER = 'ai';
export const DEFAULT_SYSTEM_PROMPT = 'You are a helpful assistant named Copilot for Obsidian.';
export const DEFAULT_SYSTEM_PROMPT = 'You are Obsidian Copilot, a helpful assistant that integrates AI to Obsidian note-taking.';
export const DEFAULT_SETTINGS: CopilotSettings = {
openAiApiKey: '',
defaultModel: 'gpt-3.5-turbo',

89
src/langchainStream.ts Normal file
View file

@ -0,0 +1,89 @@
import { AI_SENDER, USER_SENDER } from '@/constants';
import { ChatMessage } from '@/sharedState';
import { ChatOpenAI } from 'langchain/chat_models/openai';
import { AIChatMessage, HumanChatMessage, SystemChatMessage } from 'langchain/schema';
import { Notice } from 'obsidian';
export type Role = 'assistant' | 'user' | 'system';
export interface LangChainParams {
key: string,
model: string,
temperature: number,
maxTokens: number,
systemMessage: string,
}
export const getAIResponse = async (
userMessage: ChatMessage,
chatContext: ChatMessage[],
langChainParams: LangChainParams,
updateCurrentAiMessage: (message: string) => void,
addMessage: (message: ChatMessage) => void,
updateShouldAbort: (abortController: AbortController | null) => void,
stream = true,
debug = false,
) => {
const {
key, model, temperature, maxTokens, systemMessage,
} = langChainParams;
const messages = [
new SystemChatMessage(systemMessage),
...chatContext.map((chatMessage) => {
return chatMessage.sender === USER_SENDER
? new HumanChatMessage(chatMessage.message)
: new AIChatMessage(chatMessage.message);
}),
new HumanChatMessage(userMessage.message),
];
if (debug) {
console.log('langChainParams:', langChainParams);
console.log('system message:', systemMessage);
for (const [i, chatMessage] of chatContext.entries()) {
console.log(
`chat message ${i}:\nsender: ${chatMessage.sender}\n${chatMessage.message}`
);
}
}
const abortController = new AbortController();
try {
let fullAIResponse = '';
const chatOpenAI = new ChatOpenAI({
openAIApiKey: key,
modelName: model,
temperature: temperature,
maxTokens: maxTokens,
streaming: stream,
callbacks: [
{
handleLLMNewToken: (token) => {
fullAIResponse += token;
updateCurrentAiMessage(fullAIResponse);
},
},
],
});
updateShouldAbort(abortController);
await chatOpenAI.call(
messages,
{ signal: abortController.signal }
);
addMessage({
message: fullAIResponse,
sender: AI_SENDER,
isVisible: true,
});
updateCurrentAiMessage('');
} catch (error) {
const errorData = error?.response?.data?.error || error;
const errorCode = errorData?.code || error;
new Notice(`LangChain error: ${errorCode}`);
console.error(errorData);
}
};

View file

@ -84,21 +84,6 @@ export class CopilotSettingTab extends PluginSettingTab {
});
});
new Setting(containerEl)
.setName("Streaming mode")
.setDesc(
createFragment((frag) => {
frag.appendText("Stream the response from the API as it comes in. It can take a while for the API to respond, so keeping it on is recommended.");
})
)
.addToggle(toggle => toggle
.setValue(this.plugin.settings.stream)
.onChange(async (value) => {
this.plugin.settings.stream = value;
await this.plugin.saveSettings();
})
);
containerEl.createEl(
'h6',
{

38
wasmPlugin.mjs Normal file
View file

@ -0,0 +1,38 @@
import * as fs from 'fs/promises';
import * as path from 'path';
const wasmPlugin = {
name: 'wasm',
setup(build) {
build.onResolve({ filter: /\.wasm$/ }, args => {
if (args.namespace === 'wasm-stub') {
return {
path: args.path,
namespace: 'wasm-binary',
}
}
if (args.resolveDir === '') {
return
}
return {
path: path.isAbsolute(args.path) ? args.path : path.join(args.resolveDir, args.path),
namespace: 'wasm-stub',
}
})
build.onLoad({ filter: /.*/, namespace: 'wasm-stub' }, async (args) => ({
contents: `import wasm from ${JSON.stringify(args.path)}
export default (imports) =>
WebAssembly.instantiate(wasm, imports).then(
result => result.instance.exports)`,
}))
build.onLoad({ filter: /.*/, namespace: 'wasm-binary' }, async (args) => ({
contents: await fs.readFile(args.path),
loader: 'binary',
}))
},
}
export default wasmPlugin;