mirror of
https://github.com/run-llama/LlamaIndexTS.git
synced 2026-07-05 12:05:56 -04:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5f29ba5e2c | |||
| 4aba02eb82 | |||
| 75736ad01b | |||
| 68a508fcd0 | |||
| 6281fc8c91 | |||
| c3747d092a | |||
| 24a39aefb8 | |||
| 0b1299036d | |||
| 2c8d7941f0 | |||
| a1a72ab223 | |||
| b99ab056d1 | |||
| 1a45b44307 | |||
| 804c57519f | |||
| ce94780b95 | |||
| 645fcf6c24 | |||
| e37fa5d9ca | |||
| 97e4ecd5b8 | |||
| b6a660651b | |||
| 456d3fb0b3 | |||
| efa326a871 | |||
| 5765b637ce | |||
| 72687b4f69 | |||
| 0c67e1f8f3 | |||
| 4a0619758a | |||
| bc7a11cdbe | |||
| 5596e31947 | |||
| 2fe2b813ba | |||
| be5df5b01b | |||
| e74fe88342 | |||
| f1862ccab1 | |||
| 9e74a4327f | |||
| 5e61934d5a | |||
| 2008efe0ee | |||
| ee719a1fda | |||
| 1dce275a7c | |||
| d10533ef77 | |||
| 8aeb8ae690 | |||
| e8c41c5c27 | |||
| 051b4ddfa2 | |||
| 61103b677b | |||
| e69cac672a | |||
| 94246a3ca8 |
@@ -69,7 +69,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Build
|
||||
run: pnpm run build --filter llamaindex
|
||||
run: pnpm run build
|
||||
- name: Use Build For Examples
|
||||
run: pnpm link ../packages/core/
|
||||
working-directory: ./examples
|
||||
@@ -105,7 +105,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Build llamaindex
|
||||
run: pnpm run build --filter llamaindex
|
||||
run: pnpm run build
|
||||
- name: Build ${{ matrix.packages }}
|
||||
run: pnpm run build
|
||||
working-directory: packages/core/e2e/examples/${{ matrix.packages }}
|
||||
@@ -124,7 +124,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Build
|
||||
run: pnpm run build --filter llamaindex
|
||||
run: pnpm run build
|
||||
- name: Copy examples
|
||||
run: rsync -rv --exclude=node_modules ./examples ${{ runner.temp }}
|
||||
- name: Pack @llamaindex/env
|
||||
|
||||
@@ -78,6 +78,17 @@ node --import tsx ./main.ts
|
||||
|
||||
### Next.js
|
||||
|
||||
First, you will need to add a llamaindex plugin to your Next.js project.
|
||||
|
||||
```js
|
||||
// next.config.js
|
||||
const withLlamaIndex = require("llamaindex/next");
|
||||
|
||||
module.exports = withLlamaIndex({
|
||||
// your next.js config
|
||||
});
|
||||
```
|
||||
|
||||
You can combine `ai` with `llamaindex` in Next.js with RSC (React Server Components).
|
||||
|
||||
```tsx
|
||||
|
||||
@@ -1,5 +1,78 @@
|
||||
# docs
|
||||
|
||||
## 0.0.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [4aba02e]
|
||||
- llamaindex@0.3.10
|
||||
|
||||
## 0.0.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [c3747d0]
|
||||
- llamaindex@0.3.9
|
||||
|
||||
## 0.0.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [ce94780]
|
||||
- llamaindex@0.3.8
|
||||
|
||||
## 0.0.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b6a6606]
|
||||
- Updated dependencies [b6a6606]
|
||||
- llamaindex@0.3.7
|
||||
|
||||
## 0.0.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [efa326a]
|
||||
- llamaindex@0.3.6
|
||||
|
||||
## 0.0.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [bc7a11c]
|
||||
- Updated dependencies [2fe2b81]
|
||||
- Updated dependencies [5596e31]
|
||||
- Updated dependencies [e74fe88]
|
||||
- Updated dependencies [be5df5b]
|
||||
- llamaindex@0.3.5
|
||||
|
||||
## 0.0.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1dce275]
|
||||
- Updated dependencies [d10533e]
|
||||
- Updated dependencies [2008efe]
|
||||
- Updated dependencies [5e61934]
|
||||
- Updated dependencies [9e74a43]
|
||||
- Updated dependencies [ee719a1]
|
||||
- llamaindex@0.3.4
|
||||
|
||||
## 0.0.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e8c41c5]
|
||||
- llamaindex@0.3.3
|
||||
|
||||
## 0.0.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [61103b6]
|
||||
- llamaindex@0.3.2
|
||||
|
||||
## 0.0.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -72,12 +72,8 @@ export class MyAgent extends AgentRunner<MyLLM> {
|
||||
// create store is a function to create a store for each task, by default it only includes `messages` and `toolOutputs`
|
||||
createStore = AgentRunner.defaultCreateStore;
|
||||
|
||||
static taskHandler: TaskHandler<Anthropic> = async (step) => {
|
||||
const { input } = step;
|
||||
static taskHandler: TaskHandler<Anthropic> = async (step, enqueueOutput) => {
|
||||
const { llm, stream } = step.context;
|
||||
if (input) {
|
||||
step.context.store.messages = [...step.context.store.messages, input];
|
||||
}
|
||||
// initialize the input
|
||||
const response = await llm.chat({
|
||||
stream,
|
||||
@@ -90,27 +86,21 @@ export class MyAgent extends AgentRunner<MyLLM> {
|
||||
];
|
||||
// your logic here to decide whether to continue the task
|
||||
const shouldContinue = Math.random(); /* <-- replace with your logic here */
|
||||
enqueueOutput({
|
||||
taskStep: step,
|
||||
output: response,
|
||||
isLast: !shouldContinue,
|
||||
});
|
||||
if (shouldContinue) {
|
||||
const content = await someHeavyFunctionCall();
|
||||
// if you want to continue the task, you can insert your new context for the next task step
|
||||
step.context.store.messages = [
|
||||
...step.context.store.messages,
|
||||
{
|
||||
content: "INSERT MY NEW DATA",
|
||||
content,
|
||||
role: "user",
|
||||
},
|
||||
];
|
||||
return {
|
||||
taskStep: step,
|
||||
output: response,
|
||||
isLast: false,
|
||||
};
|
||||
} else {
|
||||
// if you want to end the task, you can return the response with `isLast: true`
|
||||
return {
|
||||
taskStep: step,
|
||||
output: response,
|
||||
isLast: true,
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -263,6 +253,9 @@ const sumNumbers = FunctionTool.from<Input>(
|
||||
In addition to Node.js, LlamaIndexTS now offers enhanced support for Next.js, Deno, and Cloudflare Workers, making it
|
||||
more versatile across different platforms.
|
||||
|
||||
For now, you can install llamaindex and directly import it into your existing Next.js, Deno or Cloudflare Worker project
|
||||
**without any extra configuration**.
|
||||
|
||||
#### [Deno](https://deno.com/)
|
||||
|
||||
You can use LlamaIndexTS in Deno by installation through JSR:
|
||||
|
||||
+14
-14
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "docs",
|
||||
"version": "0.0.9",
|
||||
"version": "0.0.18",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
@@ -15,29 +15,29 @@
|
||||
"typecheck": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@docusaurus/core": "^3.2.1",
|
||||
"@docusaurus/remark-plugin-npm2yarn": "^3.2.1",
|
||||
"@docusaurus/core": "^3.3.2",
|
||||
"@docusaurus/remark-plugin-npm2yarn": "^3.3.2",
|
||||
"@llamaindex/examples": "workspace:*",
|
||||
"@mdx-js/react": "^3.0.1",
|
||||
"clsx": "^2.1.0",
|
||||
"clsx": "^2.1.1",
|
||||
"llamaindex": "workspace:*",
|
||||
"postcss": "^8.4.38",
|
||||
"prism-react-renderer": "^2.3.1",
|
||||
"raw-loader": "^4.0.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@docusaurus/module-type-aliases": "3.2.0",
|
||||
"@docusaurus/preset-classic": "^3.2.1",
|
||||
"@docusaurus/theme-classic": "^3.2.1",
|
||||
"@docusaurus/types": "^3.2.1",
|
||||
"@docusaurus/module-type-aliases": "3.3.2",
|
||||
"@docusaurus/preset-classic": "^3.3.2",
|
||||
"@docusaurus/theme-classic": "^3.3.2",
|
||||
"@docusaurus/types": "^3.3.2",
|
||||
"@tsconfig/docusaurus": "^2.0.3",
|
||||
"@types/node": "^20.12.7",
|
||||
"docusaurus-plugin-typedoc": "^0.22.0",
|
||||
"@types/node": "^20.12.11",
|
||||
"docusaurus-plugin-typedoc": "^1.0.1",
|
||||
"typedoc": "^0.25.13",
|
||||
"typedoc-plugin-markdown": "^3.17.1",
|
||||
"typescript": "^5.4.4"
|
||||
"typedoc-plugin-markdown": "^4.0.1",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
DEBUG=llamaindex
|
||||
@@ -0,0 +1,39 @@
|
||||
import { ChatResponseChunk, OpenAIAgent } from "llamaindex";
|
||||
import { ReadableStream } from "node:stream/web";
|
||||
import {
|
||||
getCurrentIDTool,
|
||||
getUserInfoTool,
|
||||
getWeatherTool,
|
||||
} from "./utils/tools";
|
||||
|
||||
async function main() {
|
||||
// Create an OpenAIAgent with the function tools
|
||||
const agent = new OpenAIAgent({
|
||||
tools: [getCurrentIDTool, getUserInfoTool, getWeatherTool],
|
||||
});
|
||||
|
||||
const task = await agent.createTask(
|
||||
"What is my current address weather based on my profile?",
|
||||
true,
|
||||
);
|
||||
|
||||
for await (const stepOutput of task) {
|
||||
const stream = stepOutput.output as ReadableStream<ChatResponseChunk>;
|
||||
if (stepOutput.isLast) {
|
||||
for await (const chunk of stream) {
|
||||
process.stdout.write(chunk.delta);
|
||||
}
|
||||
process.stdout.write("\n");
|
||||
} else {
|
||||
// handing function call
|
||||
console.log("handling function call...");
|
||||
for await (const chunk of stream) {
|
||||
console.log("debug:", JSON.stringify(chunk.raw));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main().then(() => {
|
||||
console.log("Done");
|
||||
});
|
||||
@@ -53,7 +53,7 @@ async function main() {
|
||||
message: "How much is 5 + 5? then divide by 2",
|
||||
});
|
||||
|
||||
console.log(String(response));
|
||||
console.log(response.response.message);
|
||||
}
|
||||
|
||||
void main().then(() => {
|
||||
|
||||
@@ -29,15 +29,16 @@ async function main() {
|
||||
// Create an OpenAIAgent with the function tools
|
||||
const agent = new OpenAIAgent({
|
||||
tools: [queryEngineTool],
|
||||
verbose: true,
|
||||
});
|
||||
|
||||
// Chat with the agent
|
||||
const response = await agent.chat({
|
||||
message: "What was his salary?",
|
||||
message: "What was his first salary?",
|
||||
});
|
||||
|
||||
// Print the response
|
||||
console.log(String(response));
|
||||
console.log(response.response);
|
||||
}
|
||||
|
||||
void main().then(() => {
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import { ChatResponseChunk, ReActAgent } from "llamaindex";
|
||||
import { ReadableStream } from "node:stream/web";
|
||||
import {
|
||||
getCurrentIDTool,
|
||||
getUserInfoTool,
|
||||
getWeatherTool,
|
||||
} from "./utils/tools";
|
||||
|
||||
async function main() {
|
||||
// Create an OpenAIAgent with the function tools
|
||||
const agent = new ReActAgent({
|
||||
tools: [getCurrentIDTool, getUserInfoTool, getWeatherTool],
|
||||
});
|
||||
|
||||
const task = await agent.createTask(
|
||||
"What is my current address weather based on my profile?",
|
||||
true,
|
||||
);
|
||||
|
||||
for await (const stepOutput of task) {
|
||||
const stream = stepOutput.output as ReadableStream<ChatResponseChunk>;
|
||||
if (stepOutput.isLast) {
|
||||
for await (const chunk of stream) {
|
||||
process.stdout.write(chunk.delta);
|
||||
}
|
||||
process.stdout.write("\n");
|
||||
} else {
|
||||
// handing function call
|
||||
console.log("handling function call...");
|
||||
for await (const chunk of stream) {
|
||||
console.log("debug:", JSON.stringify(chunk.raw));
|
||||
}
|
||||
}
|
||||
console.log("---");
|
||||
}
|
||||
}
|
||||
|
||||
void main().then(() => {
|
||||
console.log("Done");
|
||||
});
|
||||
@@ -0,0 +1,65 @@
|
||||
import {
|
||||
FunctionTool,
|
||||
MetadataMode,
|
||||
NodeWithScore,
|
||||
OpenAIAgent,
|
||||
SimpleDirectoryReader,
|
||||
VectorStoreIndex,
|
||||
} from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
// Load the documents
|
||||
const documents = await new SimpleDirectoryReader().loadData({
|
||||
directoryPath: "node_modules/llamaindex/examples",
|
||||
});
|
||||
|
||||
// Create a vector index from the documents
|
||||
const vectorIndex = await VectorStoreIndex.fromDocuments(documents);
|
||||
|
||||
const retriever = vectorIndex.asRetriever({ similarityTopK: 3 });
|
||||
|
||||
const retrieverTool = FunctionTool.from(
|
||||
async ({ query }: { query: string }) => {
|
||||
const nodesWithScores = await retriever.retrieve({
|
||||
query,
|
||||
});
|
||||
return nodesWithScores
|
||||
.map((nodeWithScore: NodeWithScore) =>
|
||||
nodeWithScore.node.getContent(MetadataMode.NONE),
|
||||
)
|
||||
.join("\n");
|
||||
},
|
||||
{
|
||||
name: "get_abramov_info",
|
||||
description: "Get information about the Abramov documents",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
query: {
|
||||
type: "string",
|
||||
description: "The query about Abramov",
|
||||
},
|
||||
},
|
||||
required: ["query"],
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// Create an OpenAIAgent with the function tools
|
||||
const agent = new OpenAIAgent({
|
||||
tools: [retrieverTool],
|
||||
verbose: true,
|
||||
});
|
||||
|
||||
// Chat with the agent
|
||||
const response = await agent.chat({
|
||||
message: "What was his first salary?",
|
||||
});
|
||||
|
||||
// Print the response
|
||||
console.log(response.response);
|
||||
}
|
||||
|
||||
void main().then(() => {
|
||||
console.log("Done");
|
||||
});
|
||||
@@ -1,97 +0,0 @@
|
||||
import { FunctionTool, OpenAIAgent } from "llamaindex";
|
||||
import { ReadableStream } from "node:stream/web";
|
||||
|
||||
// Define a function to sum two numbers
|
||||
function sumNumbers({ a, b }: { a: number; b: number }) {
|
||||
return `${a + b}`;
|
||||
}
|
||||
|
||||
// Define a function to divide two numbers
|
||||
function divideNumbers({ a, b }: { a: number; b: number }) {
|
||||
return `${a / b}`;
|
||||
}
|
||||
|
||||
// Define the parameters of the sum function as a JSON schema
|
||||
const sumJSON = {
|
||||
type: "object",
|
||||
properties: {
|
||||
a: {
|
||||
type: "number",
|
||||
description: "The first number",
|
||||
},
|
||||
b: {
|
||||
type: "number",
|
||||
description: "The second number",
|
||||
},
|
||||
},
|
||||
required: ["a", "b"],
|
||||
} as const;
|
||||
|
||||
const divideJSON = {
|
||||
type: "object",
|
||||
properties: {
|
||||
a: {
|
||||
type: "number",
|
||||
description: "The dividend",
|
||||
},
|
||||
b: {
|
||||
type: "number",
|
||||
description: "The divisor",
|
||||
},
|
||||
},
|
||||
required: ["a", "b"],
|
||||
} as const;
|
||||
|
||||
async function main() {
|
||||
// Create a function tool from the sum function
|
||||
const functionTool = new FunctionTool(sumNumbers, {
|
||||
name: "sumNumbers",
|
||||
description: "Use this function to sum two numbers",
|
||||
parameters: sumJSON,
|
||||
});
|
||||
|
||||
// Create a function tool from the divide function
|
||||
const functionTool2 = new FunctionTool(divideNumbers, {
|
||||
name: "divideNumbers",
|
||||
description: "Use this function to divide two numbers",
|
||||
parameters: divideJSON,
|
||||
});
|
||||
|
||||
// Create an OpenAIAgent with the function tools
|
||||
const agent = new OpenAIAgent({
|
||||
tools: [functionTool, functionTool2],
|
||||
});
|
||||
|
||||
// Create a task to sum and divide numbers
|
||||
const task = await agent.createTask("How much is 5 + 5? then divide by 2");
|
||||
|
||||
let count = 0;
|
||||
|
||||
for await (const stepOutput of task) {
|
||||
console.log(`Runnning step ${count++}`);
|
||||
console.log(`======== OUTPUT ==========`);
|
||||
const output = stepOutput.output;
|
||||
if (output instanceof ReadableStream) {
|
||||
for await (const chunk of output) {
|
||||
process.stdout.write(chunk.delta);
|
||||
}
|
||||
} else {
|
||||
console.log(output);
|
||||
}
|
||||
console.log(`==========================`);
|
||||
|
||||
if (stepOutput.isLast) {
|
||||
if (stepOutput.output instanceof ReadableStream) {
|
||||
for await (const chunk of stepOutput.output) {
|
||||
process.stdout.write(chunk.delta);
|
||||
}
|
||||
} else {
|
||||
console.log(stepOutput.output);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main().then(() => {
|
||||
console.log("Done");
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
import { FunctionTool } from "llamaindex";
|
||||
|
||||
export const getCurrentIDTool = FunctionTool.from(
|
||||
() => {
|
||||
console.log("Getting user id...");
|
||||
return crypto.randomUUID();
|
||||
},
|
||||
{
|
||||
name: "get_user_id",
|
||||
description: "Get a random user id",
|
||||
},
|
||||
);
|
||||
|
||||
export const getUserInfoTool = FunctionTool.from(
|
||||
({ userId }: { userId: string }) => {
|
||||
console.log("Getting user info...", userId);
|
||||
return `Name: Alex; Address: 1234 Main St, CA; User ID: ${userId}`;
|
||||
},
|
||||
{
|
||||
name: "get_user_info",
|
||||
description: "Get user info",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
userId: {
|
||||
type: "string",
|
||||
description: "The user id",
|
||||
},
|
||||
},
|
||||
required: ["userId"],
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
export const getWeatherTool = FunctionTool.from(
|
||||
({ address }: { address: string }) => {
|
||||
console.log("Getting weather...", address);
|
||||
return `${address} is in a sunny location!`;
|
||||
},
|
||||
{
|
||||
name: "get_weather",
|
||||
description: "Get the current weather for a location",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
address: {
|
||||
type: "string",
|
||||
description: "The address",
|
||||
},
|
||||
},
|
||||
required: ["address"],
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,22 @@
|
||||
import { HuggingFaceInferenceAPI } from "llamaindex";
|
||||
|
||||
(async () => {
|
||||
if (!process.env.HUGGING_FACE_TOKEN) {
|
||||
throw new Error("Please set the HUGGING_FACE_TOKEN environment variable.");
|
||||
}
|
||||
const hf = new HuggingFaceInferenceAPI({
|
||||
accessToken: process.env.HUGGING_FACE_TOKEN,
|
||||
model: "mistralai/Mixtral-8x7B-Instruct-v0.1",
|
||||
});
|
||||
const result = await hf.chat({
|
||||
messages: [
|
||||
{ content: "You want to talk in rhymes.", role: "system" },
|
||||
{
|
||||
content:
|
||||
"How much wood would a woodchuck chuck if a woodchuck could chuck wood?",
|
||||
role: "user",
|
||||
},
|
||||
],
|
||||
});
|
||||
console.log(result);
|
||||
})();
|
||||
+6
-1
@@ -2,7 +2,12 @@ import { OllamaEmbedding } from "llamaindex";
|
||||
import { Ollama } from "llamaindex/llm/ollama";
|
||||
|
||||
(async () => {
|
||||
const llm = new Ollama({ model: "llama3" });
|
||||
const llm = new Ollama({
|
||||
model: "llama3",
|
||||
config: {
|
||||
host: "http://localhost:11434",
|
||||
},
|
||||
});
|
||||
const embedModel = new OllamaEmbedding({ model: "nomic-embed-text" });
|
||||
{
|
||||
const response = await llm.chat({
|
||||
|
||||
@@ -4,22 +4,22 @@
|
||||
"version": "0.0.4",
|
||||
"dependencies": {
|
||||
"@aws-crypto/sha256-js": "^5.2.0",
|
||||
"@datastax/astra-db-ts": "^1.0.1",
|
||||
"@datastax/astra-db-ts": "^1.1.0",
|
||||
"@notionhq/client": "^2.2.15",
|
||||
"@pinecone-database/pinecone": "^1.1.3",
|
||||
"@zilliz/milvus2-sdk-node": "^2.4.1",
|
||||
"@pinecone-database/pinecone": "^2.2.0",
|
||||
"@zilliz/milvus2-sdk-node": "^2.4.2",
|
||||
"chromadb": "^1.8.1",
|
||||
"commander": "^11.1.0",
|
||||
"commander": "^12.0.0",
|
||||
"dotenv": "^16.4.5",
|
||||
"js-tiktoken": "^1.0.11",
|
||||
"llamaindex": "*",
|
||||
"mongodb": "^6.5.0",
|
||||
"mongodb": "^6.6.1",
|
||||
"pathe": "^1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.12.7",
|
||||
"@types/node": "^20.12.11",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsx": "^4.7.2",
|
||||
"tsx": "^4.9.3",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
"llamaindex": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.12.7",
|
||||
"tsx": "^4.7.2",
|
||||
"@types/node": "^20.12.11",
|
||||
"tsx": "^4.9.3",
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -2,7 +2,7 @@
|
||||
"name": "@llamaindex/monorepo",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "turbo run build",
|
||||
"build": "turbo run build --filter=\"!docs\" --filter=\"!*-test\"",
|
||||
"build:release": "turbo run build lint test --filter=\"!docs\" --filter=\"!*-test\"",
|
||||
"dev": "turbo run dev",
|
||||
"format": "prettier --ignore-unknown --cache --check .",
|
||||
@@ -15,22 +15,22 @@
|
||||
"release": "pnpm run check-minor-version && pnpm run build:release && changeset publish",
|
||||
"release-snapshot": "pnpm run check-minor-version && pnpm run build:release && changeset publish --tag snapshot",
|
||||
"check-minor-version": "node ./scripts/check-minor-version",
|
||||
"new-version": "changeset version && pnpm run check-minor-version && pnpm run build:release",
|
||||
"new-version": "changeset version && pnpm run check-minor-version && pnpm format:write && pnpm run build:release",
|
||||
"new-snapshot": "pnpm run build:release && changeset version --snapshot"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.27.1",
|
||||
"@typescript-eslint/eslint-plugin": "^7.7.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.8.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-next": "^13.5.6",
|
||||
"eslint-config-prettier": "^8.10.0",
|
||||
"eslint-config-turbo": "^1.13.2",
|
||||
"eslint-plugin-react": "7.28.0",
|
||||
"eslint-config-next": "^14.2.3",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-config-turbo": "^1.13.3",
|
||||
"eslint-plugin-react": "7.34.1",
|
||||
"husky": "^9.0.11",
|
||||
"lint-staged": "^15.2.2",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-organize-imports": "^3.2.4",
|
||||
"turbo": "^1.13.2",
|
||||
"turbo": "^1.13.3",
|
||||
"typescript": "^5.4.5"
|
||||
},
|
||||
"packageManager": "pnpm@9.0.5",
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
# @llamaindex/autotool
|
||||
|
||||
> Auto transpile your JS function to LLM Agent compatible
|
||||
|
||||
## Usage
|
||||
|
||||
First, Install the package
|
||||
|
||||
```shell
|
||||
npm install @llamaindex/autotool
|
||||
pnpm add @llamaindex/autotool
|
||||
yarn add @llamaindex/autotool
|
||||
```
|
||||
|
||||
Second, Add the plugin/loader to your configuration:
|
||||
|
||||
### Next.js
|
||||
|
||||
```javascript
|
||||
import { withNext } from "@llamaindex/autotool/next";
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {};
|
||||
|
||||
export default withNext(nextConfig);
|
||||
```
|
||||
|
||||
### Node.js
|
||||
|
||||
```shell
|
||||
node --import @llamaindex/autotool/node ./path/to/your/script.js
|
||||
```
|
||||
|
||||
Third, add `"use tool"` on top of your tool file or change to `.tool.ts`.
|
||||
|
||||
```typescript
|
||||
"use tool";
|
||||
|
||||
export function getWeather(city: string) {
|
||||
// ...
|
||||
}
|
||||
// ...
|
||||
```
|
||||
|
||||
Finally, export a chat handler function to the frontend using `llamaindex` Agent
|
||||
|
||||
```typescript
|
||||
"use server";
|
||||
|
||||
// imports ...
|
||||
|
||||
export async function chatWithAI(message: string): Promise<JSX.Element> {
|
||||
const agent = new OpenAIAgent({
|
||||
tools: convertTools("llamaindex"),
|
||||
});
|
||||
const uiStream = createStreamableUI();
|
||||
agent
|
||||
.chat({
|
||||
stream: true,
|
||||
message,
|
||||
})
|
||||
.then(async (responseStream) => {
|
||||
return responseStream.pipeTo(
|
||||
new WritableStream({
|
||||
start: () => {
|
||||
uiStream.append("\n");
|
||||
},
|
||||
write: async (message) => {
|
||||
uiStream.append(message.response.delta);
|
||||
},
|
||||
close: () => {
|
||||
uiStream.done();
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
return uiStream.value;
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
@@ -0,0 +1,17 @@
|
||||
# @llamaindex/autotool-01-node-example
|
||||
|
||||
## null
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [4aba02e]
|
||||
- llamaindex@0.3.10
|
||||
- @llamaindex/autotool@0.0.1
|
||||
|
||||
## null
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [c3747d0]
|
||||
- llamaindex@0.3.9
|
||||
- @llamaindex/autotool@0.0.1
|
||||
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "@llamaindex/autotool-01-node-example",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@llamaindex/autotool": "workspace:*",
|
||||
"llamaindex": "workspace:*",
|
||||
"openai": "^4.43.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tsx": "^4.9.3"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node --import tsx --import @llamaindex/autotool/node ./src/index.ts"
|
||||
},
|
||||
"version": null
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { getWeather } from "./utils.js";
|
||||
|
||||
/**
|
||||
* Get current location
|
||||
*/
|
||||
export function getCurrentLocation() {
|
||||
console.log("Getting current location");
|
||||
return "London";
|
||||
}
|
||||
|
||||
export { getWeather };
|
||||
@@ -0,0 +1,23 @@
|
||||
import { convertTools } from "@llamaindex/autotool";
|
||||
import { OpenAI } from "openai";
|
||||
import "./index.tool.js";
|
||||
|
||||
const openai = new OpenAI();
|
||||
{
|
||||
const response = await openai.chat.completions.create({
|
||||
model: "gpt-3.5-turbo",
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: "What's my current weather?",
|
||||
},
|
||||
],
|
||||
tools: convertTools("openai"),
|
||||
stream: false,
|
||||
});
|
||||
|
||||
const toolCalls = response.choices[0].message.tool_calls ?? [];
|
||||
for (const toolCall of toolCalls) {
|
||||
toolCall.function.name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* Get the weather for a city
|
||||
* @param city The city to get the weather for
|
||||
* @returns The weather for the city, e.g. "Sunny", "Rainy", etc.
|
||||
*/
|
||||
export function getWeather(city: string) {
|
||||
return `The weather in ${city} is sunny!`;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./lib",
|
||||
"module": "node16",
|
||||
"moduleResolution": "node16"
|
||||
},
|
||||
"include": ["./src"]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# Rename this file to `.env.local` to use environment variables locally with `next dev`
|
||||
# https://nextjs.org/docs/pages/building-your-application/configuring/environment-variables
|
||||
MY_HOST="example.com"
|
||||
@@ -0,0 +1,35 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
@@ -0,0 +1,17 @@
|
||||
# @llamaindex/autotool-02-next-example
|
||||
|
||||
## 0.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [4aba02e]
|
||||
- llamaindex@0.3.10
|
||||
- @llamaindex/autotool@0.0.1
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [c3747d0]
|
||||
- llamaindex@0.3.9
|
||||
- @llamaindex/autotool@0.0.1
|
||||
@@ -0,0 +1,30 @@
|
||||
This is a [LlamaIndex](https://www.llamaindex.ai/) project using [Next.js](https://nextjs.org/) bootstrapped with [`create-llama`](https://github.com/run-llama/LlamaIndexTS/tree/main/packages/create-llama).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, install the dependencies:
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
Second, run the development server:
|
||||
|
||||
```
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
|
||||
|
||||
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about LlamaIndex, take a look at the following resources:
|
||||
|
||||
- [LlamaIndex Documentation](https://docs.llamaindex.ai) - learn about LlamaIndex (Python features).
|
||||
- [LlamaIndexTS Documentation](https://ts.llamaindex.ai) - learn about LlamaIndex (Typescript features).
|
||||
|
||||
You can check out [the LlamaIndexTS GitHub repository](https://github.com/run-llama/LlamaIndexTS) - your feedback and contributions are welcome!
|
||||
@@ -0,0 +1,38 @@
|
||||
"use server";
|
||||
import { OpenAIAgent } from "llamaindex";
|
||||
// import your tools on top, that's it
|
||||
import { runWithStreamableUI } from "@/context";
|
||||
import "@/tool";
|
||||
import { convertTools } from "@llamaindex/autotool";
|
||||
import { createStreamableUI } from "ai/rsc";
|
||||
import type { JSX } from "react";
|
||||
|
||||
export async function chatWithAI(message: string): Promise<JSX.Element> {
|
||||
const agent = new OpenAIAgent({
|
||||
tools: convertTools("llamaindex"),
|
||||
});
|
||||
const uiStream = createStreamableUI();
|
||||
runWithStreamableUI(uiStream, () =>
|
||||
agent
|
||||
.chat({
|
||||
stream: true,
|
||||
message,
|
||||
})
|
||||
.then(async (responseStream) => {
|
||||
return responseStream.pipeTo(
|
||||
new WritableStream({
|
||||
start: () => {
|
||||
uiStream.append("\n");
|
||||
},
|
||||
write: async (message) => {
|
||||
uiStream.append(message.response.delta);
|
||||
},
|
||||
close: () => {
|
||||
uiStream.done();
|
||||
},
|
||||
}),
|
||||
);
|
||||
}),
|
||||
).catch(uiStream.error);
|
||||
return uiStream.value;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,94 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--muted: 210 40% 96.1%;
|
||||
--muted-foreground: 215.4 16.3% 46.9%;
|
||||
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--border: 214.3 31.8% 91.4%;
|
||||
--input: 214.3 31.8% 91.4%;
|
||||
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--primary: 222.2 47.4% 11.2%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
|
||||
--secondary: 210 40% 96.1%;
|
||||
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--accent: 210 40% 96.1%;
|
||||
--accent-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--destructive: 0 100% 50%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--ring: 215 20.2% 65.1%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 224 71% 4%;
|
||||
--foreground: 213 31% 91%;
|
||||
|
||||
--muted: 223 47% 11%;
|
||||
--muted-foreground: 215.4 16.3% 56.9%;
|
||||
|
||||
--accent: 216 34% 17%;
|
||||
--accent-foreground: 210 40% 98%;
|
||||
|
||||
--popover: 224 71% 4%;
|
||||
--popover-foreground: 215 20.2% 65.1%;
|
||||
|
||||
--border: 216 34% 17%;
|
||||
--input: 216 34% 17%;
|
||||
|
||||
--card: 224 71% 4%;
|
||||
--card-foreground: 213 31% 91%;
|
||||
|
||||
--primary: 210 40% 98%;
|
||||
--primary-foreground: 222.2 47.4% 1.2%;
|
||||
|
||||
--secondary: 222.2 47.4% 11.2%;
|
||||
--secondary-foreground: 210 40% 98%;
|
||||
|
||||
--destructive: 0 63% 31%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--ring: 216 34% 17%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@layer base {
|
||||
* {
|
||||
@apply border-border;
|
||||
}
|
||||
body {
|
||||
@apply bg-background text-foreground;
|
||||
font-feature-settings:
|
||||
"rlig" 1,
|
||||
"calt" 1;
|
||||
}
|
||||
.background-gradient {
|
||||
background-color: #fff;
|
||||
background-image: radial-gradient(
|
||||
at 21% 11%,
|
||||
rgba(186, 186, 233, 0.53) 0,
|
||||
transparent 50%
|
||||
),
|
||||
radial-gradient(at 85% 0, hsla(46, 57%, 78%, 0.52) 0, transparent 50%),
|
||||
radial-gradient(at 91% 36%, rgba(194, 213, 255, 0.68) 0, transparent 50%),
|
||||
radial-gradient(at 8% 40%, rgba(251, 218, 239, 0.46) 0, transparent 50%);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Inter } from "next/font/google";
|
||||
import { Toaster } from "sonner";
|
||||
import "./globals.css";
|
||||
|
||||
const inter = Inter({ subsets: ["latin"] });
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Llama App",
|
||||
description: "Generated by create-llama",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={inter.className}>
|
||||
<Toaster />
|
||||
{children}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { ChatSection } from "@/components/chat-section";
|
||||
|
||||
export const runtime = "edge";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className="flex min-h-screen flex-col items-center gap-10 p-24 background-gradient">
|
||||
<ChatSection />
|
||||
</main>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
"use client";
|
||||
import { chatWithAI } from "@/actions";
|
||||
import { ReactNode, useActionState } from "react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
export function ChatSection() {
|
||||
const [state, formAction] = useActionState<ReactNode | null, FormData>(
|
||||
async (state, payload) => {
|
||||
const input = payload.get("input") as string | null;
|
||||
if (!input) {
|
||||
toast.error("Please type a message");
|
||||
return null;
|
||||
}
|
||||
return chatWithAI(input);
|
||||
},
|
||||
null,
|
||||
);
|
||||
return (
|
||||
<form>
|
||||
<div className="border border-gray-400 p-2 max-w-md">{state}</div>
|
||||
<input
|
||||
className="border border-gray-400 p-2"
|
||||
type="text"
|
||||
name="input"
|
||||
placeholder="Type your message here"
|
||||
/>
|
||||
<button
|
||||
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
|
||||
formAction={formAction}
|
||||
>
|
||||
Chat
|
||||
</button>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export function LocationCard() {
|
||||
return (
|
||||
<div className="border border-gray-400 p-2 max-w-md">
|
||||
<h1>Weather</h1>
|
||||
<p>San Francisco, CA</p>
|
||||
<p>Sunny</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
export function Spinner() {
|
||||
return (
|
||||
<div role="status">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="w-8 h-8 text-gray-200 animate-spin dark:text-gray-600 fill-blue-600"
|
||||
viewBox="0 0 100 101"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
|
||||
fill="currentFill"
|
||||
/>
|
||||
</svg>
|
||||
<span className="sr-only">Loading...</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import type { createStreamableUI } from "ai/rsc";
|
||||
import { AsyncLocalStorage } from "node:async_hooks";
|
||||
|
||||
type StreamableUI = ReturnType<typeof createStreamableUI>;
|
||||
|
||||
const streamUIAsyncLocalStorage = new AsyncLocalStorage<StreamableUI>();
|
||||
|
||||
export function getCurrentStreamableUI() {
|
||||
return streamUIAsyncLocalStorage.getStore();
|
||||
}
|
||||
|
||||
export function runWithStreamableUI<T>(streamUI: StreamableUI, fn: () => T): T {
|
||||
return streamUIAsyncLocalStorage.run(streamUI, fn);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { withNext } from "@llamaindex/autotool/next";
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {};
|
||||
|
||||
export default withNext(nextConfig);
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "@llamaindex/autotool-02-next-example",
|
||||
"private": true,
|
||||
"version": "0.1.2",
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@llamaindex/autotool": "workspace:*",
|
||||
"@radix-ui/react-slot": "^1.0.2",
|
||||
"ai": "^3.1.3",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"dotenv": "^16.3.1",
|
||||
"llamaindex": "workspace:*",
|
||||
"lucide-react": "^0.378.0",
|
||||
"next": "14.3.0-canary.51",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-markdown": "^9.0.1",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"sonner": "^1.4.41",
|
||||
"tailwind-merge": "^2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.12.11",
|
||||
"@types/react": "^18.3.1",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"@types/react-syntax-highlighter": "^15.5.11",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"cross-env": "^7.0.3",
|
||||
"postcss": "^8.4.32",
|
||||
"tailwindcss": "^3.3.6",
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
@@ -0,0 +1,78 @@
|
||||
import type { Config } from "tailwindcss";
|
||||
import { fontFamily } from "tailwindcss/defaultTheme";
|
||||
|
||||
const config: Config = {
|
||||
darkMode: ["class"],
|
||||
content: ["app/**/*.{ts,tsx}", "components/**/*.{ts,tsx}"],
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
padding: "2rem",
|
||||
screens: {
|
||||
"2xl": "1400px",
|
||||
},
|
||||
},
|
||||
extend: {
|
||||
colors: {
|
||||
border: "hsl(var(--border))",
|
||||
input: "hsl(var(--input))",
|
||||
ring: "hsl(var(--ring))",
|
||||
background: "hsl(var(--background))",
|
||||
foreground: "hsl(var(--foreground))",
|
||||
primary: {
|
||||
DEFAULT: "hsl(var(--primary))",
|
||||
foreground: "hsl(var(--primary-foreground))",
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: "hsl(var(--secondary))",
|
||||
foreground: "hsl(var(--secondary-foreground))",
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: "hsl(var(--destructive) / <alpha-value>)",
|
||||
foreground: "hsl(var(--destructive-foreground) / <alpha-value>)",
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: "hsl(var(--muted))",
|
||||
foreground: "hsl(var(--muted-foreground))",
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: "hsl(var(--accent))",
|
||||
foreground: "hsl(var(--accent-foreground))",
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: "hsl(var(--popover))",
|
||||
foreground: "hsl(var(--popover-foreground))",
|
||||
},
|
||||
card: {
|
||||
DEFAULT: "hsl(var(--card))",
|
||||
foreground: "hsl(var(--card-foreground))",
|
||||
},
|
||||
},
|
||||
borderRadius: {
|
||||
xl: `calc(var(--radius) + 4px)`,
|
||||
lg: `var(--radius)`,
|
||||
md: `calc(var(--radius) - 2px)`,
|
||||
sm: "calc(var(--radius) - 4px)",
|
||||
},
|
||||
fontFamily: {
|
||||
sans: ["var(--font-sans)", ...fontFamily.sans],
|
||||
},
|
||||
keyframes: {
|
||||
"accordion-down": {
|
||||
from: { height: "0" },
|
||||
to: { height: "var(--radix-accordion-content-height)" },
|
||||
},
|
||||
"accordion-up": {
|
||||
from: { height: "var(--radix-accordion-content-height)" },
|
||||
to: { height: "0" },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
"accordion-down": "accordion-down 0.2s ease-out",
|
||||
"accordion-up": "accordion-up 0.2s ease-out",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
export default config;
|
||||
@@ -0,0 +1,27 @@
|
||||
"use tool";
|
||||
import { getCurrentStreamableUI } from "@/context";
|
||||
|
||||
export async function getMyUserID() {
|
||||
const ui = getCurrentStreamableUI()!;
|
||||
ui.update("Getting user ID...");
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
return "12345";
|
||||
}
|
||||
|
||||
export async function showUserInfo(userId: string) {
|
||||
const ui = getCurrentStreamableUI()!;
|
||||
ui.update("Getting user info...");
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
ui.update(
|
||||
<div>
|
||||
User ID: {userId}
|
||||
<br />
|
||||
Name: John Doe
|
||||
</div>,
|
||||
);
|
||||
return `User ID: ${userId}\nName: John Doe\nEmail: alex@gmail.com\nPhone: 123-456-7890\nAddress: 123 Main St\nCity: San Francisco\nState: CA\nZip: 94105\nCountry: USA\n`;
|
||||
}
|
||||
|
||||
export function getWeather(address: string) {
|
||||
return `The weather in ${address} is sunny!`;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noEmit": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
},
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"name": "@llamaindex/autotool",
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"description": "auto transpile your JS function to LLM Agent compatible",
|
||||
"files": [
|
||||
"dist",
|
||||
"CHANGELOG.md"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"import": "./dist/index.js",
|
||||
"require": "./dist/index.cjs",
|
||||
"default": "./dist/index.js"
|
||||
},
|
||||
"./next": {
|
||||
"types": "./dist/next.d.ts",
|
||||
"import": "./dist/next.js",
|
||||
"require": "./dist/next.cjs",
|
||||
"default": "./dist/next.js"
|
||||
},
|
||||
"./webpack": {
|
||||
"types": "./dist/webpack.d.ts",
|
||||
"import": "./dist/webpack.js",
|
||||
"require": "./dist/webpack.cjs",
|
||||
"default": "./dist/webpack.js"
|
||||
},
|
||||
"./vite": {
|
||||
"types": "./dist/vite.d.ts",
|
||||
"import": "./dist/vite.js",
|
||||
"require": "./dist/vite.cjs",
|
||||
"default": "./dist/vite.js"
|
||||
},
|
||||
"./loader": {
|
||||
"types": "./dist/loader.d.ts",
|
||||
"import": "./dist/loader.js",
|
||||
"require": "./dist/loader.cjs",
|
||||
"default": "./dist/loader.js"
|
||||
},
|
||||
"./node": "./dist/node.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "bunchee",
|
||||
"dev": "bunchee --watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"@swc/core": "^1.5.5",
|
||||
"jotai": "^2.8.0",
|
||||
"typedoc": "^0.25.13",
|
||||
"unplugin": "^1.10.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"llamaindex": "^0.3.10",
|
||||
"openai": "^4",
|
||||
"typescript": "^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"openai": {
|
||||
"optional": true
|
||||
},
|
||||
"llamaindex": {
|
||||
"optional": true
|
||||
},
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@swc/types": "^0.1.6",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"@types/node": "^20.12.11",
|
||||
"bunchee": "^5.1.5",
|
||||
"llamaindex": "workspace:*",
|
||||
"next": "14.2.3",
|
||||
"rollup": "^4.17.2",
|
||||
"tsx": "^4.9.3",
|
||||
"typescript": "^5.4.5",
|
||||
"vitest": "^1.6.0",
|
||||
"webpack": "^5.91.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
import type {
|
||||
JSONSchema7,
|
||||
JSONSchema7Definition,
|
||||
JSONSchema7TypeName,
|
||||
} from "json-schema";
|
||||
import type { ToolMetadata } from "llamaindex";
|
||||
import type { SourceMapInput } from "rollup";
|
||||
import td from "typedoc";
|
||||
import type { SourceMapCompact } from "unplugin";
|
||||
import type { InfoString } from "./internal";
|
||||
|
||||
export const isToolFile = (url: string) => /tool\.[jt]sx?$/.test(url);
|
||||
export const isJSorTS = (url: string) => /\.m?[jt]sx?$/.test(url);
|
||||
|
||||
async function parseRoot(entryPoint: string) {
|
||||
const app = await td.Application.bootstrapWithPlugins(
|
||||
{
|
||||
entryPoints: [entryPoint],
|
||||
},
|
||||
[
|
||||
new td.TypeDocReader(),
|
||||
new td.PackageJsonReader(),
|
||||
new td.TSConfigReader(),
|
||||
],
|
||||
);
|
||||
const project = await app.convert();
|
||||
|
||||
if (project) {
|
||||
return app.serializer.projectToObject(project, process.cwd());
|
||||
}
|
||||
throw new Error("Failed to parse root");
|
||||
}
|
||||
|
||||
export async function transformAutoTool(
|
||||
code: string,
|
||||
url: string,
|
||||
): Promise<{
|
||||
code: string;
|
||||
map?: SourceMapInput | SourceMapCompact | null;
|
||||
}> {
|
||||
const json = await parseRoot(url);
|
||||
const children = json.children;
|
||||
if (Array.isArray(children)) {
|
||||
const schema = {
|
||||
type: "object",
|
||||
properties: {} as {
|
||||
[key: string]: JSONSchema7Definition;
|
||||
},
|
||||
additionalItems: false,
|
||||
required: [] as string[],
|
||||
} satisfies JSONSchema7;
|
||||
const info: InfoString = {
|
||||
originalFunction: undefined,
|
||||
parameterMapping: {},
|
||||
};
|
||||
children.forEach((child) => {
|
||||
// replace starting and ending quotes, to make it a function in the runtime
|
||||
info.originalFunction = child.name;
|
||||
const metadata: ToolMetadata = {
|
||||
name: child.name,
|
||||
description: "",
|
||||
parameters: schema,
|
||||
};
|
||||
child.signatures?.forEach((signature) => {
|
||||
const description = signature.comment?.summary
|
||||
.map((x) => x.text)
|
||||
.join("\n");
|
||||
if (description) {
|
||||
metadata.description += description;
|
||||
}
|
||||
signature.parameters?.map((parameter, idx) => {
|
||||
if (parameter.type?.type === "intrinsic") {
|
||||
// parameter.type.name
|
||||
schema.properties[parameter.name as string] = {
|
||||
type: parameter.type.name as JSONSchema7TypeName,
|
||||
description: parameter.comment?.summary
|
||||
.map((x) => x.text)
|
||||
.join("\n"),
|
||||
} as JSONSchema7Definition;
|
||||
schema.required.push(parameter.name as string);
|
||||
info.parameterMapping[parameter.name as string] = idx;
|
||||
}
|
||||
});
|
||||
});
|
||||
const infoJSON = JSON.stringify(info)
|
||||
// remove quotes from `originalFunction` value
|
||||
.replace(/"originalFunction":"(.*?)"/g, '"originalFunction":$1');
|
||||
code =
|
||||
code + `\ninjectMetadata(${JSON.stringify(metadata)}, ${infoJSON});`;
|
||||
});
|
||||
}
|
||||
if (
|
||||
!/^import\s+{\sinjectMetadata\s}\s+from\s+['"]@llamaindex\/tool['"]/.test(
|
||||
code,
|
||||
)
|
||||
) {
|
||||
code = `import {injectMetadata} from '@llamaindex/autotool';\n${code}`;
|
||||
}
|
||||
return {
|
||||
code,
|
||||
map: null,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import { atom } from "jotai/vanilla";
|
||||
import type { BaseToolWithCall, ToolMetadata } from "llamaindex";
|
||||
import type { ChatCompletionTool } from "openai/resources/chat/completions";
|
||||
import { store, toolMetadataAtom, toolsAtom, type Info } from "./internal";
|
||||
|
||||
export type { Info };
|
||||
|
||||
/**
|
||||
* @internal This function is used by the compiler to inject metadata into the source code.
|
||||
*/
|
||||
export function injectMetadata(metadata: ToolMetadata, info: Info) {
|
||||
store.get(toolMetadataAtom).push([metadata, info]);
|
||||
}
|
||||
|
||||
const openaiToolsAtom = atom<ChatCompletionTool[]>((get) => {
|
||||
const metadata = get(toolMetadataAtom);
|
||||
return metadata.map(([metadata]) => ({
|
||||
type: "function",
|
||||
function: {
|
||||
parameters: metadata.parameters,
|
||||
name: metadata.name,
|
||||
description: metadata.description,
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
||||
const llamaindexToolsAtom = atom<BaseToolWithCall[]>((get) => {
|
||||
const metadata = get(toolMetadataAtom);
|
||||
const fns = get(toolsAtom);
|
||||
return metadata.map(([metadata, info]) => ({
|
||||
call: (input: Record<string, unknown>) => {
|
||||
const args = Object.entries(info.parameterMapping).reduce(
|
||||
(arr, [name, idx]) => {
|
||||
arr[idx] = input[name];
|
||||
return arr;
|
||||
},
|
||||
[] as unknown[],
|
||||
);
|
||||
const fn = fns[metadata.name] ?? info.originalFunction;
|
||||
if (!fn) {
|
||||
throw new Error(`Cannot find function to call: ${metadata.name}`);
|
||||
}
|
||||
return fn(...args);
|
||||
},
|
||||
metadata,
|
||||
}));
|
||||
});
|
||||
|
||||
export function convertTools(format: "openai"): ChatCompletionTool[];
|
||||
export function convertTools(format: "llamaindex"): BaseToolWithCall[];
|
||||
export function convertTools(
|
||||
format: string,
|
||||
): ChatCompletionTool[] | BaseToolWithCall[] {
|
||||
switch (format) {
|
||||
case "openai": {
|
||||
return store.get(openaiToolsAtom);
|
||||
}
|
||||
case "llamaindex": {
|
||||
return store.get(llamaindexToolsAtom);
|
||||
}
|
||||
}
|
||||
throw new Error(`Unknown format: ${format}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call a tool by name with the given input.
|
||||
*/
|
||||
export function callTool(
|
||||
name: string,
|
||||
input: string | Record<string, unknown>,
|
||||
): unknown | Promise<unknown> {
|
||||
const tools = store.get(llamaindexToolsAtom);
|
||||
const targetTool = tools.find((tool) => tool.metadata.name === name);
|
||||
if (!targetTool) {
|
||||
throw new Error(`Cannot find tool: ${name}`);
|
||||
}
|
||||
return targetTool.call(
|
||||
// for OpenAI, input is a string
|
||||
// for ClaudeAI, input is an object
|
||||
typeof input === "string" ? JSON.parse(input) : input,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { atom, createStore } from "jotai/vanilla";
|
||||
import type { ToolMetadata } from "llamaindex";
|
||||
|
||||
export type Info = {
|
||||
originalFunction?: (...args: any[]) => any;
|
||||
/**
|
||||
* In current LLM, it doesn't support non-object parameter, so we mock arguments as object, and use this mapping to convert it back.
|
||||
*/
|
||||
parameterMapping: Record<string, number>;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is used in parser side to store the original function and parameter mapping.
|
||||
*
|
||||
* In the runtime, originalFunction is a JS function.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export type InfoString = {
|
||||
originalFunction?: string;
|
||||
parameterMapping: Record<string, number>;
|
||||
};
|
||||
|
||||
export const store = createStore();
|
||||
export const toolMetadataAtom = atom<[ToolMetadata, Info][]>([]);
|
||||
export const toolsAtom = atom<Record<string, (...args: any[]) => any>>({});
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* This is a node module loader hook that injects metadata into the source code.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
import { parse } from "@swc/core";
|
||||
import type { ExpressionStatement } from "@swc/types";
|
||||
import type { LoadHook } from "node:module";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { isJSorTS, isToolFile, transformAutoTool } from "./compiler";
|
||||
|
||||
export const load: LoadHook = async (url, context, nextLoad) => {
|
||||
const output = await nextLoad(url, context);
|
||||
if (typeof output.source === "string" && isJSorTS(url)) {
|
||||
const isTool = isToolFile(url);
|
||||
const hasToolDirective = (await parse(output.source)).body
|
||||
.filter(
|
||||
(node): node is ExpressionStatement =>
|
||||
node.type === "ExpressionStatement",
|
||||
)
|
||||
.some(
|
||||
(node) =>
|
||||
node.expression.type === "StringLiteral" &&
|
||||
node.expression.value === "use tool",
|
||||
);
|
||||
if (isTool || hasToolDirective) {
|
||||
const { code } = await transformAutoTool(
|
||||
output.source,
|
||||
fileURLToPath(url),
|
||||
);
|
||||
return {
|
||||
...output,
|
||||
source: code,
|
||||
};
|
||||
}
|
||||
}
|
||||
return output;
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
import type { NextConfig } from "next";
|
||||
import webpackPlugin from "./webpack";
|
||||
|
||||
export function withNext(config: NextConfig) {
|
||||
return {
|
||||
...config,
|
||||
webpack: (webpackConfig: any, context: any) => {
|
||||
webpackConfig = config.webpack?.(webpackConfig, context) ?? webpackConfig;
|
||||
webpackConfig.plugins.push(webpackPlugin());
|
||||
return webpackConfig;
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @example
|
||||
* ```shell
|
||||
* node --import @llamaindex/autotool/node ./dist/index.js
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```shell
|
||||
* node --import tsx --import @llamaindex/autotool/node ./src/index.ts
|
||||
* ```
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
import { register } from "node:module";
|
||||
|
||||
register("./loader.js", import.meta.url);
|
||||
@@ -0,0 +1,35 @@
|
||||
import { parse } from "@swc/core";
|
||||
import type { ExpressionStatement } from "@swc/types";
|
||||
import { createUnplugin, type UnpluginFactory } from "unplugin";
|
||||
import { isJSorTS, isToolFile, transformAutoTool } from "./compiler";
|
||||
|
||||
export interface Options {}
|
||||
|
||||
const name = "llama-index-tool";
|
||||
|
||||
export const unpluginFactory: UnpluginFactory<Options | undefined> = () => ({
|
||||
name,
|
||||
async transform(code, id) {
|
||||
if (!isJSorTS(id)) {
|
||||
return code;
|
||||
}
|
||||
const isTool = isToolFile(id);
|
||||
const hasToolDirective = (await parse(code)).body
|
||||
.filter(
|
||||
(node): node is ExpressionStatement =>
|
||||
node.type === "ExpressionStatement",
|
||||
)
|
||||
.some(
|
||||
(node) =>
|
||||
node.expression.type === "StringLiteral" &&
|
||||
node.expression.value === "use tool",
|
||||
);
|
||||
if (isTool || hasToolDirective) {
|
||||
return transformAutoTool(code, id);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const unplugin = /* #__PURE__ */ createUnplugin(unpluginFactory);
|
||||
|
||||
export default unplugin;
|
||||
@@ -0,0 +1,6 @@
|
||||
import { createVitePlugin } from "unplugin";
|
||||
import { unpluginFactory } from "./plugin";
|
||||
|
||||
const vitePlugin = createVitePlugin(unpluginFactory);
|
||||
|
||||
export default vitePlugin;
|
||||
@@ -0,0 +1,6 @@
|
||||
import { createWebpackPlugin } from "unplugin";
|
||||
import { unpluginFactory } from "./plugin";
|
||||
|
||||
const webpackPlugin = createWebpackPlugin(unpluginFactory);
|
||||
|
||||
export default webpackPlugin;
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"outDir": "./lib",
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["./src"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../core/tsconfig.json"
|
||||
},
|
||||
{
|
||||
"path": "../env/tsconfig.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,76 @@
|
||||
# llamaindex
|
||||
|
||||
## 0.3.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4aba02e: feat: support gpt4-o
|
||||
|
||||
## 0.3.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- c3747d0: fix: import `@xenova/transformers`
|
||||
|
||||
For now, if you use llamaindex in next.js, you need to add a plugin from `llamaindex/next` to ensure some module resolutions are correct.
|
||||
|
||||
## 0.3.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- ce94780: Add page number to read PDFs and use generated IDs for PDF and markdown content
|
||||
|
||||
## 0.3.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- b6a6606: feat: allow change host of ollama
|
||||
- b6a6606: chore: export ollama in default js runtime
|
||||
|
||||
## 0.3.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- efa326a: chore: update package.json
|
||||
- Updated dependencies [efa326a]
|
||||
- Updated dependencies [efa326a]
|
||||
- @llamaindex/env@0.1.2
|
||||
|
||||
## 0.3.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- bc7a11c: fix: inline ollama build
|
||||
- 2fe2b81: fix: filter with multiple filters in ChromaDB
|
||||
- 5596e31: feat: improve `@llamaindex/env`
|
||||
- e74fe88: fix: change <-> to <=> in the SELECT query
|
||||
- be5df5b: fix: anthropic agent on multiple chat
|
||||
- Updated dependencies [5596e31]
|
||||
- @llamaindex/env@0.1.1
|
||||
|
||||
## 0.3.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 1dce275: fix: export `StorageContext` on edge runtime
|
||||
- d10533e: feat: add hugging face llm
|
||||
- 2008efe: feat: add verbose mode to Agent
|
||||
- 5e61934: fix: remove clone object in `CallbackManager.dispatchEvent`
|
||||
- 9e74a43: feat: add top k to `asQueryEngine`
|
||||
- ee719a1: fix: streaming for ReAct Agent
|
||||
|
||||
## 0.3.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- e8c41c5: fix: wrong gemini streaming chat response
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 61103b6: fix: streaming for `Agent.createTask` API
|
||||
|
||||
## 0.3.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# @llamaindex/core-e2e
|
||||
|
||||
## 0.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- c3747d0: fix: import `@xenova/transformers`
|
||||
|
||||
For now, if you use llamaindex in next.js, you need to add a plugin from `llamaindex/next` to ensure some module resolutions are correct.
|
||||
|
||||
## 0.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- be5df5b: fix: anthropic agent on multiple chat
|
||||
|
||||
## 0.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 61103b6: fix: streaming for `Agent.createTask` API
|
||||
@@ -1,5 +1,78 @@
|
||||
# @llamaindex/cloudflare-worker-agent-test
|
||||
|
||||
## 0.0.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [4aba02e]
|
||||
- llamaindex@0.3.10
|
||||
|
||||
## 0.0.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [c3747d0]
|
||||
- llamaindex@0.3.9
|
||||
|
||||
## 0.0.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [ce94780]
|
||||
- llamaindex@0.3.8
|
||||
|
||||
## 0.0.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b6a6606]
|
||||
- Updated dependencies [b6a6606]
|
||||
- llamaindex@0.3.7
|
||||
|
||||
## 0.0.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [efa326a]
|
||||
- llamaindex@0.3.6
|
||||
|
||||
## 0.0.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [bc7a11c]
|
||||
- Updated dependencies [2fe2b81]
|
||||
- Updated dependencies [5596e31]
|
||||
- Updated dependencies [e74fe88]
|
||||
- Updated dependencies [be5df5b]
|
||||
- llamaindex@0.3.5
|
||||
|
||||
## 0.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1dce275]
|
||||
- Updated dependencies [d10533e]
|
||||
- Updated dependencies [2008efe]
|
||||
- Updated dependencies [5e61934]
|
||||
- Updated dependencies [9e74a43]
|
||||
- Updated dependencies [ee719a1]
|
||||
- llamaindex@0.3.4
|
||||
|
||||
## 0.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e8c41c5]
|
||||
- llamaindex@0.3.3
|
||||
|
||||
## 0.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [61103b6]
|
||||
- llamaindex@0.3.2
|
||||
|
||||
## 0.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@llamaindex/cloudflare-worker-agent-test",
|
||||
"version": "0.0.2",
|
||||
"version": "0.0.11",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -12,11 +12,13 @@
|
||||
"cf-typegen": "wrangler types"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cloudflare/vitest-pool-workers": "^0.2.3",
|
||||
"@cloudflare/workers-types": "^4.20240423.0",
|
||||
"@cloudflare/vitest-pool-workers": "^0.2.6",
|
||||
"@cloudflare/workers-types": "^4.20240502.0",
|
||||
"@vitest/runner": "1.3.0",
|
||||
"@vitest/snapshot": "1.3.0",
|
||||
"typescript": "^5.4.5",
|
||||
"vitest": "1.3.0",
|
||||
"wrangler": "^3.52.0"
|
||||
"wrangler": "^3.53.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"llamaindex": "workspace:*"
|
||||
|
||||
@@ -1,5 +1,82 @@
|
||||
# @llamaindex/next-agent-test
|
||||
|
||||
## 0.1.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [4aba02e]
|
||||
- llamaindex@0.3.10
|
||||
|
||||
## 0.1.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- c3747d0: fix: import `@xenova/transformers`
|
||||
|
||||
For now, if you use llamaindex in next.js, you need to add a plugin from `llamaindex/next` to ensure some module resolutions are correct.
|
||||
|
||||
- Updated dependencies [c3747d0]
|
||||
- llamaindex@0.3.9
|
||||
|
||||
## 0.1.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [ce94780]
|
||||
- llamaindex@0.3.8
|
||||
|
||||
## 0.1.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b6a6606]
|
||||
- Updated dependencies [b6a6606]
|
||||
- llamaindex@0.3.7
|
||||
|
||||
## 0.1.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [efa326a]
|
||||
- llamaindex@0.3.6
|
||||
|
||||
## 0.1.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [bc7a11c]
|
||||
- Updated dependencies [2fe2b81]
|
||||
- Updated dependencies [5596e31]
|
||||
- Updated dependencies [e74fe88]
|
||||
- Updated dependencies [be5df5b]
|
||||
- llamaindex@0.3.5
|
||||
|
||||
## 0.1.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1dce275]
|
||||
- Updated dependencies [d10533e]
|
||||
- Updated dependencies [2008efe]
|
||||
- Updated dependencies [5e61934]
|
||||
- Updated dependencies [9e74a43]
|
||||
- Updated dependencies [ee719a1]
|
||||
- llamaindex@0.3.4
|
||||
|
||||
## 0.1.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e8c41c5]
|
||||
- llamaindex@0.3.3
|
||||
|
||||
## 0.1.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [61103b6]
|
||||
- llamaindex@0.3.2
|
||||
|
||||
## 0.1.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {};
|
||||
|
||||
export default nextConfig;
|
||||
import withLlamaIndex from "llamaindex/next";
|
||||
|
||||
export default withLlamaIndex(nextConfig);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@llamaindex/next-agent-test",
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.11",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
@@ -9,20 +9,20 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"ai": "^3.0.34",
|
||||
"ai": "^3.1.3",
|
||||
"llamaindex": "workspace:*",
|
||||
"next": "14.2.3",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18.2.79",
|
||||
"@types/react-dom": "^18.2.25",
|
||||
"eslint": "^8",
|
||||
"@types/node": "^20.12.11",
|
||||
"@types/react": "^18.3.1",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-next": "14.2.3",
|
||||
"postcss": "^8",
|
||||
"tailwindcss": "^3.4.1",
|
||||
"typescript": "^5"
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,35 @@
|
||||
# test-edge-runtime
|
||||
|
||||
## 0.1.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [4aba02e]
|
||||
- llamaindex@0.3.10
|
||||
|
||||
## 0.1.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- c3747d0: fix: import `@xenova/transformers`
|
||||
|
||||
For now, if you use llamaindex in next.js, you need to add a plugin from `llamaindex/next` to ensure some module resolutions are correct.
|
||||
|
||||
- Updated dependencies [c3747d0]
|
||||
- llamaindex@0.3.9
|
||||
|
||||
## 0.1.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @llamaindex/edge@0.3.6
|
||||
|
||||
## 0.1.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @llamaindex/edge@0.3.5
|
||||
|
||||
## 0.1.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {};
|
||||
|
||||
export default nextConfig;
|
||||
import withLlamaIndex from "llamaindex/next";
|
||||
|
||||
export default withLlamaIndex(nextConfig);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@llamaindex/nextjs-edge-runtime-test",
|
||||
"version": "0.1.6",
|
||||
"version": "0.1.10",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
@@ -8,15 +8,15 @@
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@llamaindex/edge": "workspace:*",
|
||||
"next": "14.1.3",
|
||||
"react": "^18",
|
||||
"react-dom": "^18"
|
||||
"llamaindex": "workspace:*",
|
||||
"next": "14.2.3",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.12.7",
|
||||
"@types/react": "^18.2.79",
|
||||
"@types/react-dom": "^18.2.25",
|
||||
"typescript": "^5"
|
||||
"@types/node": "^20.12.11",
|
||||
"@types/react": "^18.3.1",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,232 +0,0 @@
|
||||
.main {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 6rem;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.description {
|
||||
display: inherit;
|
||||
justify-content: inherit;
|
||||
align-items: inherit;
|
||||
font-size: 0.85rem;
|
||||
max-width: var(--max-width);
|
||||
width: 100%;
|
||||
z-index: 2;
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
.description a {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.description p {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 1rem;
|
||||
background-color: rgba(var(--callout-rgb), 0.5);
|
||||
border: 1px solid rgba(var(--callout-border-rgb), 0.3);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.code {
|
||||
font-weight: 700;
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(25%, auto));
|
||||
max-width: 100%;
|
||||
width: var(--max-width);
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 1rem 1.2rem;
|
||||
border-radius: var(--border-radius);
|
||||
background: rgba(var(--card-rgb), 0);
|
||||
border: 1px solid rgba(var(--card-border-rgb), 0);
|
||||
transition:
|
||||
background 200ms,
|
||||
border 200ms;
|
||||
}
|
||||
|
||||
.card span {
|
||||
display: inline-block;
|
||||
transition: transform 200ms;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.7rem;
|
||||
}
|
||||
|
||||
.card p {
|
||||
margin: 0;
|
||||
opacity: 0.6;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.5;
|
||||
max-width: 30ch;
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
.center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
padding: 4rem 0;
|
||||
}
|
||||
|
||||
.center::before {
|
||||
background: var(--secondary-glow);
|
||||
border-radius: 50%;
|
||||
width: 480px;
|
||||
height: 360px;
|
||||
margin-left: -400px;
|
||||
}
|
||||
|
||||
.center::after {
|
||||
background: var(--primary-glow);
|
||||
width: 240px;
|
||||
height: 180px;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.center::before,
|
||||
.center::after {
|
||||
content: "";
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
filter: blur(45px);
|
||||
transform: translateZ(0);
|
||||
}
|
||||
|
||||
.logo {
|
||||
position: relative;
|
||||
}
|
||||
/* Enable hover only on non-touch devices */
|
||||
@media (hover: hover) and (pointer: fine) {
|
||||
.card:hover {
|
||||
background: rgba(var(--card-rgb), 0.1);
|
||||
border: 1px solid rgba(var(--card-border-rgb), 0.15);
|
||||
}
|
||||
|
||||
.card:hover span {
|
||||
transform: translateX(4px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion) {
|
||||
.card:hover span {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile */
|
||||
@media (max-width: 700px) {
|
||||
.content {
|
||||
padding: 4rem;
|
||||
}
|
||||
|
||||
.grid {
|
||||
grid-template-columns: 1fr;
|
||||
margin-bottom: 120px;
|
||||
max-width: 320px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 1rem 2.5rem;
|
||||
}
|
||||
|
||||
.card h2 {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.center {
|
||||
padding: 8rem 0 6rem;
|
||||
}
|
||||
|
||||
.center::before {
|
||||
transform: none;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.description a {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.description p,
|
||||
.description div {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.description p {
|
||||
align-items: center;
|
||||
inset: 0 0 auto;
|
||||
padding: 2rem 1rem 1.4rem;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
border-bottom: 1px solid rgba(var(--callout-border-rgb), 0.25);
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
rgba(var(--background-start-rgb), 1),
|
||||
rgba(var(--callout-rgb), 0.5)
|
||||
);
|
||||
background-clip: padding-box;
|
||||
backdrop-filter: blur(24px);
|
||||
}
|
||||
|
||||
.description div {
|
||||
align-items: flex-end;
|
||||
pointer-events: none;
|
||||
inset: auto 0 0;
|
||||
padding: 2rem;
|
||||
height: 200px;
|
||||
background: linear-gradient(
|
||||
to bottom,
|
||||
transparent 0%,
|
||||
rgb(var(--background-end-rgb)) 40%
|
||||
);
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Tablet and Smaller Desktop */
|
||||
@media (min-width: 701px) and (max-width: 1120px) {
|
||||
.grid {
|
||||
grid-template-columns: repeat(2, 50%);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.vercelLogo {
|
||||
filter: invert(1);
|
||||
}
|
||||
|
||||
.logo {
|
||||
filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
from {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
}
|
||||
@@ -1,98 +1,20 @@
|
||||
import Image from "next/image";
|
||||
import "../utils/llm";
|
||||
import styles from "./page.module.css";
|
||||
import { tokenizerResultPromise } from "@/utils/llm";
|
||||
import { use } from "react";
|
||||
|
||||
export const runtime = "edge";
|
||||
|
||||
export default function Home() {
|
||||
const result = use(tokenizerResultPromise);
|
||||
return (
|
||||
<main className={styles.main}>
|
||||
<div className={styles.description}>
|
||||
<p>
|
||||
Get started by editing
|
||||
<code className={styles.code}>src/app/page.tsx</code>
|
||||
</p>
|
||||
<main>
|
||||
<div>
|
||||
<h1>Next.js Edge Runtime</h1>
|
||||
<div>
|
||||
<a
|
||||
href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
By{" "}
|
||||
<Image
|
||||
src="/vercel.svg"
|
||||
alt="Vercel Logo"
|
||||
className={styles.vercelLogo}
|
||||
width={100}
|
||||
height={24}
|
||||
priority
|
||||
/>
|
||||
</a>
|
||||
{result.map((value, index) => (
|
||||
<span key={index}>{value}</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={styles.center}>
|
||||
<Image
|
||||
className={styles.logo}
|
||||
src="/next.svg"
|
||||
alt="Next.js Logo"
|
||||
width={180}
|
||||
height={37}
|
||||
priority
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className={styles.grid}>
|
||||
<a
|
||||
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className={styles.card}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2>
|
||||
Docs <span>-></span>
|
||||
</h2>
|
||||
<p>Find in-depth information about Next.js features and API.</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className={styles.card}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2>
|
||||
Learn <span>-></span>
|
||||
</h2>
|
||||
<p>Learn about Next.js in an interactive course with quizzes!</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className={styles.card}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2>
|
||||
Templates <span>-></span>
|
||||
</h2>
|
||||
<p>Explore starter templates for Next.js.</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
|
||||
className={styles.card}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<h2>
|
||||
Deploy <span>-></span>
|
||||
</h2>
|
||||
<p>
|
||||
Instantly deploy your Next.js site to a shareable URL with Vercel.
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,23 @@
|
||||
"use server";
|
||||
// test runtime
|
||||
import "llamaindex";
|
||||
import { ClipEmbedding } from "llamaindex/embeddings/ClipEmbedding";
|
||||
import "llamaindex/readers/SimpleDirectoryReader";
|
||||
|
||||
// @ts-expect-error
|
||||
if (typeof EdgeRuntime !== "string") {
|
||||
throw new Error("Expected run in EdgeRuntime");
|
||||
}
|
||||
|
||||
export const tokenizerResultPromise = new Promise<number[]>(
|
||||
(resolve, reject) => {
|
||||
const embedding = new ClipEmbedding();
|
||||
//#region make sure @xenova/transformers is working in edge runtime
|
||||
embedding
|
||||
.getTokenizer()
|
||||
.then((tokenizer) => {
|
||||
resolve(tokenizer.encode("hello world"));
|
||||
})
|
||||
.catch(reject);
|
||||
//#endregion
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"outDir": "./dist",
|
||||
"allowJs": true,
|
||||
|
||||
@@ -1,5 +1,78 @@
|
||||
# @llamaindex/waku-query-engine-test
|
||||
|
||||
## 0.0.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [4aba02e]
|
||||
- llamaindex@0.3.10
|
||||
|
||||
## 0.0.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [c3747d0]
|
||||
- llamaindex@0.3.9
|
||||
|
||||
## 0.0.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [ce94780]
|
||||
- llamaindex@0.3.8
|
||||
|
||||
## 0.0.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b6a6606]
|
||||
- Updated dependencies [b6a6606]
|
||||
- llamaindex@0.3.7
|
||||
|
||||
## 0.0.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [efa326a]
|
||||
- llamaindex@0.3.6
|
||||
|
||||
## 0.0.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [bc7a11c]
|
||||
- Updated dependencies [2fe2b81]
|
||||
- Updated dependencies [5596e31]
|
||||
- Updated dependencies [e74fe88]
|
||||
- Updated dependencies [be5df5b]
|
||||
- llamaindex@0.3.5
|
||||
|
||||
## 0.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1dce275]
|
||||
- Updated dependencies [d10533e]
|
||||
- Updated dependencies [2008efe]
|
||||
- Updated dependencies [5e61934]
|
||||
- Updated dependencies [9e74a43]
|
||||
- Updated dependencies [ee719a1]
|
||||
- llamaindex@0.3.4
|
||||
|
||||
## 0.0.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e8c41c5]
|
||||
- llamaindex@0.3.3
|
||||
|
||||
## 0.0.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [61103b6]
|
||||
- llamaindex@0.3.2
|
||||
|
||||
## 0.0.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@llamaindex/waku-query-engine-test",
|
||||
"version": "0.0.2",
|
||||
"version": "0.0.11",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@@ -16,10 +16,10 @@
|
||||
"waku": "0.20.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "18.2.74",
|
||||
"@types/react-dom": "18.2.24",
|
||||
"@types/react": "18.3.1",
|
||||
"@types/react-dom": "18.3.0",
|
||||
"autoprefixer": "10.4.19",
|
||||
"tailwindcss": "3.4.3",
|
||||
"typescript": "5.4.4"
|
||||
"typescript": "5.4.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import { AnthropicAgent } from "llamaindex/agent/anthropic";
|
||||
import { extractText } from "llamaindex/llm/utils";
|
||||
import { ok, strictEqual } from "node:assert";
|
||||
import { beforeEach, test } from "node:test";
|
||||
import { sumNumbersTool } from "./fixtures/tools.js";
|
||||
import { getWeatherTool, sumNumbersTool } from "./fixtures/tools.js";
|
||||
import { mockLLMEvent } from "./utils.js";
|
||||
|
||||
let llm: LLM;
|
||||
@@ -118,14 +118,58 @@ await test("anthropic agent", async (t) => {
|
||||
});
|
||||
|
||||
await t.test("sum numbers", async () => {
|
||||
const openaiAgent = new AnthropicAgent({
|
||||
const anthropicAgent = new AnthropicAgent({
|
||||
tools: [sumNumbersTool],
|
||||
});
|
||||
|
||||
const { response } = await openaiAgent.chat({
|
||||
const { response } = await anthropicAgent.chat({
|
||||
message: "how much is 1 + 1?",
|
||||
});
|
||||
|
||||
ok(extractText(response.message.content).includes("2"));
|
||||
});
|
||||
});
|
||||
|
||||
await test("anthropic agent with multiple chat", async (t) => {
|
||||
await mockLLMEvent(t, "anthropic-agent-multiple-chat");
|
||||
await t.test("chat", async () => {
|
||||
const agent = new AnthropicAgent({
|
||||
tools: [getWeatherTool],
|
||||
});
|
||||
{
|
||||
const { response } = await agent.chat({
|
||||
message: 'Hello? Response to me "Yes"',
|
||||
});
|
||||
consola.debug("response:", response.message.content);
|
||||
ok(extractText(response.message.content).includes("Yes"));
|
||||
}
|
||||
{
|
||||
const { response } = await agent.chat({
|
||||
message: 'Hello? Response to me "No"',
|
||||
});
|
||||
consola.debug("response:", response.message.content);
|
||||
ok(extractText(response.message.content).includes("No"));
|
||||
}
|
||||
{
|
||||
const { response } = await agent.chat({
|
||||
message: 'Hello? Response to me "Maybe"',
|
||||
});
|
||||
consola.debug("response:", response.message.content);
|
||||
ok(extractText(response.message.content).includes("Maybe"));
|
||||
}
|
||||
{
|
||||
const { response } = await agent.chat({
|
||||
message: "What is the weather in San Francisco?",
|
||||
});
|
||||
consola.debug("response:", response.message.content);
|
||||
ok(extractText(response.message.content).includes("72"));
|
||||
}
|
||||
{
|
||||
const { response } = await agent.chat({
|
||||
message: "What is the weather in Shanghai?",
|
||||
});
|
||||
consola.debug("response:", response.message.content);
|
||||
ok(extractText(response.message.content).includes("72"));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -27,3 +27,23 @@ await test("react agent", async (t) => {
|
||||
ok(extractText(response.message.content).includes("72"));
|
||||
});
|
||||
});
|
||||
|
||||
await test("react agent stream", async (t) => {
|
||||
await mockLLMEvent(t, "react-agent-stream");
|
||||
await t.test("get weather", async () => {
|
||||
const agent = new ReActAgent({
|
||||
tools: [getWeatherTool],
|
||||
});
|
||||
|
||||
const stream = await agent.chat({
|
||||
stream: true,
|
||||
message: "What is the weather like in San Francisco?",
|
||||
});
|
||||
|
||||
let content = "";
|
||||
for await (const { response } of stream) {
|
||||
content += response.delta;
|
||||
}
|
||||
ok(content.includes("72"));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,552 @@
|
||||
{
|
||||
"llmEventStart": [
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello? Response to me \"Yes\""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello? Response to me \"Yes\""
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has not asked a question that requires using any of the available tools. They have simply requested that I respond with the word \"Yes\".\n</thinking>\n\nYes"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello? Response to me \"No\""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_2",
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello? Response to me \"Yes\""
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has not asked a question that requires using any of the available tools. They have simply requested that I respond with the word \"Yes\".\n</thinking>\n\nYes"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello? Response to me \"No\""
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has not asked a question that requires using any of the available tools. They have simply requested that I respond with the word \"No\".\n</thinking>\n\nNo"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello? Response to me \"Maybe\""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_3",
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello? Response to me \"Yes\""
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has not asked a question that requires using any of the available tools. They have simply requested that I respond with the word \"Yes\".\n</thinking>\n\nYes"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello? Response to me \"No\""
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has not asked a question that requires using any of the available tools. They have simply requested that I respond with the word \"No\".\n</thinking>\n\nNo"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello? Response to me \"Maybe\""
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has not asked a question that requires using any of the available tools. They have simply requested that I respond with the word \"Maybe\".\n</thinking>\n\nMaybe"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "What is the weather in San Francisco?"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_4",
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello? Response to me \"Yes\""
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has not asked a question that requires using any of the available tools. They have simply requested that I respond with the word \"Yes\".\n</thinking>\n\nYes"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello? Response to me \"No\""
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has not asked a question that requires using any of the available tools. They have simply requested that I respond with the word \"No\".\n</thinking>\n\nNo"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello? Response to me \"Maybe\""
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has not asked a question that requires using any of the available tools. They have simply requested that I respond with the word \"Maybe\".\n</thinking>\n\nMaybe"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "What is the weather in San Francisco?"
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has asked for the weather in a specific city, San Francisco. The relevant tool to answer this is the getWeather function.\n\nLooking at the required parameters for getWeather:\ncity (string): The user directly provided the city \"San Francisco\"\n\nSince the required \"city\" parameter has been provided, we can proceed with the getWeather function call.\n</thinking>"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {
|
||||
"toolCall": {
|
||||
"id": "toolu_01Gy7Gxbx7uGmjVncGH6pubL",
|
||||
"name": "getWeather",
|
||||
"input": {
|
||||
"city": "San Francisco"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": "The weather in San Francisco is 72 degrees",
|
||||
"role": "user",
|
||||
"options": {
|
||||
"toolResult": {
|
||||
"result": "The weather in San Francisco is 72 degrees",
|
||||
"isError": false,
|
||||
"id": "toolu_01Gy7Gxbx7uGmjVncGH6pubL"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_5",
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello? Response to me \"Yes\""
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has not asked a question that requires using any of the available tools. They have simply requested that I respond with the word \"Yes\".\n</thinking>\n\nYes"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello? Response to me \"No\""
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has not asked a question that requires using any of the available tools. They have simply requested that I respond with the word \"No\".\n</thinking>\n\nNo"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello? Response to me \"Maybe\""
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has not asked a question that requires using any of the available tools. They have simply requested that I respond with the word \"Maybe\".\n</thinking>\n\nMaybe"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "What is the weather in San Francisco?"
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has asked for the weather in a specific city, San Francisco. The relevant tool to answer this is the getWeather function.\n\nLooking at the required parameters for getWeather:\ncity (string): The user directly provided the city \"San Francisco\"\n\nSince the required \"city\" parameter has been provided, we can proceed with the getWeather function call.\n</thinking>"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {
|
||||
"toolCall": {
|
||||
"id": "toolu_01Gy7Gxbx7uGmjVncGH6pubL",
|
||||
"name": "getWeather",
|
||||
"input": {
|
||||
"city": "San Francisco"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": "The weather in San Francisco is 72 degrees",
|
||||
"role": "user",
|
||||
"options": {
|
||||
"toolResult": {
|
||||
"result": "The weather in San Francisco is 72 degrees",
|
||||
"isError": false,
|
||||
"id": "toolu_01Gy7Gxbx7uGmjVncGH6pubL"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "The current weather in San Francisco is 72 degrees."
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "What is the weather in Shanghai?"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_6",
|
||||
"messages": [
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello? Response to me \"Yes\""
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has not asked a question that requires using any of the available tools. They have simply requested that I respond with the word \"Yes\".\n</thinking>\n\nYes"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello? Response to me \"No\""
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has not asked a question that requires using any of the available tools. They have simply requested that I respond with the word \"No\".\n</thinking>\n\nNo"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Hello? Response to me \"Maybe\""
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has not asked a question that requires using any of the available tools. They have simply requested that I respond with the word \"Maybe\".\n</thinking>\n\nMaybe"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "What is the weather in San Francisco?"
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has asked for the weather in a specific city, San Francisco. The relevant tool to answer this is the getWeather function.\n\nLooking at the required parameters for getWeather:\ncity (string): The user directly provided the city \"San Francisco\"\n\nSince the required \"city\" parameter has been provided, we can proceed with the getWeather function call.\n</thinking>"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {
|
||||
"toolCall": {
|
||||
"id": "toolu_01Gy7Gxbx7uGmjVncGH6pubL",
|
||||
"name": "getWeather",
|
||||
"input": {
|
||||
"city": "San Francisco"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": "The weather in San Francisco is 72 degrees",
|
||||
"role": "user",
|
||||
"options": {
|
||||
"toolResult": {
|
||||
"result": "The weather in San Francisco is 72 degrees",
|
||||
"isError": false,
|
||||
"id": "toolu_01Gy7Gxbx7uGmjVncGH6pubL"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "The current weather in San Francisco is 72 degrees."
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "What is the weather in Shanghai?"
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has asked for the weather in a specific city, Shanghai. The relevant tool to answer this is the getWeather function.\n\nLooking at the required parameters for getWeather:\ncity (string): The user directly provided the city \"Shanghai\"\n\nSince the required \"city\" parameter has been provided, we can proceed with the getWeather function call.\n</thinking>"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {
|
||||
"toolCall": {
|
||||
"id": "toolu_01NHyahSUqrPjxQk9mvCvvGe",
|
||||
"name": "getWeather",
|
||||
"input": {
|
||||
"city": "Shanghai"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"content": "The weather in Shanghai is 72 degrees",
|
||||
"role": "user",
|
||||
"options": {
|
||||
"toolResult": {
|
||||
"result": "The weather in Shanghai is 72 degrees",
|
||||
"isError": false,
|
||||
"id": "toolu_01NHyahSUqrPjxQk9mvCvvGe"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"llmEventEnd": [
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"response": {
|
||||
"raw": null,
|
||||
"message": {
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has not asked a question that requires using any of the available tools. They have simply requested that I respond with the word \"Yes\".\n</thinking>\n\nYes"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"response": {
|
||||
"raw": null,
|
||||
"message": {
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has not asked a question that requires using any of the available tools. They have simply requested that I respond with the word \"No\".\n</thinking>\n\nNo"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_2",
|
||||
"response": {
|
||||
"raw": null,
|
||||
"message": {
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has not asked a question that requires using any of the available tools. They have simply requested that I respond with the word \"Maybe\".\n</thinking>\n\nMaybe"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_3",
|
||||
"response": {
|
||||
"raw": null,
|
||||
"message": {
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has asked for the weather in a specific city, San Francisco. The relevant tool to answer this is the getWeather function.\n\nLooking at the required parameters for getWeather:\ncity (string): The user directly provided the city \"San Francisco\"\n\nSince the required \"city\" parameter has been provided, we can proceed with the getWeather function call.\n</thinking>"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {
|
||||
"toolCall": {
|
||||
"id": "toolu_01Gy7Gxbx7uGmjVncGH6pubL",
|
||||
"name": "getWeather",
|
||||
"input": {
|
||||
"city": "San Francisco"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_4",
|
||||
"response": {
|
||||
"raw": null,
|
||||
"message": {
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "The current weather in San Francisco is 72 degrees."
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_5",
|
||||
"response": {
|
||||
"raw": null,
|
||||
"message": {
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>\nThe user has asked for the weather in a specific city, Shanghai. The relevant tool to answer this is the getWeather function.\n\nLooking at the required parameters for getWeather:\ncity (string): The user directly provided the city \"Shanghai\"\n\nSince the required \"city\" parameter has been provided, we can proceed with the getWeather function call.\n</thinking>"
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {
|
||||
"toolCall": {
|
||||
"id": "toolu_01NHyahSUqrPjxQk9mvCvvGe",
|
||||
"name": "getWeather",
|
||||
"input": {
|
||||
"city": "Shanghai"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_6",
|
||||
"response": {
|
||||
"raw": null,
|
||||
"message": {
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "The current weather in Shanghai is 72 degrees."
|
||||
}
|
||||
],
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"llmEventStream": []
|
||||
}
|
||||
@@ -0,0 +1,488 @@
|
||||
{
|
||||
"llmEventStart": [
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are designed to help with a variety of tasks, from answering questions to providing summaries to other types of analyses.\n\n## Tools\nYou have access to a wide variety of tools. You are responsible for using\nthe tools in any sequence you deem appropriate to complete the task at hand.\nThis may require breaking the task into subtasks and using different tools\nto complete each subtask.\n\nYou have access to the following tools:\n- getWeather: Get the weather for a city with schema: {\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\",\"description\":\"The city to get the weather for\"}},\"required\":[\"city\"]}\n\n## Output Format\nTo answer the question, please use the following format.\n\n\"\"\"\nThought: I need to use a tool to help me answer the question.\nAction: tool name (one of getWeather) if using a tool.\nAction Input: the input to the tool, in a JSON format representing the kwargs (e.g. {{\"input\": \"hello world\", \"num_beams\": 5}})\n\"\"\"\n\nPlease ALWAYS start with a Thought.\n\nPlease use a valid JSON format for the Action Input. Do NOT do this {{'input': 'hello world', 'num_beams': 5}}.\n\nIf this format is used, the user will respond in the following format:\n\n\"\"\"\"\nObservation: tool response\n\"\"\"\"\n\nYou should keep repeating the above format until you have enough information\nto answer the question without using any more tools. At that point, you MUST respond\nin the one of the following two formats:\n\n\"\"\"\"\nThought: I can answer without using any more tools.\nAnswer: [your answer here]\n\"\"\"\"\n\n\"\"\"\"\nThought: I cannot answer the question with the provided tools.\nAnswer: Sorry, I cannot answer your query.\n\"\"\"\"\n\n## Current Conversation\nBelow is the current conversation consisting of interleaving human and assistant messages."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "What is the weather like in San Francisco?"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"messages": [
|
||||
{
|
||||
"role": "system",
|
||||
"content": "You are designed to help with a variety of tasks, from answering questions to providing summaries to other types of analyses.\n\n## Tools\nYou have access to a wide variety of tools. You are responsible for using\nthe tools in any sequence you deem appropriate to complete the task at hand.\nThis may require breaking the task into subtasks and using different tools\nto complete each subtask.\n\nYou have access to the following tools:\n- getWeather: Get the weather for a city with schema: {\"type\":\"object\",\"properties\":{\"city\":{\"type\":\"string\",\"description\":\"The city to get the weather for\"}},\"required\":[\"city\"]}\n\n## Output Format\nTo answer the question, please use the following format.\n\n\"\"\"\nThought: I need to use a tool to help me answer the question.\nAction: tool name (one of getWeather) if using a tool.\nAction Input: the input to the tool, in a JSON format representing the kwargs (e.g. {{\"input\": \"hello world\", \"num_beams\": 5}})\n\"\"\"\n\nPlease ALWAYS start with a Thought.\n\nPlease use a valid JSON format for the Action Input. Do NOT do this {{'input': 'hello world', 'num_beams': 5}}.\n\nIf this format is used, the user will respond in the following format:\n\n\"\"\"\"\nObservation: tool response\n\"\"\"\"\n\nYou should keep repeating the above format until you have enough information\nto answer the question without using any more tools. At that point, you MUST respond\nin the one of the following two formats:\n\n\"\"\"\"\nThought: I can answer without using any more tools.\nAnswer: [your answer here]\n\"\"\"\"\n\n\"\"\"\"\nThought: I cannot answer the question with the provided tools.\nAnswer: Sorry, I cannot answer your query.\n\"\"\"\"\n\n## Current Conversation\nBelow is the current conversation consisting of interleaving human and assistant messages."
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "What is the weather like in San Francisco?"
|
||||
},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "Thought: I need to use a tool to help me answer the question.\nAction: getWeather\nInput: {\n city: San Francisco\n}"
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": "Observation: The weather in San Francisco is 72 degrees"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"llmEventEnd": [
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"response": {
|
||||
"raw": null,
|
||||
"message": {
|
||||
"content": "Thought: I need to use a tool to help me answer the question.\nAction: getWeather\nAction Input: {\"city\": \"San Francisco\"}",
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"response": {
|
||||
"raw": null,
|
||||
"message": {
|
||||
"content": "Thought: I can answer without using any more tools.\nAnswer: The weather in San Francisco is 72 degrees.",
|
||||
"role": "assistant",
|
||||
"options": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"llmEventStream": [
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": "Thought"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": ":"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " I"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " need"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " to"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " use"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " tool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " to"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " help"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " me"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " answer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " the"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " question"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": ".\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": "Action"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": ":"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " get"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": "Weather"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": "\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": "Action"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " Input"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": ":"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " {\""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": "city"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": "\":"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " \""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": "San"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " Francisco"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_0",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": "\"}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": "Thought"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": ":"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " I"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " can"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " answer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " without"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " using"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " any"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " more"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " tools"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": ".\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": "Answer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": ":"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " The"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " weather"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " in"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " San"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " Francisco"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " is"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " "
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": "72"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": " degrees"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "PRESERVE_1",
|
||||
"chunk": {
|
||||
"raw": null,
|
||||
"options": {},
|
||||
"delta": "."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@llamaindex/core-e2e",
|
||||
"private": true,
|
||||
"version": "0.0.2",
|
||||
"version": "0.0.5",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"e2e": "node --import tsx --import ./mock-register.js --test ./node/*.e2e.ts",
|
||||
@@ -10,9 +10,9 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@faker-js/faker": "^8.4.1",
|
||||
"@types/node": "^20.12.7",
|
||||
"@types/node": "^20.12.11",
|
||||
"consola": "^3.2.3",
|
||||
"llamaindex": "workspace:*",
|
||||
"tsx": "^4.7.2"
|
||||
"tsx": "^4.9.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
{
|
||||
"name": "@llamaindex/core",
|
||||
"version": "0.3.0",
|
||||
"version": "0.3.10",
|
||||
"exports": "./src/index.ts",
|
||||
"imports": {
|
||||
"@llamaindex/env": "jsr:@llamaindex/env@0.0.6"
|
||||
"@llamaindex/env": "jsr:@llamaindex/env@0.1.2"
|
||||
},
|
||||
"publish": {
|
||||
"include": ["LICENSE", "README.md", "src/**/*", "jsr.json"]
|
||||
}
|
||||
}
|
||||
|
||||
+36
-20
@@ -1,48 +1,64 @@
|
||||
{
|
||||
"name": "llamaindex",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.10",
|
||||
"expectedMinorVersion": "3",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"keywords": [
|
||||
"llm",
|
||||
"llama",
|
||||
"openai",
|
||||
"gpt",
|
||||
"data science",
|
||||
"prompt",
|
||||
"prompt engineering",
|
||||
"chatgpt",
|
||||
"machine learning",
|
||||
"ml",
|
||||
"embedding",
|
||||
"vectorstore",
|
||||
"data framework",
|
||||
"llamaindex"
|
||||
],
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.20.6",
|
||||
"@anthropic-ai/sdk": "^0.20.9",
|
||||
"@aws-crypto/sha256-js": "^5.2.0",
|
||||
"@datastax/astra-db-ts": "^1.0.1",
|
||||
"@google/generative-ai": "^0.8.0",
|
||||
"@grpc/grpc-js": "^1.10.6",
|
||||
"@datastax/astra-db-ts": "^1.1.0",
|
||||
"@google/generative-ai": "^0.11.0",
|
||||
"@grpc/grpc-js": "^1.10.7",
|
||||
"@huggingface/inference": "^2.6.7",
|
||||
"@llamaindex/cloud": "0.0.5",
|
||||
"@llamaindex/env": "workspace:*",
|
||||
"@mistralai/mistralai": "^0.1.3",
|
||||
"@mistralai/mistralai": "^0.2.0",
|
||||
"@pinecone-database/pinecone": "^2.2.0",
|
||||
"@qdrant/js-client-rest": "^1.8.2",
|
||||
"@types/lodash": "^4.17.0",
|
||||
"@qdrant/js-client-rest": "^1.9.0",
|
||||
"@types/lodash": "^4.17.1",
|
||||
"@types/papaparse": "^5.3.14",
|
||||
"@types/pg": "^8.11.5",
|
||||
"@types/pg": "^8.11.6",
|
||||
"@xenova/transformers": "^2.17.1",
|
||||
"@zilliz/milvus2-sdk-node": "^2.4.1",
|
||||
"ajv": "^8.12.0",
|
||||
"assemblyai": "^4.4.1",
|
||||
"chromadb": "~1.7.3",
|
||||
"@zilliz/milvus2-sdk-node": "^2.4.2",
|
||||
"ajv": "^8.13.0",
|
||||
"assemblyai": "^4.4.2",
|
||||
"chromadb": "~1.8.1",
|
||||
"cohere-ai": "^7.9.5",
|
||||
"js-tiktoken": "^1.0.11",
|
||||
"lodash": "^4.17.21",
|
||||
"magic-bytes.js": "^1.10.0",
|
||||
"mammoth": "^1.7.1",
|
||||
"mammoth": "^1.7.2",
|
||||
"md-utils-ts": "^2.0.0",
|
||||
"mongodb": "^6.5.0",
|
||||
"mongodb": "^6.6.1",
|
||||
"notion-md-crawler": "^1.0.0",
|
||||
"ollama": "^0.5.0",
|
||||
"openai": "^4.38.0",
|
||||
"openai": "^4.43.0",
|
||||
"papaparse": "^5.4.1",
|
||||
"pathe": "^1.1.2",
|
||||
"pdf2json": "^3.0.5",
|
||||
"pdf2json": "3.0.5",
|
||||
"pg": "^8.11.5",
|
||||
"pgvector": "^0.1.8",
|
||||
"portkey-ai": "^0.1.16",
|
||||
"rake-modified": "^1.0.8",
|
||||
"string-strip-html": "^13.4.8",
|
||||
"wikipedia": "^2.1.2",
|
||||
"wink-nlp": "^1.14.3"
|
||||
"wink-nlp": "^2.2.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@notionhq/client": "^2.2.15"
|
||||
@@ -50,7 +66,7 @@
|
||||
"devDependencies": {
|
||||
"@notionhq/client": "^2.2.15",
|
||||
"@swc/cli": "^0.3.12",
|
||||
"@swc/core": "^1.4.16",
|
||||
"@swc/core": "^1.5.5",
|
||||
"concurrently": "^8.2.2",
|
||||
"glob": "^10.3.12",
|
||||
"madge": "^7.0.0",
|
||||
|
||||
@@ -55,9 +55,9 @@ class GlobalSettings implements Config {
|
||||
get debug() {
|
||||
const debug = getEnv("DEBUG");
|
||||
return (
|
||||
getEnv("NODE_ENV") === "development" &&
|
||||
Boolean(debug) &&
|
||||
debug?.includes("llamaindex")
|
||||
(Boolean(debug) && debug?.includes("llamaindex")) ||
|
||||
debug === "*" ||
|
||||
debug === "true"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ export class AnthropicAgent extends AgentRunner<Anthropic> {
|
||||
"tools" in params
|
||||
? params.tools
|
||||
: params.toolRetriever.retrieve.bind(params.toolRetriever),
|
||||
verbose: params.verbose ?? false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -67,12 +68,8 @@ export class AnthropicAgent extends AgentRunner<Anthropic> {
|
||||
return super.chat(params);
|
||||
}
|
||||
|
||||
static taskHandler: TaskHandler<Anthropic> = async (step) => {
|
||||
const { input } = step;
|
||||
static taskHandler: TaskHandler<Anthropic> = async (step, enqueueOutput) => {
|
||||
const { llm, getTools, stream } = step.context;
|
||||
if (input) {
|
||||
step.context.store.messages = [...step.context.store.messages, input];
|
||||
}
|
||||
const lastMessage = step.context.store.messages.at(-1)!.content;
|
||||
const tools = await getTools(lastMessage);
|
||||
if (stream === true) {
|
||||
@@ -88,37 +85,36 @@ export class AnthropicAgent extends AgentRunner<Anthropic> {
|
||||
response.message,
|
||||
];
|
||||
const options = response.message.options ?? {};
|
||||
enqueueOutput({
|
||||
taskStep: step,
|
||||
output: response,
|
||||
isLast: !("toolCall" in options),
|
||||
});
|
||||
if ("toolCall" in options) {
|
||||
const { toolCall } = options;
|
||||
const targetTool = tools.find(
|
||||
(tool) => tool.metadata.name === toolCall.name,
|
||||
);
|
||||
const toolOutput = await callTool(targetTool, toolCall);
|
||||
const toolOutput = await callTool(
|
||||
targetTool,
|
||||
toolCall,
|
||||
step.context.logger,
|
||||
);
|
||||
step.context.store.toolOutputs.push(toolOutput);
|
||||
return {
|
||||
taskStep: step,
|
||||
output: {
|
||||
raw: response.raw,
|
||||
message: {
|
||||
content: stringifyJSONToMessageContent(toolOutput.output),
|
||||
role: "user",
|
||||
options: {
|
||||
toolResult: {
|
||||
result: toolOutput.output,
|
||||
isError: toolOutput.isError,
|
||||
id: toolCall.id,
|
||||
},
|
||||
step.context.store.messages = [
|
||||
...step.context.store.messages,
|
||||
{
|
||||
content: stringifyJSONToMessageContent(toolOutput.output),
|
||||
role: "user",
|
||||
options: {
|
||||
toolResult: {
|
||||
result: toolOutput.output,
|
||||
isError: toolOutput.isError,
|
||||
id: toolCall.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
isLast: false,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
taskStep: step,
|
||||
output: response,
|
||||
isLast: true,
|
||||
};
|
||||
];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4,12 +4,14 @@ import {
|
||||
pipeline,
|
||||
randomUUID,
|
||||
} from "@llamaindex/env";
|
||||
import { Settings } from "../Settings.js";
|
||||
import {
|
||||
type ChatEngine,
|
||||
type ChatEngineParamsNonStreaming,
|
||||
type ChatEngineParamsStreaming,
|
||||
} from "../engines/chat/index.js";
|
||||
import { wrapEventCaller } from "../internal/context/EventCaller.js";
|
||||
import { consoleLogger, emptyLogger } from "../internal/logger.js";
|
||||
import { getCallbackManager } from "../internal/settings/CallbackManager.js";
|
||||
import { isAsyncIterable } from "../internal/utils.js";
|
||||
import type {
|
||||
@@ -27,14 +29,10 @@ import type {
|
||||
TaskStep,
|
||||
TaskStepOutput,
|
||||
} from "./types.js";
|
||||
import { consumeAsyncIterable } from "./utils.js";
|
||||
|
||||
export const MAX_TOOL_CALLS = 10;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export async function* createTaskImpl<
|
||||
export function createTaskOutputStream<
|
||||
Model extends LLM,
|
||||
Store extends object = {},
|
||||
AdditionalMessageOptions extends object = Model extends LLM<
|
||||
@@ -46,65 +44,67 @@ export async function* createTaskImpl<
|
||||
>(
|
||||
handler: TaskHandler<Model, Store, AdditionalMessageOptions>,
|
||||
context: AgentTaskContext<Model, Store, AdditionalMessageOptions>,
|
||||
_input: ChatMessage<AdditionalMessageOptions>,
|
||||
): AsyncGenerator<TaskStepOutput<Model, Store, AdditionalMessageOptions>> {
|
||||
let isFirst = true;
|
||||
let isDone = false;
|
||||
let input: ChatMessage<AdditionalMessageOptions> | null = _input;
|
||||
let prevStep: TaskStep<Model, Store, AdditionalMessageOptions> | null = null;
|
||||
while (!isDone) {
|
||||
const step: TaskStep<Model, Store, AdditionalMessageOptions> = {
|
||||
id: randomUUID(),
|
||||
input,
|
||||
context,
|
||||
prevStep,
|
||||
nextSteps: new Set(),
|
||||
};
|
||||
if (prevStep) {
|
||||
prevStep.nextSteps.add(step);
|
||||
}
|
||||
const prevToolCallCount = step.context.toolCallCount;
|
||||
if (!step.context.shouldContinue(step)) {
|
||||
throw new Error("Tool call count exceeded limit");
|
||||
}
|
||||
if (isFirst) {
|
||||
): ReadableStream<TaskStepOutput<Model, Store, AdditionalMessageOptions>> {
|
||||
const steps: TaskStep<Model, Store, AdditionalMessageOptions>[] = [];
|
||||
return new ReadableStream<
|
||||
TaskStepOutput<Model, Store, AdditionalMessageOptions>
|
||||
>({
|
||||
pull: async (controller) => {
|
||||
const step: TaskStep<Model, Store, AdditionalMessageOptions> = {
|
||||
id: randomUUID(),
|
||||
context,
|
||||
prevStep: null,
|
||||
nextSteps: new Set(),
|
||||
};
|
||||
if (steps.length > 0) {
|
||||
step.prevStep = steps[steps.length - 1];
|
||||
}
|
||||
const taskOutputs: TaskStepOutput<
|
||||
Model,
|
||||
Store,
|
||||
AdditionalMessageOptions
|
||||
>[] = [];
|
||||
steps.push(step);
|
||||
const enqueueOutput = (
|
||||
output: TaskStepOutput<Model, Store, AdditionalMessageOptions>,
|
||||
) => {
|
||||
context.logger.log("Enqueueing output for step(id, %s).", step.id);
|
||||
taskOutputs.push(output);
|
||||
controller.enqueue(output);
|
||||
};
|
||||
getCallbackManager().dispatchEvent("agent-start", {
|
||||
payload: {
|
||||
startStep: step,
|
||||
},
|
||||
});
|
||||
isFirst = false;
|
||||
}
|
||||
const taskOutput = await handler(step);
|
||||
const { isLast, output, taskStep } = taskOutput;
|
||||
// do not consume last output
|
||||
if (!isLast) {
|
||||
if (output) {
|
||||
input = isAsyncIterable(output)
|
||||
? await consumeAsyncIterable(output)
|
||||
: output.message;
|
||||
} else {
|
||||
input = null;
|
||||
}
|
||||
}
|
||||
context = {
|
||||
...taskStep.context,
|
||||
store: {
|
||||
...taskStep.context.store,
|
||||
},
|
||||
toolCallCount: prevToolCallCount + 1,
|
||||
};
|
||||
if (isLast) {
|
||||
isDone = true;
|
||||
getCallbackManager().dispatchEvent("agent-end", {
|
||||
payload: {
|
||||
endStep: step,
|
||||
|
||||
context.logger.log("Starting step(id, %s).", step.id);
|
||||
await handler(step, enqueueOutput);
|
||||
context.logger.log("Finished step(id, %s).", step.id);
|
||||
// fixme: support multi-thread when there are multiple outputs
|
||||
// todo: for now we pretend there is only one task output
|
||||
const { isLast, taskStep } = taskOutputs[0];
|
||||
context = {
|
||||
...taskStep.context,
|
||||
store: {
|
||||
...taskStep.context.store,
|
||||
},
|
||||
});
|
||||
}
|
||||
prevStep = taskStep;
|
||||
yield taskOutput;
|
||||
}
|
||||
toolCallCount: 1,
|
||||
};
|
||||
if (isLast) {
|
||||
context.logger.log(
|
||||
"Final step(id, %s) reached, closing task.",
|
||||
step.id,
|
||||
);
|
||||
getCallbackManager().dispatchEvent("agent-end", {
|
||||
payload: {
|
||||
endStep: step,
|
||||
},
|
||||
});
|
||||
controller.close();
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export type AgentStreamChatResponse<Options extends object> = {
|
||||
@@ -134,6 +134,7 @@ export type AgentRunnerParams<
|
||||
tools:
|
||||
| BaseToolWithCall[]
|
||||
| ((query: MessageContent) => Promise<BaseToolWithCall[]>);
|
||||
verbose: boolean;
|
||||
};
|
||||
|
||||
export type AgentParamsBase<
|
||||
@@ -148,6 +149,7 @@ export type AgentParamsBase<
|
||||
llm?: AI;
|
||||
chatHistory?: ChatMessage<AdditionalMessageOptions>[];
|
||||
systemPrompt?: MessageContent;
|
||||
verbose?: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -170,15 +172,16 @@ export abstract class AgentWorker<
|
||||
query: string,
|
||||
context: AgentTaskContext<AI, Store, AdditionalMessageOptions>,
|
||||
): ReadableStream<TaskStepOutput<AI, Store, AdditionalMessageOptions>> {
|
||||
const taskGenerator = createTaskImpl(this.taskHandler, context, {
|
||||
context.store.messages.push({
|
||||
role: "user",
|
||||
content: query,
|
||||
});
|
||||
const taskOutputStream = createTaskOutputStream(this.taskHandler, context);
|
||||
return new ReadableStream<
|
||||
TaskStepOutput<AI, Store, AdditionalMessageOptions>
|
||||
>({
|
||||
start: async (controller) => {
|
||||
for await (const stepOutput of taskGenerator) {
|
||||
for await (const stepOutput of taskOutputStream) {
|
||||
this.#taskSet.add(stepOutput.taskStep);
|
||||
controller.enqueue(stepOutput);
|
||||
if (stepOutput.isLast) {
|
||||
@@ -226,6 +229,7 @@ export abstract class AgentRunner<
|
||||
readonly #systemPrompt: MessageContent | null = null;
|
||||
#chatHistory: ChatMessage<AdditionalMessageOptions>[];
|
||||
readonly #runner: AgentWorker<AI, Store, AdditionalMessageOptions>;
|
||||
readonly #verbose: boolean;
|
||||
|
||||
// create extra store
|
||||
abstract createStore(): Store;
|
||||
@@ -237,14 +241,15 @@ export abstract class AgentRunner<
|
||||
protected constructor(
|
||||
params: AgentRunnerParams<AI, Store, AdditionalMessageOptions>,
|
||||
) {
|
||||
const { llm, chatHistory, runner, tools } = params;
|
||||
const { llm, chatHistory, systemPrompt, runner, tools, verbose } = params;
|
||||
this.#llm = llm;
|
||||
this.#chatHistory = chatHistory;
|
||||
this.#runner = runner;
|
||||
if (params.systemPrompt) {
|
||||
this.#systemPrompt = params.systemPrompt;
|
||||
if (systemPrompt) {
|
||||
this.#systemPrompt = systemPrompt;
|
||||
}
|
||||
this.#tools = tools;
|
||||
this.#verbose = verbose;
|
||||
}
|
||||
|
||||
get llm() {
|
||||
@@ -255,6 +260,10 @@ export abstract class AgentRunner<
|
||||
return this.#chatHistory;
|
||||
}
|
||||
|
||||
get verbose(): boolean {
|
||||
return Settings.debug || this.#verbose;
|
||||
}
|
||||
|
||||
public reset(): void {
|
||||
this.#chatHistory = [];
|
||||
}
|
||||
@@ -278,8 +287,11 @@ export abstract class AgentRunner<
|
||||
return task.context.toolCallCount < MAX_TOOL_CALLS;
|
||||
}
|
||||
|
||||
// fixme: this shouldn't be async
|
||||
async createTask(message: MessageContent, stream: boolean = false) {
|
||||
createTask(
|
||||
message: MessageContent,
|
||||
stream: boolean = false,
|
||||
verbose: boolean | undefined = undefined,
|
||||
) {
|
||||
const initialMessages = [...this.#chatHistory];
|
||||
if (this.#systemPrompt !== null) {
|
||||
const systemPrompt = this.#systemPrompt;
|
||||
@@ -304,6 +316,13 @@ export abstract class AgentRunner<
|
||||
toolOutputs: [] as ToolOutput[],
|
||||
},
|
||||
shouldContinue: AgentRunner.shouldContinue,
|
||||
logger:
|
||||
// disable verbose if explicitly set to false
|
||||
verbose === false
|
||||
? emptyLogger
|
||||
: verbose || this.verbose
|
||||
? consoleLogger
|
||||
: emptyLogger,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -320,7 +339,7 @@ export abstract class AgentRunner<
|
||||
| AgentChatResponse<AdditionalMessageOptions>
|
||||
| ReadableStream<AgentStreamChatResponse<AdditionalMessageOptions>>
|
||||
> {
|
||||
const task = await this.createTask(params.message, !!params.stream);
|
||||
const task = this.createTask(params.message, !!params.stream);
|
||||
const stepOutput = await pipeline(
|
||||
task,
|
||||
async (
|
||||
@@ -329,6 +348,8 @@ export abstract class AgentRunner<
|
||||
>,
|
||||
) => {
|
||||
for await (const stepOutput of iter) {
|
||||
// update chat history for each round
|
||||
this.#chatHistory = [...stepOutput.taskStep.context.store.messages];
|
||||
if (stepOutput.isLast) {
|
||||
return stepOutput;
|
||||
}
|
||||
@@ -337,7 +358,6 @@ export abstract class AgentRunner<
|
||||
},
|
||||
);
|
||||
const { output, taskStep } = stepOutput;
|
||||
this.#chatHistory = [...taskStep.context.store.messages];
|
||||
if (isAsyncIterable(output)) {
|
||||
return output.pipeThrough<
|
||||
AgentStreamChatResponse<AdditionalMessageOptions>
|
||||
|
||||
@@ -46,17 +46,14 @@ export class OpenAIAgent extends AgentRunner<OpenAI> {
|
||||
"tools" in params
|
||||
? params.tools
|
||||
: params.toolRetriever.retrieve.bind(params.toolRetriever),
|
||||
verbose: params.verbose ?? false,
|
||||
});
|
||||
}
|
||||
|
||||
createStore = AgentRunner.defaultCreateStore;
|
||||
|
||||
static taskHandler: TaskHandler<OpenAI> = async (step) => {
|
||||
const { input } = step;
|
||||
static taskHandler: TaskHandler<OpenAI> = async (step, enqueueOutput) => {
|
||||
const { llm, stream, getTools } = step.context;
|
||||
if (input) {
|
||||
step.context.store.messages = [...step.context.store.messages, input];
|
||||
}
|
||||
const lastMessage = step.context.store.messages.at(-1)!.content;
|
||||
const tools = await getTools(lastMessage);
|
||||
const response = await llm.chat({
|
||||
@@ -71,37 +68,36 @@ export class OpenAIAgent extends AgentRunner<OpenAI> {
|
||||
response.message,
|
||||
];
|
||||
const options = response.message.options ?? {};
|
||||
enqueueOutput({
|
||||
taskStep: step,
|
||||
output: response,
|
||||
isLast: !("toolCall" in options),
|
||||
});
|
||||
if ("toolCall" in options) {
|
||||
const { toolCall } = options;
|
||||
const targetTool = tools.find(
|
||||
(tool) => tool.metadata.name === toolCall.name,
|
||||
);
|
||||
const toolOutput = await callTool(targetTool, toolCall);
|
||||
const toolOutput = await callTool(
|
||||
targetTool,
|
||||
toolCall,
|
||||
step.context.logger,
|
||||
);
|
||||
step.context.store.toolOutputs.push(toolOutput);
|
||||
return {
|
||||
taskStep: step,
|
||||
output: {
|
||||
raw: response.raw,
|
||||
message: {
|
||||
content: stringifyJSONToMessageContent(toolOutput.output),
|
||||
role: "user",
|
||||
options: {
|
||||
toolResult: {
|
||||
result: toolOutput.output,
|
||||
isError: toolOutput.isError,
|
||||
id: toolCall.id,
|
||||
},
|
||||
step.context.store.messages = [
|
||||
...step.context.store.messages,
|
||||
{
|
||||
role: "user" as const,
|
||||
content: stringifyJSONToMessageContent(toolOutput.output),
|
||||
options: {
|
||||
toolResult: {
|
||||
result: toolOutput.output,
|
||||
isError: toolOutput.isError,
|
||||
id: toolCall.id,
|
||||
},
|
||||
},
|
||||
},
|
||||
isLast: false,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
taskStep: step,
|
||||
output: response,
|
||||
isLast: true,
|
||||
};
|
||||
];
|
||||
}
|
||||
} else {
|
||||
const responseChunkStream = new ReadableStream<
|
||||
@@ -126,6 +122,11 @@ export class OpenAIAgent extends AgentRunner<OpenAI> {
|
||||
// check if first chunk has tool calls, if so, this is a function call
|
||||
// otherwise, it's a regular message
|
||||
const hasToolCall = !!(value.options && "toolCall" in value.options);
|
||||
enqueueOutput({
|
||||
taskStep: step,
|
||||
output: finalStream,
|
||||
isLast: !hasToolCall,
|
||||
});
|
||||
|
||||
if (hasToolCall) {
|
||||
// you need to consume the response to get the full toolCalls
|
||||
@@ -158,7 +159,11 @@ export class OpenAIAgent extends AgentRunner<OpenAI> {
|
||||
},
|
||||
},
|
||||
];
|
||||
const toolOutput = await callTool(targetTool, toolCall);
|
||||
const toolOutput = await callTool(
|
||||
targetTool,
|
||||
toolCall,
|
||||
step.context.logger,
|
||||
);
|
||||
step.context.store.messages = [
|
||||
...step.context.store.messages,
|
||||
{
|
||||
@@ -175,17 +180,6 @@ export class OpenAIAgent extends AgentRunner<OpenAI> {
|
||||
];
|
||||
step.context.store.toolOutputs.push(toolOutput);
|
||||
}
|
||||
return {
|
||||
taskStep: step,
|
||||
output: null,
|
||||
isLast: false,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
taskStep: step,
|
||||
output: finalStream,
|
||||
isLast: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { pipeline, randomUUID } from "@llamaindex/env";
|
||||
import { Settings } from "../Settings.js";
|
||||
import { randomUUID, ReadableStream } from "@llamaindex/env";
|
||||
import { getReACTAgentSystemHeader } from "../internal/prompt/react.js";
|
||||
import {
|
||||
isAsyncIterable,
|
||||
@@ -13,6 +12,7 @@ import {
|
||||
} from "../llm/index.js";
|
||||
import { extractText } from "../llm/utils.js";
|
||||
import { ObjectRetriever } from "../objects/index.js";
|
||||
import { Settings } from "../Settings.js";
|
||||
import type {
|
||||
BaseTool,
|
||||
BaseToolWithCall,
|
||||
@@ -60,7 +60,7 @@ type ActionReason = BaseReason & {
|
||||
type ResponseReason = BaseReason & {
|
||||
type: "response";
|
||||
thought: string;
|
||||
response: ChatResponse | AsyncIterable<ChatResponseChunk>;
|
||||
response: ChatResponse;
|
||||
};
|
||||
|
||||
type Reason = ObservationReason | ActionReason | ResponseReason;
|
||||
@@ -74,16 +74,9 @@ function reasonFormatter(reason: Reason): string | Promise<string> {
|
||||
reason.input,
|
||||
)}`;
|
||||
case "response": {
|
||||
if (isAsyncIterable(reason.response)) {
|
||||
return consumeAsyncIterable(reason.response).then(
|
||||
(message) =>
|
||||
`Thought: ${reason.thought}\nAnswer: ${extractText(message.content)}`,
|
||||
);
|
||||
} else {
|
||||
return `Thought: ${reason.thought}\nAnswer: ${extractText(
|
||||
reason.response.message.content,
|
||||
)}`;
|
||||
}
|
||||
return `Thought: ${reason.thought}\nAnswer: ${extractText(
|
||||
reason.response.message.content,
|
||||
)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,35 +139,52 @@ function actionInputParser(jsonStr: string): JSONObject {
|
||||
|
||||
type ReACTOutputParser = <Options extends object>(
|
||||
output: ChatResponse<Options> | AsyncIterable<ChatResponseChunk<Options>>,
|
||||
onResolveType: (
|
||||
type: "action" | "thought" | "answer",
|
||||
response:
|
||||
| ChatResponse<Options>
|
||||
| ReadableStream<ChatResponseChunk<Options>>,
|
||||
) => void,
|
||||
) => Promise<Reason>;
|
||||
|
||||
const reACTOutputParser: ReACTOutputParser = async (
|
||||
output,
|
||||
onResolveType,
|
||||
): Promise<Reason> => {
|
||||
let reason: Reason | null = null;
|
||||
|
||||
if (isAsyncIterable(output)) {
|
||||
const [peakStream, finalStream] = createReadableStream(output).tee();
|
||||
const type = await pipeline(peakStream, async (iter) => {
|
||||
let content = "";
|
||||
for await (const chunk of iter) {
|
||||
content += chunk.delta;
|
||||
if (content.includes("Action:")) {
|
||||
return "action";
|
||||
} else if (content.includes("Answer:")) {
|
||||
return "answer";
|
||||
} else if (content.includes("Thought:")) {
|
||||
return "thought";
|
||||
}
|
||||
const reader = peakStream.getReader();
|
||||
let type: "action" | "thought" | "answer" | null = null;
|
||||
let content = "";
|
||||
do {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
});
|
||||
content += value.delta;
|
||||
if (content.includes("Action:")) {
|
||||
type = "action";
|
||||
} else if (content.includes("Answer:")) {
|
||||
type = "answer";
|
||||
}
|
||||
} while (true);
|
||||
if (type === null) {
|
||||
// `Thought:` is always present at the beginning of the output.
|
||||
type = "thought";
|
||||
}
|
||||
reader.releaseLock();
|
||||
if (!type) {
|
||||
throw new Error("Could not determine type of output");
|
||||
}
|
||||
onResolveType(type, finalStream);
|
||||
// step 2: do the parsing from content
|
||||
switch (type) {
|
||||
case "action": {
|
||||
// have to consume the stream to get the full content
|
||||
const response = await consumeAsyncIterable(finalStream);
|
||||
const { content } = response;
|
||||
const [thought, action, input] = extractToolUse(content);
|
||||
const response = await consumeAsyncIterable(peakStream, content);
|
||||
const [thought, action, input] = extractToolUse(response.content);
|
||||
const jsonStr = extractJsonStr(input);
|
||||
let json: JSONObject;
|
||||
try {
|
||||
@@ -192,18 +202,20 @@ const reACTOutputParser: ReACTOutputParser = async (
|
||||
}
|
||||
case "thought": {
|
||||
const thought = "(Implicit) I can answer without any more tools!";
|
||||
const response = await consumeAsyncIterable(peakStream, content);
|
||||
reason = {
|
||||
type: "response",
|
||||
thought,
|
||||
// bypass the response, because here we don't need to do anything with it
|
||||
response: finalStream,
|
||||
response: {
|
||||
raw: peakStream,
|
||||
message: response,
|
||||
},
|
||||
};
|
||||
break;
|
||||
}
|
||||
case "answer": {
|
||||
const response = await consumeAsyncIterable(finalStream);
|
||||
const { content } = response;
|
||||
const [thought, answer] = extractFinalResponse(content);
|
||||
const response = await consumeAsyncIterable(peakStream, content);
|
||||
const [thought, answer] = extractFinalResponse(response.content);
|
||||
reason = {
|
||||
type: "response",
|
||||
thought,
|
||||
@@ -227,7 +239,9 @@ const reACTOutputParser: ReACTOutputParser = async (
|
||||
? "answer"
|
||||
: content.includes("Action:")
|
||||
? "action"
|
||||
: "thought";
|
||||
: // `Thought:` is always present at the beginning of the output.
|
||||
"thought";
|
||||
onResolveType(type, output);
|
||||
|
||||
// step 2: do the parsing from content
|
||||
switch (type) {
|
||||
@@ -340,6 +354,7 @@ export class ReActAgent extends AgentRunner<LLM, ReACTAgentStore> {
|
||||
"tools" in params
|
||||
? params.tools
|
||||
: params.toolRetriever.retrieve.bind(params.toolRetriever),
|
||||
verbose: params.verbose ?? false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -349,12 +364,11 @@ export class ReActAgent extends AgentRunner<LLM, ReACTAgentStore> {
|
||||
};
|
||||
}
|
||||
|
||||
static taskHandler: TaskHandler<LLM, ReACTAgentStore> = async (step) => {
|
||||
static taskHandler: TaskHandler<LLM, ReACTAgentStore> = async (
|
||||
step,
|
||||
enqueueOutput,
|
||||
) => {
|
||||
const { llm, stream, getTools } = step.context;
|
||||
const input = step.input;
|
||||
if (input) {
|
||||
step.context.store.messages.push(input);
|
||||
}
|
||||
const lastMessage = step.context.store.messages.at(-1)!.content;
|
||||
const tools = await getTools(lastMessage);
|
||||
const messages = await chatFormatter(
|
||||
@@ -367,35 +381,33 @@ export class ReActAgent extends AgentRunner<LLM, ReACTAgentStore> {
|
||||
stream,
|
||||
messages,
|
||||
});
|
||||
const reason = await reACTOutputParser(response);
|
||||
step.context.store.reasons = [...step.context.store.reasons, reason];
|
||||
if (reason.type === "response") {
|
||||
return {
|
||||
isLast: true,
|
||||
output: response,
|
||||
const reason = await reACTOutputParser(response, (type, response) => {
|
||||
enqueueOutput({
|
||||
taskStep: step,
|
||||
};
|
||||
} else {
|
||||
if (reason.type === "action") {
|
||||
const tool = tools.find((tool) => tool.metadata.name === reason.action);
|
||||
const toolOutput = await callTool(tool, {
|
||||
output: response,
|
||||
isLast: type !== "action",
|
||||
});
|
||||
});
|
||||
step.context.logger.log("current reason: %O", reason);
|
||||
step.context.store.reasons = [...step.context.store.reasons, reason];
|
||||
if (reason.type === "action") {
|
||||
const tool = tools.find((tool) => tool.metadata.name === reason.action);
|
||||
const toolOutput = await callTool(
|
||||
tool,
|
||||
{
|
||||
id: randomUUID(),
|
||||
input: reason.input,
|
||||
name: reason.action,
|
||||
});
|
||||
step.context.store.reasons = [
|
||||
...step.context.store.reasons,
|
||||
{
|
||||
type: "observation",
|
||||
observation: toolOutput.output,
|
||||
},
|
||||
];
|
||||
}
|
||||
return {
|
||||
isLast: false,
|
||||
output: null,
|
||||
taskStep: step,
|
||||
};
|
||||
},
|
||||
step.context.logger,
|
||||
);
|
||||
step.context.store.reasons = [
|
||||
...step.context.store.reasons,
|
||||
{
|
||||
type: "observation",
|
||||
observation: toolOutput.output,
|
||||
},
|
||||
];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ReadableStream } from "@llamaindex/env";
|
||||
import type { Logger } from "../internal/logger.js";
|
||||
import type { BaseEvent } from "../internal/type.js";
|
||||
import type {
|
||||
ChatMessage,
|
||||
@@ -32,6 +33,7 @@ export type AgentTaskContext<
|
||||
toolOutputs: ToolOutput[];
|
||||
messages: ChatMessage<AdditionalMessageOptions>[];
|
||||
} & Store;
|
||||
logger: Readonly<Logger>;
|
||||
};
|
||||
|
||||
export type TaskStep<
|
||||
@@ -45,7 +47,6 @@ export type TaskStep<
|
||||
: never,
|
||||
> = {
|
||||
id: UUID;
|
||||
input: ChatMessage<AdditionalMessageOptions> | null;
|
||||
context: AgentTaskContext<Model, Store, AdditionalMessageOptions>;
|
||||
|
||||
// linked list
|
||||
@@ -62,22 +63,14 @@ export type TaskStepOutput<
|
||||
>
|
||||
? AdditionalMessageOptions
|
||||
: never,
|
||||
> =
|
||||
| {
|
||||
taskStep: TaskStep<Model, Store, AdditionalMessageOptions>;
|
||||
output:
|
||||
| null
|
||||
| ChatResponse<AdditionalMessageOptions>
|
||||
| ReadableStream<ChatResponseChunk<AdditionalMessageOptions>>;
|
||||
isLast: false;
|
||||
}
|
||||
| {
|
||||
taskStep: TaskStep<Model, Store, AdditionalMessageOptions>;
|
||||
output:
|
||||
| ChatResponse<AdditionalMessageOptions>
|
||||
| ReadableStream<ChatResponseChunk<AdditionalMessageOptions>>;
|
||||
isLast: true;
|
||||
};
|
||||
> = {
|
||||
taskStep: TaskStep<Model, Store, AdditionalMessageOptions>;
|
||||
// output shows the response to the user
|
||||
output:
|
||||
| ChatResponse<AdditionalMessageOptions>
|
||||
| ReadableStream<ChatResponseChunk<AdditionalMessageOptions>>;
|
||||
isLast: boolean;
|
||||
};
|
||||
|
||||
export type TaskHandler<
|
||||
Model extends LLM,
|
||||
@@ -90,7 +83,10 @@ export type TaskHandler<
|
||||
: never,
|
||||
> = (
|
||||
step: TaskStep<Model, Store, AdditionalMessageOptions>,
|
||||
) => Promise<TaskStepOutput<Model, Store, AdditionalMessageOptions>>;
|
||||
enqueueOutput: (
|
||||
taskOutput: TaskStepOutput<Model, Store, AdditionalMessageOptions>,
|
||||
) => void,
|
||||
) => Promise<void>;
|
||||
|
||||
export type AgentStartEvent = BaseEvent<{
|
||||
startStep: TaskStep;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ReadableStream } from "@llamaindex/env";
|
||||
import type { Logger } from "../internal/logger.js";
|
||||
import { getCallbackManager } from "../internal/settings/CallbackManager.js";
|
||||
import { isAsyncIterable, prettifyError } from "../internal/utils.js";
|
||||
import type {
|
||||
@@ -13,12 +14,14 @@ import type { BaseTool, JSONObject, JSONValue, ToolOutput } from "../types.js";
|
||||
export async function callTool(
|
||||
tool: BaseTool | undefined,
|
||||
toolCall: ToolCall | PartialToolCall,
|
||||
logger: Logger,
|
||||
): Promise<ToolOutput> {
|
||||
const input: JSONObject =
|
||||
typeof toolCall.input === "string"
|
||||
? JSON.parse(toolCall.input)
|
||||
: toolCall.input;
|
||||
if (!tool) {
|
||||
logger.error(`Tool ${toolCall.name} does not exist.`);
|
||||
const output = `Tool ${toolCall.name} does not exist.`;
|
||||
return {
|
||||
tool,
|
||||
@@ -30,6 +33,9 @@ export async function callTool(
|
||||
const call = tool.call;
|
||||
let output: JSONValue;
|
||||
if (!call) {
|
||||
logger.error(
|
||||
`Tool ${tool.metadata.name} (remote:${toolCall.name}) does not have a implementation.`,
|
||||
);
|
||||
output = `Tool ${tool.metadata.name} (remote:${toolCall.name}) does not have a implementation.`;
|
||||
return {
|
||||
tool,
|
||||
@@ -45,6 +51,10 @@ export async function callTool(
|
||||
},
|
||||
});
|
||||
output = await call.call(tool, input);
|
||||
logger.log(
|
||||
`Tool ${tool.metadata.name} (remote:${toolCall.name}) succeeded.`,
|
||||
);
|
||||
logger.log(`Output: ${JSON.stringify(output)}`);
|
||||
const toolOutput: ToolOutput = {
|
||||
tool,
|
||||
input,
|
||||
@@ -60,6 +70,9 @@ export async function callTool(
|
||||
return toolOutput;
|
||||
} catch (e) {
|
||||
output = prettifyError(e);
|
||||
logger.error(
|
||||
`Tool ${tool.metadata.name} (remote:${toolCall.name}) failed: ${output}`,
|
||||
);
|
||||
}
|
||||
return {
|
||||
tool,
|
||||
@@ -71,16 +84,19 @@ export async function callTool(
|
||||
|
||||
export async function consumeAsyncIterable<Options extends object>(
|
||||
input: ChatMessage<Options>,
|
||||
previousContent?: string,
|
||||
): Promise<ChatMessage<Options>>;
|
||||
export async function consumeAsyncIterable<Options extends object>(
|
||||
input: AsyncIterable<ChatResponseChunk<Options>>,
|
||||
previousContent?: string,
|
||||
): Promise<TextChatMessage<Options>>;
|
||||
export async function consumeAsyncIterable<Options extends object>(
|
||||
input: ChatMessage<Options> | AsyncIterable<ChatResponseChunk<Options>>,
|
||||
previousContent: string = "",
|
||||
): Promise<ChatMessage<Options>> {
|
||||
if (isAsyncIterable(input)) {
|
||||
const result: ChatMessage<Options> = {
|
||||
content: "",
|
||||
content: previousContent,
|
||||
// only assistant will give streaming response
|
||||
role: "assistant",
|
||||
options: {} as Options,
|
||||
|
||||
@@ -12,6 +12,8 @@ import type {
|
||||
LLMStreamEvent,
|
||||
LLMToolCallEvent,
|
||||
LLMToolResultEvent,
|
||||
RetrievalEndEvent,
|
||||
RetrievalStartEvent,
|
||||
} from "../llm/types.js";
|
||||
|
||||
export class LlamaIndexCustomEvent<T = any> extends CustomEvent<T> {
|
||||
@@ -45,6 +47,8 @@ export interface LlamaIndexEventMaps {
|
||||
* @deprecated
|
||||
*/
|
||||
retrieve: CustomEvent<RetrievalCallbackResponse>;
|
||||
"retrieve-start": RetrievalStartEvent;
|
||||
"retrieve-end": RetrievalEndEvent;
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@@ -212,10 +216,13 @@ export class CallbackManager implements CallbackManagerMethods {
|
||||
if (!handlers) {
|
||||
return;
|
||||
}
|
||||
const clone = structuredClone(detail);
|
||||
queueMicrotask(() => {
|
||||
handlers.forEach((handler) =>
|
||||
handler(LlamaIndexCustomEvent.fromEvent(event, clone)),
|
||||
handler(
|
||||
LlamaIndexCustomEvent.fromEvent(event, {
|
||||
...detail,
|
||||
}),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
import _ from "lodash";
|
||||
import type { ImageType } from "../Node.js";
|
||||
import { lazyLoadTransformers } from "../internal/deps/transformers.js";
|
||||
import { MultiModalEmbedding } from "./MultiModalEmbedding.js";
|
||||
// only import type, to avoid bundling error
|
||||
import type {
|
||||
CLIPTextModelWithProjection,
|
||||
CLIPVisionModelWithProjection,
|
||||
PreTrainedTokenizer,
|
||||
Processor,
|
||||
} from "@xenova/transformers";
|
||||
|
||||
async function readImage(input: ImageType) {
|
||||
const { RawImage } = await import(
|
||||
/* webpackIgnore: true */
|
||||
"@xenova/transformers"
|
||||
);
|
||||
const { RawImage } = await lazyLoadTransformers();
|
||||
if (input instanceof Blob) {
|
||||
return await RawImage.fromBlob(input);
|
||||
} else if (_.isString(input) || input instanceof URL) {
|
||||
@@ -25,39 +30,30 @@ export class ClipEmbedding extends MultiModalEmbedding {
|
||||
modelType: ClipEmbeddingModelType =
|
||||
ClipEmbeddingModelType.XENOVA_CLIP_VIT_BASE_PATCH16;
|
||||
|
||||
private tokenizer: any;
|
||||
private processor: any;
|
||||
private visionModel: any;
|
||||
private textModel: any;
|
||||
private tokenizer: PreTrainedTokenizer | null = null;
|
||||
private processor: Processor | null = null;
|
||||
private visionModel: CLIPVisionModelWithProjection | null = null;
|
||||
private textModel: CLIPTextModelWithProjection | null = null;
|
||||
|
||||
async getTokenizer() {
|
||||
const { AutoTokenizer } = await lazyLoadTransformers();
|
||||
if (!this.tokenizer) {
|
||||
const { AutoTokenizer } = await import(
|
||||
/* webpackIgnore: true */
|
||||
"@xenova/transformers"
|
||||
);
|
||||
this.tokenizer = await AutoTokenizer.from_pretrained(this.modelType);
|
||||
}
|
||||
return this.tokenizer;
|
||||
}
|
||||
|
||||
async getProcessor() {
|
||||
const { AutoProcessor } = await lazyLoadTransformers();
|
||||
if (!this.processor) {
|
||||
const { AutoProcessor } = await import(
|
||||
/* webpackIgnore: true */
|
||||
"@xenova/transformers"
|
||||
);
|
||||
this.processor = await AutoProcessor.from_pretrained(this.modelType);
|
||||
}
|
||||
return this.processor;
|
||||
}
|
||||
|
||||
async getVisionModel() {
|
||||
const { CLIPVisionModelWithProjection } = await lazyLoadTransformers();
|
||||
if (!this.visionModel) {
|
||||
const { CLIPVisionModelWithProjection } = await import(
|
||||
/* webpackIgnore: true */
|
||||
"@xenova/transformers"
|
||||
);
|
||||
this.visionModel = await CLIPVisionModelWithProjection.from_pretrained(
|
||||
this.modelType,
|
||||
);
|
||||
@@ -67,11 +63,8 @@ export class ClipEmbedding extends MultiModalEmbedding {
|
||||
}
|
||||
|
||||
async getTextModel() {
|
||||
const { CLIPTextModelWithProjection } = await lazyLoadTransformers();
|
||||
if (!this.textModel) {
|
||||
const { CLIPTextModelWithProjection } = await import(
|
||||
/* webpackIgnore: true */
|
||||
"@xenova/transformers"
|
||||
);
|
||||
this.textModel = await CLIPTextModelWithProjection.from_pretrained(
|
||||
this.modelType,
|
||||
);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { lazyLoadTransformers } from "../internal/deps/transformers.js";
|
||||
import { BaseEmbedding } from "./types.js";
|
||||
|
||||
export enum HuggingFaceEmbeddingModelType {
|
||||
@@ -31,7 +32,7 @@ export class HuggingFaceEmbedding extends BaseEmbedding {
|
||||
|
||||
async getExtractor() {
|
||||
if (!this.extractor) {
|
||||
const { pipeline } = await import("@xenova/transformers");
|
||||
const { pipeline } = await lazyLoadTransformers();
|
||||
this.extractor = await pipeline("feature-extraction", this.modelType, {
|
||||
quantized: this.quantized,
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ export * from "./GeminiEmbedding.js";
|
||||
export * from "./JinaAIEmbedding.js";
|
||||
export * from "./MistralAIEmbedding.js";
|
||||
export * from "./MultiModalEmbedding.js";
|
||||
export { OllamaEmbedding } from "./OllamaEmbedding.js";
|
||||
export * from "./OpenAIEmbedding.js";
|
||||
export { FireworksEmbedding } from "./fireworks.js";
|
||||
export { TogetherEmbedding } from "./together.js";
|
||||
|
||||
@@ -13,6 +13,11 @@ export interface ChatEngineParamsBase {
|
||||
* Optional chat history if you want to customize the chat history.
|
||||
*/
|
||||
chatHistory?: ChatMessage[] | ChatHistory;
|
||||
/**
|
||||
* Optional flag to enable verbose mode.
|
||||
* @default false
|
||||
*/
|
||||
verbose?: boolean;
|
||||
}
|
||||
|
||||
export interface ChatEngineParamsStreaming extends ChatEngineParamsBase {
|
||||
|
||||
@@ -27,6 +27,7 @@ export * from "./objects/index.js";
|
||||
export * from "./postprocessors/index.js";
|
||||
export * from "./prompts/index.js";
|
||||
export * from "./selectors/index.js";
|
||||
export * from "./storage/StorageContext.js";
|
||||
export * from "./synthesizers/index.js";
|
||||
export * from "./tools/index.js";
|
||||
export * from "./types.js";
|
||||
|
||||
@@ -10,5 +10,3 @@ export {
|
||||
HuggingFaceEmbedding,
|
||||
HuggingFaceEmbeddingModelType,
|
||||
} from "./embeddings/HuggingFaceEmbedding.js";
|
||||
export { OllamaEmbedding } from "./embeddings/OllamaEmbedding.js";
|
||||
export { Ollama, type OllamaParams } from "./llm/ollama.js";
|
||||
|
||||
@@ -1,14 +1,8 @@
|
||||
import type {
|
||||
BaseNode,
|
||||
Document,
|
||||
Metadata,
|
||||
NodeWithScore,
|
||||
} from "../../Node.js";
|
||||
import type { BaseNode, Document, NodeWithScore } from "../../Node.js";
|
||||
import { ImageNode, ObjectType, splitNodesByType } from "../../Node.js";
|
||||
import type { BaseRetriever, RetrieveParams } from "../../Retriever.js";
|
||||
import type { ServiceContext } from "../../ServiceContext.js";
|
||||
import {
|
||||
Settings,
|
||||
embedModelFromSettingsOrContext,
|
||||
nodeParserFromSettingsOrContext,
|
||||
} from "../../Settings.js";
|
||||
@@ -25,6 +19,7 @@ import {
|
||||
createDocStoreStrategy,
|
||||
} from "../../ingestion/strategies/index.js";
|
||||
import { wrapEventCaller } from "../../internal/context/EventCaller.js";
|
||||
import { getCallbackManager } from "../../internal/settings/CallbackManager.js";
|
||||
import type { BaseNodePostprocessor } from "../../postprocessors/types.js";
|
||||
import type { StorageContext } from "../../storage/StorageContext.js";
|
||||
import { storageContextFromDefaults } from "../../storage/StorageContext.js";
|
||||
@@ -279,18 +274,29 @@ export class VectorStoreIndex extends BaseIndex<IndexDict> {
|
||||
return new VectorIndexRetriever({ index: this, ...options });
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a RetrieverQueryEngine.
|
||||
* similarityTopK is only used if no existing retriever is provided.
|
||||
*/
|
||||
asQueryEngine(options?: {
|
||||
retriever?: BaseRetriever;
|
||||
responseSynthesizer?: BaseSynthesizer;
|
||||
preFilters?: MetadataFilters;
|
||||
nodePostprocessors?: BaseNodePostprocessor[];
|
||||
similarityTopK?: number;
|
||||
}): QueryEngine & RetrieverQueryEngine {
|
||||
const { retriever, responseSynthesizer } = options ?? {};
|
||||
return new RetrieverQueryEngine(
|
||||
retriever ?? this.asRetriever(),
|
||||
const {
|
||||
retriever,
|
||||
responseSynthesizer,
|
||||
options?.preFilters,
|
||||
options?.nodePostprocessors,
|
||||
preFilters,
|
||||
nodePostprocessors,
|
||||
similarityTopK,
|
||||
} = options ?? {};
|
||||
return new RetrieverQueryEngine(
|
||||
retriever ?? this.asRetriever({ similarityTopK }),
|
||||
responseSynthesizer,
|
||||
preFilters,
|
||||
nodePostprocessors,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -400,10 +406,16 @@ export class VectorIndexRetriever implements BaseRetriever {
|
||||
this.imageSimilarityTopK = imageSimilarityTopK ?? DEFAULT_SIMILARITY_TOP_K;
|
||||
}
|
||||
|
||||
@wrapEventCaller
|
||||
async retrieve({
|
||||
query,
|
||||
preFilters,
|
||||
}: RetrieveParams): Promise<NodeWithScore[]> {
|
||||
getCallbackManager().dispatchEvent("retrieve-start", {
|
||||
payload: {
|
||||
query,
|
||||
},
|
||||
});
|
||||
let nodesWithScores = await this.textRetrieve(
|
||||
query,
|
||||
preFilters as MetadataFilters,
|
||||
@@ -411,7 +423,17 @@ export class VectorIndexRetriever implements BaseRetriever {
|
||||
nodesWithScores = nodesWithScores.concat(
|
||||
await this.textToImageRetrieve(query, preFilters as MetadataFilters),
|
||||
);
|
||||
this.sendEvent(query, nodesWithScores);
|
||||
getCallbackManager().dispatchEvent("retrieve-end", {
|
||||
payload: {
|
||||
query,
|
||||
nodes: nodesWithScores,
|
||||
},
|
||||
});
|
||||
// send deprecated event
|
||||
getCallbackManager().dispatchEvent("retrieve", {
|
||||
query,
|
||||
nodes: nodesWithScores,
|
||||
});
|
||||
return nodesWithScores;
|
||||
}
|
||||
|
||||
@@ -448,17 +470,6 @@ export class VectorIndexRetriever implements BaseRetriever {
|
||||
return this.buildNodeListFromQueryResult(result);
|
||||
}
|
||||
|
||||
@wrapEventCaller
|
||||
protected sendEvent(
|
||||
query: string,
|
||||
nodesWithScores: NodeWithScore<Metadata>[],
|
||||
) {
|
||||
Settings.callbackManager.dispatchEvent("retrieve", {
|
||||
query,
|
||||
nodes: nodesWithScores,
|
||||
});
|
||||
}
|
||||
|
||||
protected async buildVectorStoreQuery(
|
||||
embedModel: BaseEmbedding,
|
||||
query: string,
|
||||
|
||||
+264
@@ -0,0 +1,264 @@
|
||||
type Fetch = typeof fetch;
|
||||
interface Config {
|
||||
host: string;
|
||||
fetch?: Fetch;
|
||||
proxy?: boolean;
|
||||
}
|
||||
interface Options {
|
||||
numa: boolean;
|
||||
num_ctx: number;
|
||||
num_batch: number;
|
||||
main_gpu: number;
|
||||
low_vram: boolean;
|
||||
f16_kv: boolean;
|
||||
logits_all: boolean;
|
||||
vocab_only: boolean;
|
||||
use_mmap: boolean;
|
||||
use_mlock: boolean;
|
||||
embedding_only: boolean;
|
||||
num_thread: number;
|
||||
num_keep: number;
|
||||
seed: number;
|
||||
num_predict: number;
|
||||
top_k: number;
|
||||
top_p: number;
|
||||
tfs_z: number;
|
||||
typical_p: number;
|
||||
repeat_last_n: number;
|
||||
temperature: number;
|
||||
repeat_penalty: number;
|
||||
presence_penalty: number;
|
||||
frequency_penalty: number;
|
||||
mirostat: number;
|
||||
mirostat_tau: number;
|
||||
mirostat_eta: number;
|
||||
penalize_newline: boolean;
|
||||
stop: string[];
|
||||
}
|
||||
interface GenerateRequest {
|
||||
model: string;
|
||||
prompt: string;
|
||||
system?: string;
|
||||
template?: string;
|
||||
context?: number[];
|
||||
stream?: boolean;
|
||||
raw?: boolean;
|
||||
format?: string;
|
||||
images?: Uint8Array[] | string[];
|
||||
keep_alive?: string | number;
|
||||
options?: Partial<Options>;
|
||||
}
|
||||
interface Message {
|
||||
role: string;
|
||||
content: string;
|
||||
images?: Uint8Array[] | string[];
|
||||
}
|
||||
interface ChatRequest {
|
||||
model: string;
|
||||
messages?: Message[];
|
||||
stream?: boolean;
|
||||
format?: string;
|
||||
keep_alive?: string | number;
|
||||
options?: Partial<Options>;
|
||||
}
|
||||
interface PullRequest {
|
||||
model: string;
|
||||
insecure?: boolean;
|
||||
stream?: boolean;
|
||||
}
|
||||
interface PushRequest {
|
||||
model: string;
|
||||
insecure?: boolean;
|
||||
stream?: boolean;
|
||||
}
|
||||
interface CreateRequest {
|
||||
model: string;
|
||||
path?: string;
|
||||
modelfile?: string;
|
||||
stream?: boolean;
|
||||
}
|
||||
interface DeleteRequest {
|
||||
model: string;
|
||||
}
|
||||
interface CopyRequest {
|
||||
source: string;
|
||||
destination: string;
|
||||
}
|
||||
interface ShowRequest {
|
||||
model: string;
|
||||
system?: string;
|
||||
template?: string;
|
||||
options?: Partial<Options>;
|
||||
}
|
||||
interface EmbeddingsRequest {
|
||||
model: string;
|
||||
prompt: string;
|
||||
keep_alive?: string | number;
|
||||
options?: Partial<Options>;
|
||||
}
|
||||
interface GenerateResponse {
|
||||
model: string;
|
||||
created_at: Date;
|
||||
response: string;
|
||||
done: boolean;
|
||||
context: number[];
|
||||
total_duration: number;
|
||||
load_duration: number;
|
||||
prompt_eval_count: number;
|
||||
prompt_eval_duration: number;
|
||||
eval_count: number;
|
||||
eval_duration: number;
|
||||
}
|
||||
interface ChatResponse {
|
||||
model: string;
|
||||
created_at: Date;
|
||||
message: Message;
|
||||
done: boolean;
|
||||
total_duration: number;
|
||||
load_duration: number;
|
||||
prompt_eval_count: number;
|
||||
prompt_eval_duration: number;
|
||||
eval_count: number;
|
||||
eval_duration: number;
|
||||
}
|
||||
interface EmbeddingsResponse {
|
||||
embedding: number[];
|
||||
}
|
||||
interface ProgressResponse {
|
||||
status: string;
|
||||
digest: string;
|
||||
total: number;
|
||||
completed: number;
|
||||
}
|
||||
interface ModelResponse {
|
||||
name: string;
|
||||
modified_at: Date;
|
||||
size: number;
|
||||
digest: string;
|
||||
details: ModelDetails;
|
||||
}
|
||||
interface ModelDetails {
|
||||
parent_model: string;
|
||||
format: string;
|
||||
family: string;
|
||||
families: string[];
|
||||
parameter_size: string;
|
||||
quantization_level: string;
|
||||
}
|
||||
interface ShowResponse {
|
||||
license: string;
|
||||
modelfile: string;
|
||||
parameters: string;
|
||||
template: string;
|
||||
system: string;
|
||||
details: ModelDetails;
|
||||
messages: Message[];
|
||||
}
|
||||
interface ListResponse {
|
||||
models: ModelResponse[];
|
||||
}
|
||||
interface ErrorResponse {
|
||||
error: string;
|
||||
}
|
||||
interface StatusResponse {
|
||||
status: string;
|
||||
}
|
||||
|
||||
declare class Ollama {
|
||||
protected readonly config: Config;
|
||||
protected readonly fetch: Fetch;
|
||||
private abortController;
|
||||
constructor(config?: Partial<Config>);
|
||||
abort(): void;
|
||||
protected processStreamableRequest<T extends object>(
|
||||
endpoint: string,
|
||||
request: {
|
||||
stream?: boolean;
|
||||
} & Record<string, any>,
|
||||
): Promise<T | AsyncGenerator<T>>;
|
||||
encodeImage(image: Uint8Array | string): Promise<string>;
|
||||
generate(
|
||||
request: GenerateRequest & {
|
||||
stream: true;
|
||||
},
|
||||
): Promise<AsyncGenerator<GenerateResponse>>;
|
||||
generate(
|
||||
request: GenerateRequest & {
|
||||
stream?: false;
|
||||
},
|
||||
): Promise<GenerateResponse>;
|
||||
chat(
|
||||
request: ChatRequest & {
|
||||
stream: true;
|
||||
},
|
||||
): Promise<AsyncGenerator<ChatResponse>>;
|
||||
chat(
|
||||
request: ChatRequest & {
|
||||
stream?: false;
|
||||
},
|
||||
): Promise<ChatResponse>;
|
||||
create(
|
||||
request: CreateRequest & {
|
||||
stream: true;
|
||||
},
|
||||
): Promise<AsyncGenerator<ProgressResponse>>;
|
||||
create(
|
||||
request: CreateRequest & {
|
||||
stream?: false;
|
||||
},
|
||||
): Promise<ProgressResponse>;
|
||||
pull(
|
||||
request: PullRequest & {
|
||||
stream: true;
|
||||
},
|
||||
): Promise<AsyncGenerator<ProgressResponse>>;
|
||||
pull(
|
||||
request: PullRequest & {
|
||||
stream?: false;
|
||||
},
|
||||
): Promise<ProgressResponse>;
|
||||
push(
|
||||
request: PushRequest & {
|
||||
stream: true;
|
||||
},
|
||||
): Promise<AsyncGenerator<ProgressResponse>>;
|
||||
push(
|
||||
request: PushRequest & {
|
||||
stream?: false;
|
||||
},
|
||||
): Promise<ProgressResponse>;
|
||||
delete(request: DeleteRequest): Promise<StatusResponse>;
|
||||
copy(request: CopyRequest): Promise<StatusResponse>;
|
||||
list(): Promise<ListResponse>;
|
||||
show(request: ShowRequest): Promise<ShowResponse>;
|
||||
embeddings(request: EmbeddingsRequest): Promise<EmbeddingsResponse>;
|
||||
}
|
||||
declare const _default: Ollama;
|
||||
|
||||
export {
|
||||
Ollama,
|
||||
_default as default,
|
||||
type ChatRequest,
|
||||
type ChatResponse,
|
||||
type Config,
|
||||
type CopyRequest,
|
||||
type CreateRequest,
|
||||
type DeleteRequest,
|
||||
type EmbeddingsRequest,
|
||||
type EmbeddingsResponse,
|
||||
type ErrorResponse,
|
||||
type Fetch,
|
||||
type GenerateRequest,
|
||||
type GenerateResponse,
|
||||
type ListResponse,
|
||||
type Message,
|
||||
type ModelDetails,
|
||||
type ModelResponse,
|
||||
type Options,
|
||||
type ProgressResponse,
|
||||
type PullRequest,
|
||||
type PushRequest,
|
||||
type ShowRequest,
|
||||
type ShowResponse,
|
||||
type StatusResponse,
|
||||
};
|
||||
@@ -0,0 +1,462 @@
|
||||
// generate from "tsup ./src/browser.js --format esm --dts"
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
||||
var __knownSymbol = (name, symbol) => {
|
||||
return (symbol = Symbol[name]) ? symbol : Symbol.for("Symbol." + name);
|
||||
};
|
||||
var __defNormalProp = (obj, key, value) =>
|
||||
key in obj
|
||||
? __defProp(obj, key, {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value,
|
||||
})
|
||||
: (obj[key] = value);
|
||||
var __spreadValues = (a, b) => {
|
||||
for (var prop in b || (b = {}))
|
||||
if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]);
|
||||
if (__getOwnPropSymbols)
|
||||
for (var prop of __getOwnPropSymbols(b)) {
|
||||
if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]);
|
||||
}
|
||||
return a;
|
||||
};
|
||||
var __async = (__this, __arguments, generator) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
var fulfilled = (value) => {
|
||||
try {
|
||||
step(generator.next(value));
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
};
|
||||
var rejected = (value) => {
|
||||
try {
|
||||
step(generator.throw(value));
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
};
|
||||
var step = (x) =>
|
||||
x.done
|
||||
? resolve(x.value)
|
||||
: Promise.resolve(x.value).then(fulfilled, rejected);
|
||||
step((generator = generator.apply(__this, __arguments)).next());
|
||||
});
|
||||
};
|
||||
var __await = function (promise, isYieldStar) {
|
||||
this[0] = promise;
|
||||
this[1] = isYieldStar;
|
||||
};
|
||||
var __asyncGenerator = (__this, __arguments, generator) => {
|
||||
var resume = (k, v, yes, no) => {
|
||||
try {
|
||||
var x = generator[k](v),
|
||||
isAwait = (v = x.value) instanceof __await,
|
||||
done = x.done;
|
||||
Promise.resolve(isAwait ? v[0] : v)
|
||||
.then((y) =>
|
||||
isAwait
|
||||
? resume(
|
||||
k === "return" ? k : "next",
|
||||
v[1] ? { done: y.done, value: y.value } : y,
|
||||
yes,
|
||||
no,
|
||||
)
|
||||
: yes({ value: y, done }),
|
||||
)
|
||||
.catch((e) => resume("throw", e, yes, no));
|
||||
} catch (e) {
|
||||
no(e);
|
||||
}
|
||||
};
|
||||
var method = (k) =>
|
||||
(it[k] = (x) => new Promise((yes, no) => resume(k, x, yes, no)));
|
||||
var it = {};
|
||||
return (
|
||||
(generator = generator.apply(__this, __arguments)),
|
||||
(it[__knownSymbol("asyncIterator")] = () => it),
|
||||
method("next"),
|
||||
method("throw"),
|
||||
method("return"),
|
||||
it
|
||||
);
|
||||
};
|
||||
var __forAwait = (obj, it, method) =>
|
||||
(it = obj[__knownSymbol("asyncIterator")])
|
||||
? it.call(obj)
|
||||
: ((obj = obj[__knownSymbol("iterator")]()),
|
||||
(it = {}),
|
||||
(method = (key, fn) =>
|
||||
(fn = obj[key]) &&
|
||||
(it[key] = (arg) =>
|
||||
new Promise(
|
||||
(yes, no, done) => (
|
||||
(arg = fn.call(obj, arg)),
|
||||
(done = arg.done),
|
||||
Promise.resolve(arg.value).then(
|
||||
(value) => yes({ value, done }),
|
||||
no,
|
||||
)
|
||||
),
|
||||
))),
|
||||
method("next"),
|
||||
method("return"),
|
||||
it);
|
||||
|
||||
// src/version.ts
|
||||
var version = "0.0.0";
|
||||
|
||||
// src/utils.ts
|
||||
var ResponseError = class _ResponseError extends Error {
|
||||
constructor(error, status_code) {
|
||||
super(error);
|
||||
this.error = error;
|
||||
this.status_code = status_code;
|
||||
this.name = "ResponseError";
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, _ResponseError);
|
||||
}
|
||||
}
|
||||
};
|
||||
var checkOk = (response) =>
|
||||
__async(void 0, null, function* () {
|
||||
var _a;
|
||||
if (!response.ok) {
|
||||
let message = `Error ${response.status}: ${response.statusText}`;
|
||||
let errorData = null;
|
||||
if (
|
||||
(_a = response.headers.get("content-type")) == null
|
||||
? void 0
|
||||
: _a.includes("application/json")
|
||||
) {
|
||||
try {
|
||||
errorData = yield response.json();
|
||||
message = errorData.error || message;
|
||||
} catch (error) {
|
||||
console.log("Failed to parse error response as JSON");
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
console.log("Getting text from response");
|
||||
const textResponse = yield response.text();
|
||||
message = textResponse || message;
|
||||
} catch (error) {
|
||||
console.log("Failed to get text from error response");
|
||||
}
|
||||
}
|
||||
throw new ResponseError(message, response.status);
|
||||
}
|
||||
});
|
||||
function getPlatform() {
|
||||
if (typeof window !== "undefined" && window.navigator) {
|
||||
return `${window.navigator.platform.toLowerCase()} Browser/${navigator.userAgent};`;
|
||||
} else if (typeof process !== "undefined") {
|
||||
return `${process.arch} ${process.platform} Node.js/${process.version}`;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
var fetchWithHeaders = (_0, _1, ..._2) =>
|
||||
__async(void 0, [_0, _1, ..._2], function* (fetch2, url, options = {}) {
|
||||
const defaultHeaders = {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
"User-Agent": `ollama-js/${version} (${getPlatform()})`,
|
||||
};
|
||||
if (!options.headers) {
|
||||
options.headers = {};
|
||||
}
|
||||
options.headers = __spreadValues(
|
||||
__spreadValues({}, defaultHeaders),
|
||||
options.headers,
|
||||
);
|
||||
return fetch2(url, options);
|
||||
});
|
||||
var get = (fetch2, host) =>
|
||||
__async(void 0, null, function* () {
|
||||
const response = yield fetchWithHeaders(fetch2, host);
|
||||
yield checkOk(response);
|
||||
return response;
|
||||
});
|
||||
var post = (fetch2, host, data, options) =>
|
||||
__async(void 0, null, function* () {
|
||||
const isRecord = (input) => {
|
||||
return (
|
||||
input !== null && typeof input === "object" && !Array.isArray(input)
|
||||
);
|
||||
};
|
||||
const formattedData = isRecord(data) ? JSON.stringify(data) : data;
|
||||
const response = yield fetchWithHeaders(fetch2, host, {
|
||||
method: "POST",
|
||||
body: formattedData,
|
||||
signal: options == null ? void 0 : options.signal,
|
||||
});
|
||||
yield checkOk(response);
|
||||
return response;
|
||||
});
|
||||
var del = (fetch2, host, data) =>
|
||||
__async(void 0, null, function* () {
|
||||
const response = yield fetchWithHeaders(fetch2, host, {
|
||||
method: "DELETE",
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
yield checkOk(response);
|
||||
return response;
|
||||
});
|
||||
var parseJSON = function (itr) {
|
||||
return __asyncGenerator(this, null, function* () {
|
||||
var _a;
|
||||
const decoder = new TextDecoder("utf-8");
|
||||
let buffer = "";
|
||||
const reader = itr.getReader();
|
||||
while (true) {
|
||||
const { done, value: chunk } = yield new __await(reader.read());
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
buffer += decoder.decode(chunk);
|
||||
const parts = buffer.split("\n");
|
||||
buffer = (_a = parts.pop()) != null ? _a : "";
|
||||
for (const part of parts) {
|
||||
try {
|
||||
yield JSON.parse(part);
|
||||
} catch (error) {
|
||||
console.warn("invalid json: ", part);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const part of buffer.split("\n").filter((p) => p !== "")) {
|
||||
try {
|
||||
yield JSON.parse(part);
|
||||
} catch (error) {
|
||||
console.warn("invalid json: ", part);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
var formatHost = (host) => {
|
||||
if (!host) {
|
||||
return "http://127.0.0.1:11434";
|
||||
}
|
||||
let isExplicitProtocol = host.includes("://");
|
||||
if (host.startsWith(":")) {
|
||||
host = `http://127.0.0.1${host}`;
|
||||
isExplicitProtocol = false;
|
||||
}
|
||||
if (!isExplicitProtocol) {
|
||||
host = `http://${host}`;
|
||||
}
|
||||
const url = new URL(host);
|
||||
let port = url.port;
|
||||
if (!port) {
|
||||
if (!isExplicitProtocol) {
|
||||
port = "11434";
|
||||
} else {
|
||||
port = url.protocol === "https:" ? "443" : "80";
|
||||
}
|
||||
}
|
||||
let formattedHost = `${url.protocol}//${url.hostname}:${port}${url.pathname}`;
|
||||
if (formattedHost.endsWith("/")) {
|
||||
formattedHost = formattedHost.slice(0, -1);
|
||||
}
|
||||
return formattedHost;
|
||||
};
|
||||
|
||||
// src/browser.ts
|
||||
// import "whatwg-fetch";
|
||||
var Ollama = class {
|
||||
constructor(config) {
|
||||
var _a;
|
||||
this.config = {
|
||||
host: "",
|
||||
};
|
||||
if (!(config == null ? void 0 : config.proxy)) {
|
||||
this.config.host = formatHost(
|
||||
(_a = config == null ? void 0 : config.host) != null
|
||||
? _a
|
||||
: "http://127.0.0.1:11434",
|
||||
);
|
||||
}
|
||||
this.fetch = fetch;
|
||||
if ((config == null ? void 0 : config.fetch) != null) {
|
||||
this.fetch = config.fetch;
|
||||
}
|
||||
this.abortController = new AbortController();
|
||||
}
|
||||
// Abort any ongoing requests to Ollama
|
||||
abort() {
|
||||
this.abortController.abort();
|
||||
this.abortController = new AbortController();
|
||||
}
|
||||
processStreamableRequest(endpoint, request) {
|
||||
return __async(this, null, function* () {
|
||||
var _a;
|
||||
request.stream = (_a = request.stream) != null ? _a : false;
|
||||
const response = yield post(
|
||||
this.fetch,
|
||||
`${this.config.host}/api/${endpoint}`,
|
||||
__spreadValues({}, request),
|
||||
{ signal: this.abortController.signal },
|
||||
);
|
||||
if (!response.body) {
|
||||
throw new Error("Missing body");
|
||||
}
|
||||
const itr = parseJSON(response.body);
|
||||
if (request.stream) {
|
||||
return (function () {
|
||||
return __asyncGenerator(this, null, function* () {
|
||||
try {
|
||||
for (
|
||||
var iter = __forAwait(itr), more, temp, error;
|
||||
(more = !(temp = yield new __await(iter.next())).done);
|
||||
more = false
|
||||
) {
|
||||
const message = temp.value;
|
||||
if ("error" in message) {
|
||||
throw new Error(message.error);
|
||||
}
|
||||
yield message;
|
||||
if (message.done || message.status === "success") {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (temp) {
|
||||
error = [temp];
|
||||
} finally {
|
||||
try {
|
||||
more &&
|
||||
(temp = iter.return) &&
|
||||
(yield new __await(temp.call(iter)));
|
||||
} finally {
|
||||
if (error) throw error[0];
|
||||
}
|
||||
}
|
||||
throw new Error(
|
||||
"Did not receive done or success response in stream.",
|
||||
);
|
||||
});
|
||||
})();
|
||||
} else {
|
||||
const message = yield itr.next();
|
||||
if (!message.value.done && message.value.status !== "success") {
|
||||
throw new Error("Expected a completed response.");
|
||||
}
|
||||
return message.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
encodeImage(image) {
|
||||
return __async(this, null, function* () {
|
||||
if (typeof image !== "string") {
|
||||
const uint8Array = new Uint8Array(image);
|
||||
const numberArray = Array.from(uint8Array);
|
||||
const base64String = btoa(String.fromCharCode.apply(null, numberArray));
|
||||
return base64String;
|
||||
}
|
||||
return image;
|
||||
});
|
||||
}
|
||||
generate(request) {
|
||||
return __async(this, null, function* () {
|
||||
if (request.images) {
|
||||
request.images = yield Promise.all(
|
||||
request.images.map(this.encodeImage.bind(this)),
|
||||
);
|
||||
}
|
||||
return this.processStreamableRequest("generate", request);
|
||||
});
|
||||
}
|
||||
chat(request) {
|
||||
return __async(this, null, function* () {
|
||||
if (request.messages) {
|
||||
for (const message of request.messages) {
|
||||
if (message.images) {
|
||||
message.images = yield Promise.all(
|
||||
message.images.map(this.encodeImage.bind(this)),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.processStreamableRequest("chat", request);
|
||||
});
|
||||
}
|
||||
create(request) {
|
||||
return __async(this, null, function* () {
|
||||
return this.processStreamableRequest("create", {
|
||||
name: request.model,
|
||||
stream: request.stream,
|
||||
modelfile: request.modelfile,
|
||||
});
|
||||
});
|
||||
}
|
||||
pull(request) {
|
||||
return __async(this, null, function* () {
|
||||
return this.processStreamableRequest("pull", {
|
||||
name: request.model,
|
||||
stream: request.stream,
|
||||
insecure: request.insecure,
|
||||
});
|
||||
});
|
||||
}
|
||||
push(request) {
|
||||
return __async(this, null, function* () {
|
||||
return this.processStreamableRequest("push", {
|
||||
name: request.model,
|
||||
stream: request.stream,
|
||||
insecure: request.insecure,
|
||||
});
|
||||
});
|
||||
}
|
||||
delete(request) {
|
||||
return __async(this, null, function* () {
|
||||
yield del(this.fetch, `${this.config.host}/api/delete`, {
|
||||
name: request.model,
|
||||
});
|
||||
return { status: "success" };
|
||||
});
|
||||
}
|
||||
copy(request) {
|
||||
return __async(this, null, function* () {
|
||||
yield post(
|
||||
this.fetch,
|
||||
`${this.config.host}/api/copy`,
|
||||
__spreadValues({}, request),
|
||||
);
|
||||
return { status: "success" };
|
||||
});
|
||||
}
|
||||
list() {
|
||||
return __async(this, null, function* () {
|
||||
const response = yield get(this.fetch, `${this.config.host}/api/tags`);
|
||||
const listResponse = yield response.json();
|
||||
return listResponse;
|
||||
});
|
||||
}
|
||||
show(request) {
|
||||
return __async(this, null, function* () {
|
||||
const response = yield post(
|
||||
this.fetch,
|
||||
`${this.config.host}/api/show`,
|
||||
__spreadValues({}, request),
|
||||
);
|
||||
const showResponse = yield response.json();
|
||||
return showResponse;
|
||||
});
|
||||
}
|
||||
embeddings(request) {
|
||||
return __async(this, null, function* () {
|
||||
const response = yield post(
|
||||
this.fetch,
|
||||
`${this.config.host}/api/embeddings`,
|
||||
__spreadValues({}, request),
|
||||
);
|
||||
const embeddingsResponse = yield response.json();
|
||||
return embeddingsResponse;
|
||||
});
|
||||
}
|
||||
};
|
||||
var browser_default = new Ollama();
|
||||
export { Ollama, browser_default as default };
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2023 Saul
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,15 @@
|
||||
let transformer: typeof import("@xenova/transformers") | null = null;
|
||||
|
||||
export async function lazyLoadTransformers() {
|
||||
if (!transformer) {
|
||||
transformer = await import("@xenova/transformers");
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
if (typeof EdgeRuntime === "string") {
|
||||
// there is no local file system in the edge runtime
|
||||
transformer.env.allowLocalModels = false;
|
||||
}
|
||||
// fixme: handle cloudflare workers case here?
|
||||
return transformer;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
export type Logger = {
|
||||
log: (...args: unknown[]) => void;
|
||||
error: (...args: unknown[]) => void;
|
||||
warn: (...args: unknown[]) => void;
|
||||
};
|
||||
|
||||
export const emptyLogger: Logger = Object.freeze({
|
||||
log: () => {},
|
||||
error: () => {},
|
||||
warn: () => {},
|
||||
});
|
||||
|
||||
export const consoleLogger: Logger = Object.freeze({
|
||||
log: console.log.bind(console),
|
||||
error: console.error.bind(console),
|
||||
warn: console.warn.bind(console),
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user