Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | |||
| b440a008e5 | |||
| 46227f2a70 | |||
| 77f0298f6f | |||
| c14e112236 | |||
| 62b035fdc1 | |||
| aa0be1469b | |||
| 5016f21d52 | |||
| 130b7992a1 | |||
| 0d50b22dbf | |||
| db1d1f57c9 | |||
| dccb8163d8 | |||
| 1ab3ba407e | |||
| b03f765733 | |||
| 7488d3c235 | |||
| 5cb270d07f | |||
| 62771058aa | |||
| ca348a6570 | |||
| 44a7fd72e8 | |||
| d8d952d937 |
@@ -0,0 +1,37 @@
|
||||
name: Publish to GitHub Releases
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "llamaindex@*"
|
||||
|
||||
jobs:
|
||||
build-and-publish:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v3
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
cache: "pnpm"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
|
||||
- name: Build tarball
|
||||
run: |
|
||||
pnpm pack
|
||||
working-directory: packages/core
|
||||
|
||||
- name: Create release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: "packages/core/llamaindex-*.tgz"
|
||||
name: Release ${{ github.ref }}
|
||||
bodyFile: "packages/core/CHANGELOG.md"
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -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
|
||||
@@ -84,9 +84,16 @@ jobs:
|
||||
name: typecheck-build-dist
|
||||
path: ./packages/core/dist
|
||||
if-no-files-found: error
|
||||
core-edge-runtime:
|
||||
e2e-core-examples:
|
||||
strategy:
|
||||
matrix:
|
||||
packages:
|
||||
- cloudflare-worker-agent
|
||||
- nextjs-agent
|
||||
- nextjs-edge-runtime
|
||||
- waku-query-engine
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
name: Build Core Example (${{ matrix.packages }})
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v3
|
||||
@@ -97,11 +104,12 @@ jobs:
|
||||
cache: "pnpm"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Build
|
||||
run: pnpm run build --filter @llamaindex/edge
|
||||
- name: Build Edge Runtime
|
||||
- name: Build llamaindex
|
||||
run: pnpm run build
|
||||
working-directory: ./packages/edge/e2e/test-edge-runtime
|
||||
- name: Build ${{ matrix.packages }}
|
||||
run: pnpm run build
|
||||
working-directory: packages/core/e2e/examples/${{ matrix.packages }}
|
||||
|
||||
typecheck-examples:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -116,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
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
pnpm format
|
||||
pnpm format:write
|
||||
pnpm lint
|
||||
npx lint-staged
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
pnpm test
|
||||
@@ -19,25 +19,29 @@ Try examples online:
|
||||
|
||||
LlamaIndex.TS aims to be a lightweight, easy to use set of libraries to help you integrate large language models into your applications with your own data.
|
||||
|
||||
## Getting started with an example:
|
||||
## Multiple JS Environment Support
|
||||
|
||||
LlamaIndex.TS requires Node v18 or higher. You can download it from https://nodejs.org or use https://nvm.sh (our preferred option).
|
||||
LlamaIndex.TS supports multiple JS environments, including:
|
||||
|
||||
In a new folder:
|
||||
- Node.js (18, 20, 22) ✅
|
||||
- Deno ✅
|
||||
- Bun ✅
|
||||
- React Server Components (Next.js) ✅
|
||||
|
||||
```bash
|
||||
export OPENAI_API_KEY="sk-......" # Replace with your key from https://platform.openai.com/account/api-keys
|
||||
pnpm init
|
||||
pnpm install typescript
|
||||
pnpm exec tsc --init # if needed
|
||||
For now, browser support is limited due to the lack of support for [AsyncLocalStorage-like APIs](https://github.com/tc39/proposal-async-context)
|
||||
|
||||
## Getting started
|
||||
|
||||
```shell
|
||||
npm install llamaindex
|
||||
pnpm install llamaindex
|
||||
pnpm install @types/node
|
||||
yarn add llamaindex
|
||||
jsr install @llamaindex/core
|
||||
```
|
||||
|
||||
Create the file example.ts
|
||||
### Node.js
|
||||
|
||||
```ts
|
||||
// example.ts
|
||||
import fs from "fs/promises";
|
||||
import { Document, VectorStoreIndex } from "llamaindex";
|
||||
|
||||
@@ -67,10 +71,121 @@ async function main() {
|
||||
main();
|
||||
```
|
||||
|
||||
Then you can run it using
|
||||
|
||||
```bash
|
||||
pnpm dlx ts-node example.ts
|
||||
# `pnpm install tsx` before running the script
|
||||
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
|
||||
// src/apps/page.tsx
|
||||
"use client";
|
||||
import { chatWithAgent } from "@/actions";
|
||||
import type { JSX } from "react";
|
||||
import { useFormState } from "react-dom";
|
||||
|
||||
// You can use the Edge runtime in Next.js by adding this line:
|
||||
// export const runtime = "edge";
|
||||
|
||||
export default function Home() {
|
||||
const [ui, action] = useFormState<JSX.Element | null>(async () => {
|
||||
return chatWithAgent("hello!", []);
|
||||
}, null);
|
||||
return (
|
||||
<main>
|
||||
{ui}
|
||||
<form action={action}>
|
||||
<button>Chat</button>
|
||||
</form>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
```tsx
|
||||
// src/actions/index.ts
|
||||
"use server";
|
||||
import { createStreamableUI } from "ai/rsc";
|
||||
import { OpenAIAgent } from "llamaindex";
|
||||
import type { ChatMessage } from "llamaindex/llm/types";
|
||||
|
||||
export async function chatWithAgent(
|
||||
question: string,
|
||||
prevMessages: ChatMessage[] = [],
|
||||
) {
|
||||
const agent = new OpenAIAgent({
|
||||
tools: [
|
||||
// ... adding your tools here
|
||||
],
|
||||
});
|
||||
const responseStream = await agent.chat({
|
||||
stream: true,
|
||||
message: question,
|
||||
chatHistory: prevMessages,
|
||||
});
|
||||
const uiStream = createStreamableUI(<div>loading...</div>);
|
||||
responseStream
|
||||
.pipeTo(
|
||||
new WritableStream({
|
||||
start: () => {
|
||||
uiStream.update("response:");
|
||||
},
|
||||
write: async (message) => {
|
||||
uiStream.append(message.response.delta);
|
||||
},
|
||||
}),
|
||||
)
|
||||
.catch(console.error);
|
||||
return uiStream.value;
|
||||
}
|
||||
```
|
||||
|
||||
### Cloudflare Workers
|
||||
|
||||
```ts
|
||||
// src/index.ts
|
||||
export default {
|
||||
async fetch(
|
||||
request: Request,
|
||||
env: Env,
|
||||
ctx: ExecutionContext,
|
||||
): Promise<Response> {
|
||||
const { setEnvs } = await import("@llamaindex/env");
|
||||
// set environment variables so that the OpenAIAgent can use them
|
||||
setEnvs(env);
|
||||
const { OpenAIAgent } = await import("llamaindex");
|
||||
const agent = new OpenAIAgent({
|
||||
tools: [],
|
||||
});
|
||||
const responseStream = await agent.chat({
|
||||
stream: true,
|
||||
message: "Hello? What is the weather today?",
|
||||
});
|
||||
const textEncoder = new TextEncoder();
|
||||
const response = responseStream.pipeThrough(
|
||||
new TransformStream({
|
||||
transform: (chunk, controller) => {
|
||||
controller.enqueue(textEncoder.encode(chunk.response.delta));
|
||||
},
|
||||
}),
|
||||
);
|
||||
return new Response(response);
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
## Playground
|
||||
@@ -93,79 +208,25 @@ Check out our NextJS playground at https://llama-playground.vercel.app/. The sou
|
||||
|
||||
- [SimplePrompt](/packages/core/src/Prompt.ts): A simple standardized function call definition that takes in inputs and formats them in a template literal. SimplePrompts can be specialized using currying and combined using other SimplePrompt functions.
|
||||
|
||||
## Using NextJS
|
||||
## Tips when using in non-Node.js environments
|
||||
|
||||
If you're using the NextJS App Router, you can choose between the Node.js and the [Edge runtime](https://nextjs.org/docs/app/building-your-application/rendering/edge-and-nodejs-runtimes#edge-runtime).
|
||||
When you are importing `llamaindex` in a non-Node.js environment(such as React Server Components, Cloudflare Workers, etc.)
|
||||
Some classes are not exported from top-level entry file.
|
||||
|
||||
With NextJS 13 and 14, using the Node.js runtime is the default. You can explicitly set the Edge runtime in your [router handler](https://nextjs.org/docs/app/building-your-application/routing/route-handlers) by adding this line:
|
||||
The reason is that some classes are only compatible with Node.js runtime,(e.g. `PDFReader`) which uses Node.js specific APIs(like `fs`, `child_process`, `crypto`).
|
||||
|
||||
If you need any of those classes, you have to import them instead directly though their file path in the package.
|
||||
Here's an example for importing the `PineconeVectorStore` class:
|
||||
|
||||
```typescript
|
||||
export const runtime = "edge";
|
||||
```
|
||||
|
||||
The following sections explain further differences in using the Node.js or Edge runtime.
|
||||
|
||||
### Using the Node.js runtime
|
||||
|
||||
Add the following config to your `next.config.js` to ignore specific packages in the server-side bundling:
|
||||
|
||||
```js
|
||||
// next.config.js
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
experimental: {
|
||||
serverComponentsExternalPackages: [
|
||||
"pdf2json",
|
||||
"@zilliz/milvus2-sdk-node",
|
||||
"sharp",
|
||||
"onnxruntime-node",
|
||||
],
|
||||
},
|
||||
webpack: (config) => {
|
||||
config.externals.push({
|
||||
pdf2json: "commonjs pdf2json",
|
||||
"@zilliz/milvus2-sdk-node": "commonjs @zilliz/milvus2-sdk-node",
|
||||
sharp: "commonjs sharp",
|
||||
"onnxruntime-node": "commonjs onnxruntime-node",
|
||||
});
|
||||
|
||||
return config;
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = nextConfig;
|
||||
```
|
||||
|
||||
### Using the Edge runtime
|
||||
|
||||
We publish a dedicated package (`@llamaindex/edge` instead of `llamaindex`) for using the Edge runtime. To use it, first install the package:
|
||||
|
||||
```shell
|
||||
pnpm install @llamaindex/edge
|
||||
```
|
||||
|
||||
> _Note_: Ensure that your `package.json` doesn't include the `llamaindex` package if you're using `@llamaindex/edge`.
|
||||
|
||||
Then make sure to use the correct import statement in your code:
|
||||
|
||||
```typescript
|
||||
// replace 'llamaindex' with '@llamaindex/edge'
|
||||
import {} from "@llamaindex/edge";
|
||||
```
|
||||
|
||||
A further difference is that the `@llamaindex/edge` package doesn't export classes from the `readers` or `storage` folders. The reason is that most of these classes are not compatible with the Edge runtime.
|
||||
|
||||
If you need any of those classes, you have to import them instead directly. Here's an example for importing the `PineconeVectorStore` class:
|
||||
|
||||
```typescript
|
||||
import { PineconeVectorStore } from "@llamaindex/edge/storage/vectorStore/PineconeVectorStore";
|
||||
import { PineconeVectorStore } from "llamaindex/storage/vectorStore/PineconeVectorStore";
|
||||
```
|
||||
|
||||
As the `PDFReader` is not working with the Edge runtime, here's how to use the `SimpleDirectoryReader` with the `LlamaParseReader` to load PDFs:
|
||||
|
||||
```typescript
|
||||
import { SimpleDirectoryReader } from "@llamaindex/edge/readers/SimpleDirectoryReader";
|
||||
import { LlamaParseReader } from "@llamaindex/edge/readers/LlamaParseReader";
|
||||
import { SimpleDirectoryReader } from "llamaindex/readers/SimpleDirectoryReader";
|
||||
import { LlamaParseReader } from "llamaindex/readers/LlamaParseReader";
|
||||
|
||||
export const DATA_DIR = "./data";
|
||||
|
||||
@@ -183,7 +244,7 @@ export async function getDocuments() {
|
||||
|
||||
> _Note_: Reader classes have to be added explictly to the `fileExtToReader` map in the Edge version of the `SimpleDirectoryReader`.
|
||||
|
||||
You'll find a complete example of using the Edge runtime with LlamaIndexTS here: https://github.com/run-llama/create_llama_projects/tree/main/nextjs-edge-llamaparse
|
||||
You'll find a complete example with LlamaIndexTS here: https://github.com/run-llama/create_llama_projects/tree/main/nextjs-edge-llamaparse
|
||||
|
||||
## Supported LLMs:
|
||||
|
||||
|
||||
@@ -1,5 +1,99 @@
|
||||
# docs
|
||||
|
||||
## 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
|
||||
|
||||
- Updated dependencies [46227f2]
|
||||
- llamaindex@0.3.1
|
||||
|
||||
## 0.0.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5016f21]
|
||||
- llamaindex@0.3.0
|
||||
|
||||
## 0.0.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [6277105]
|
||||
- llamaindex@0.2.13
|
||||
|
||||
## 0.0.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [d8d952d]
|
||||
- llamaindex@0.2.12
|
||||
|
||||
## 0.0.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -0,0 +1,493 @@
|
||||
---
|
||||
title: LlamaIndexTS v0.3.0
|
||||
description: This is my first post on Docusaurus.
|
||||
slug: welcome-llamaindexts-v0.3
|
||||
authors:
|
||||
- name: Alex Yang
|
||||
title: LlamaIndexTS maintainer, Node.js Member
|
||||
url: https://github.com/himself65
|
||||
image_url: https://github.com/himself65.png
|
||||
tags: [llamaindex, agent]
|
||||
hide_table_of_contents: false
|
||||
---
|
||||
|
||||
- [What's new in LlamaIndexTS v0.3.0](#whats-new-in-llamaindexts-v030)
|
||||
- [Improvement in LlamaIndexTS v0.3.0](#improvement-in-llamaindexts-v030)
|
||||
- [What's the next?](#whats-the-next)
|
||||
|
||||
## What's new in LlamaIndexTS v0.3.0
|
||||
|
||||
## Agents
|
||||
|
||||
In this release, we've not only ported the Agent module from the LlamaIndex Python version but have significantly
|
||||
enhanced it to be more powerful and user-friendly for JavaScript/TypeScript applications.
|
||||
|
||||
Starting from v0.3.0, we are introducing multiple agents specifically designed for RAG applications, including:
|
||||
|
||||
- `OpenAIAgent`
|
||||
- `AnthropicAgent`
|
||||
- `ReActAgent`:
|
||||
|
||||
```ts
|
||||
import { OpenAIAgent } from "llamaindex";
|
||||
import { tools } from "./tools";
|
||||
|
||||
const agent = new OpenAIAgent({
|
||||
tools: [...tools],
|
||||
});
|
||||
const { response } = await agent.chat({
|
||||
message: "What is weather today?",
|
||||
stream: false,
|
||||
});
|
||||
|
||||
console.log(response.message.content);
|
||||
```
|
||||
|
||||
We are also introducing the abstract AgentRunner class, which allows you to create your own agent by simply implementing
|
||||
the task handler.
|
||||
|
||||
```ts
|
||||
import { AgentRunner, OpenAI } from "llamaindex";
|
||||
|
||||
class MyLLM extends OpenAI {}
|
||||
|
||||
export class MyAgentWorker extends AgentWorker<MyLLM> {
|
||||
taskHandler = MyAgent.taskHandler;
|
||||
}
|
||||
|
||||
export class MyAgent extends AgentRunner<MyLLM> {
|
||||
constructor(params: Params) {
|
||||
super({
|
||||
llm: params.llm,
|
||||
chatHistory: params.chatHistory ?? [],
|
||||
systemPrompt: params.systemPrompt ?? null,
|
||||
runner: new MyAgentWorker(),
|
||||
tools:
|
||||
"tools" in params
|
||||
? params.tools
|
||||
: params.toolRetriever.retrieve.bind(params.toolRetriever),
|
||||
});
|
||||
}
|
||||
|
||||
// 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, enqueueOutput) => {
|
||||
const { llm, stream } = step.context;
|
||||
// initialize the input
|
||||
const response = await llm.chat({
|
||||
stream,
|
||||
messages: step.context.store.messages,
|
||||
});
|
||||
// store the response for next task step
|
||||
step.context.store.messages = [
|
||||
...step.context.store.messages,
|
||||
response.message,
|
||||
];
|
||||
// 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,
|
||||
role: "user",
|
||||
},
|
||||
];
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### Web Stream API for Streaming response
|
||||
|
||||
Web Stream is a web standard utilized in many modern web frameworks and libraries (like React 19, Deno, Node 22). We
|
||||
have migrated streaming responses to Web Stream to ensure broader compatibility.
|
||||
|
||||
For instance, you can use the streaming response in a simple HTTP Server:
|
||||
|
||||
```ts
|
||||
import { createServer } from "http";
|
||||
import { OpenAIAgent } from "llamaindex";
|
||||
import { OpenAIStream, streamToResponse } from "ai";
|
||||
import { tools } from "./tools";
|
||||
|
||||
const agent = new OpenAIAgent({
|
||||
tools: [...tools],
|
||||
});
|
||||
|
||||
const server = createServer(async (req, res) => {
|
||||
const response = await agent.chat({
|
||||
message: "What is weather today?",
|
||||
stream: true,
|
||||
});
|
||||
|
||||
// Transform the response into a string readable stream
|
||||
const stream: ReadableStream<string> = response.pipeThrough(
|
||||
new TransformStream({
|
||||
transform: (chunk, controller) => {
|
||||
controller.enqueue(chunk.response.delta);
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
// Pipe the stream to the response
|
||||
streamToResponse(stream, res);
|
||||
});
|
||||
|
||||
server.listen(3000);
|
||||
```
|
||||
|
||||
Or it can be integrated into React Server Components (RSC) in Next.js:
|
||||
|
||||
```tsx
|
||||
// app/actions/index.tsx
|
||||
"use server";
|
||||
import { createStreamableUI } from "ai/rsc";
|
||||
import { OpenAIAgent } from "llamaindex";
|
||||
import type { ChatMessage } from "llamaindex/llm/types";
|
||||
|
||||
export async function chatWithAgent(
|
||||
question: string,
|
||||
prevMessages: ChatMessage[] = [],
|
||||
) {
|
||||
const agent = new OpenAIAgent({
|
||||
tools: [],
|
||||
});
|
||||
const responseStream = await agent.chat({
|
||||
stream: true,
|
||||
message: question,
|
||||
chatHistory: prevMessages,
|
||||
});
|
||||
const uiStream = createStreamableUI(<div>loading...</div>);
|
||||
responseStream
|
||||
.pipeTo(
|
||||
new WritableStream({
|
||||
start: () => {
|
||||
uiStream.update("response:");
|
||||
},
|
||||
write: async (message) => {
|
||||
uiStream.append(message.response.delta);
|
||||
},
|
||||
}),
|
||||
)
|
||||
.catch(uiStream.error);
|
||||
return uiStream.value;
|
||||
}
|
||||
```
|
||||
|
||||
```tsx
|
||||
// app/src/page.tsx
|
||||
"use client";
|
||||
import { chatWithAgent } from "@/actions";
|
||||
import type { JSX } from "react";
|
||||
import { useFormState } from "react-dom";
|
||||
|
||||
export const runtime = "edge";
|
||||
|
||||
export default function Home() {
|
||||
const [state, action] = useFormState<JSX.Element | null>(async () => {
|
||||
return chatWithAgent("hello!", []);
|
||||
}, null);
|
||||
return (
|
||||
<main>
|
||||
{state}
|
||||
<form action={action}>
|
||||
<button>Chat</button>
|
||||
</form>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Improvement in LlamaIndexTS v0.3.0
|
||||
|
||||
### Better TypeScript support
|
||||
|
||||
We have made significant improvements to the type system to ensure that all code is thoroughly checked before it is
|
||||
published. This ongoing enhancement has already resulted in better module reliability and developer experience.
|
||||
|
||||
For example, we have improved `FunctionTool` type with generic support:
|
||||
|
||||
```ts
|
||||
type Input = {
|
||||
a: number;
|
||||
b: number;
|
||||
};
|
||||
|
||||
const sumNumbers = FunctionTool.from<Input>(
|
||||
({ a, b }) => `${a + b}`, // a and b will be checked as number
|
||||
// JSON schema will be an error if you type wrong.
|
||||
{
|
||||
name: "sumNumbers",
|
||||
description: "Use this function to sum two numbers",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
a: {
|
||||
type: "number",
|
||||
description: "The first number",
|
||||
},
|
||||
b: {
|
||||
type: "number",
|
||||
description: "The second number",
|
||||
},
|
||||
},
|
||||
required: ["a", "b"],
|
||||
},
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Better Next.js, Deno, Cloudflare Worker, and Waku(Vite) support
|
||||
|
||||
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:
|
||||
|
||||
```sh
|
||||
jsr add @llamaindex/core
|
||||
```
|
||||
|
||||
#### [Cloudflare Worker](https://developers.cloudflare.com/workers/)
|
||||
|
||||
For Cloudflare Workers, here is a starter template:
|
||||
|
||||
```typescript
|
||||
export default {
|
||||
async fetch(
|
||||
request: Request,
|
||||
env: Env,
|
||||
ctx: ExecutionContext,
|
||||
): Promise<Response> {
|
||||
const { setEnvs } = await import("@llamaindex/env");
|
||||
setEnvs(env);
|
||||
const { OpenAIAgent } = await import("llamaindex");
|
||||
const agent = new OpenAIAgent({
|
||||
tools: [],
|
||||
});
|
||||
const responseStream = await agent.chat({
|
||||
stream: true,
|
||||
message: "Hello? What is the weather today?",
|
||||
});
|
||||
const textEncoder = new TextEncoder();
|
||||
const response = responseStream.pipeThrough(
|
||||
new TransformStream({
|
||||
transform: (chunk, controller) => {
|
||||
controller.enqueue(textEncoder.encode(chunk.response.delta));
|
||||
},
|
||||
}),
|
||||
);
|
||||
return new Response(response);
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### [Waku (Vite)](https://waku.gg/)
|
||||
|
||||
Waku powered by Vite is a minimal React framework that supports multiple JS environments, including Deno, Cloudflare, and
|
||||
Node.js.
|
||||
|
||||
You can use LlamaIndexTS with Node.js output to enable full Node.js support with React.
|
||||
|
||||
```sh
|
||||
npm install llamaindex
|
||||
```
|
||||
|
||||
```ts
|
||||
// file: src/actions.ts
|
||||
"use server";
|
||||
import { Document, VectorStoreIndex } from "llamaindex";
|
||||
import { readFile } from "node:fs/promises";
|
||||
|
||||
const path = "node_modules/llamaindex/examples/abramov.txt";
|
||||
|
||||
const essay = await readFile(path, "utf-8");
|
||||
|
||||
// Create Document object with essay
|
||||
const document = new Document({ text: essay, id_: path });
|
||||
|
||||
// Split text and create embeddings. Store them in a VectorStoreIndex
|
||||
const index = await VectorStoreIndex.fromDocuments([document]);
|
||||
|
||||
const queryEngine = index.asQueryEngine();
|
||||
|
||||
export async function chatWithAI(question: string): Promise<string> {
|
||||
const { response } = await queryEngine.query({ query: question });
|
||||
return response;
|
||||
}
|
||||
```
|
||||
|
||||
```tsx
|
||||
// file: src/pages/index.tsx
|
||||
import { chatWithAI } from "./actions";
|
||||
|
||||
export default async function HomePage() {
|
||||
return (
|
||||
<div>
|
||||
<Chat askQuestion={chatWithAI} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
```tsx
|
||||
// file: src/components/Chat.tsx
|
||||
"use client";
|
||||
|
||||
export type ChatProps = {
|
||||
askQuestion: (question: string) => Promise<string>;
|
||||
};
|
||||
|
||||
export const Chat = (props: ChatProps) => {
|
||||
const [response, setResponse] = useState<string | null>(null);
|
||||
|
||||
return (
|
||||
<section className="border-blue-400 -mx-4 mt-4 rounded border border-dashed p-4">
|
||||
<h2 className="text-lg font-bold">Chat with AI</h2>
|
||||
{response ? (
|
||||
<p className="text-sm text-gray-600 max-w-sm">{response}</p>
|
||||
) : null}
|
||||
<form
|
||||
action={async (formData) => {
|
||||
const question = formData.get("question") as string | null;
|
||||
if (question) {
|
||||
setResponse(await props.askQuestion(question));
|
||||
}
|
||||
}}
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
name="question"
|
||||
className="border border-gray-400 rounded-sm px-2 py-0.5 text-sm"
|
||||
/>
|
||||
<button className="rounded-sm bg-black px-2 py-0.5 text-sm text-white">
|
||||
Ask
|
||||
</button>
|
||||
</form>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
```shell
|
||||
waku dev # development mode
|
||||
waku build # build for production
|
||||
waku start # start the production server
|
||||
```
|
||||
|
||||
Note that not all the modules are supported in all JS environments because of
|
||||
lack of the file system, network API,
|
||||
and incompatibility with the Node.js API by upstream dependencies.
|
||||
|
||||
But we are trying to make it more compatible with all the environments.
|
||||
|
||||
## What's the next?
|
||||
|
||||
As we continue to develop LlamaIndexTS, our focus remains on providing more comprehensive and powerful tools for
|
||||
creating custom agents.
|
||||
|
||||
### Align with the Python `llama-index`
|
||||
|
||||
We aim to align LlamaIndexTS with the Python version to ensure API consistency and ease of use for developers familiar
|
||||
with the Python ecosystem.
|
||||
|
||||
### Align with the Web Standard and JS development
|
||||
|
||||
Not all python APIs are compatible and easy to use in JavaScript/TypeScript.
|
||||
We are trying to make the API more compatible with the Web Standard and JavaScript modern development.
|
||||
|
||||
### More Agents
|
||||
|
||||
Future releases will introduce more agents from the Python Llama-Index and explore APIs tailored to real-world use
|
||||
cases.
|
||||
|
||||
### 🧪 `@llamaindex/tool`
|
||||
|
||||
We are exploring innovative ways to create tools for agents. The `@llamaindex/tool` library allows you to transform any
|
||||
function into a tool for an agent, simplifying the development process and reducing runtime costs.
|
||||
|
||||
```ts
|
||||
export function getWeather(city: string) {
|
||||
return `The weather in ${city} is sunny.`;
|
||||
}
|
||||
|
||||
// you don't need to worry about the shcema with different llm tools
|
||||
export function getTemperature(city: string) {
|
||||
return `The temperature in ${city} is 25°C.`;
|
||||
}
|
||||
|
||||
export function getCurrentCity() {
|
||||
return "New York";
|
||||
}
|
||||
```
|
||||
|
||||
These functions can be easily integrated into your applications, such as Next.js:
|
||||
|
||||
```ts
|
||||
"use server";
|
||||
import { OpenAI } from "openai";
|
||||
import { getTools } from "@llamaindex/tool";
|
||||
|
||||
export async function chat(message: string) {
|
||||
const openai = new OpenAI();
|
||||
openai.chat.completions.create({
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: "What is the weather in the current city?",
|
||||
},
|
||||
],
|
||||
tools: getTools("openai"),
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
// next.config.js
|
||||
const withTool = require("@llamaindex/tool/next");
|
||||
|
||||
const config = {
|
||||
// Your original Next.js config
|
||||
};
|
||||
module.exports = withTool(config);
|
||||
```
|
||||
|
||||
The functions are automatically transformed into tools for the agent at compile time, which eliminates any extra runtime
|
||||
costs. This feature is particularly beneficial when you need to debug or deploy your assistant.
|
||||
|
||||
For deploying your local functions into OpenAI, you can use a simple command:
|
||||
|
||||
```sh
|
||||
npm install -g @llamaindex/tool
|
||||
mkai --tools ./src/index.llama.ts
|
||||
# Successfully created assistant: asst_XXX
|
||||
# chat with your assistant by `chatai --assistant asst_XXX`
|
||||
chatai --assistant asst_XXX
|
||||
# Open your browser and chat with your assistant
|
||||
# Running at http://localhost:3000
|
||||
```
|
||||
|
||||
This deployment process simplifies the testing and implementation of your custom tools in a live environment.
|
||||
|
||||
As this project is still in its early stages, we continue to explore the best ways to create and integrate tools for
|
||||
agents. For more information and updates, visit the @llamaindex/tool repository.
|
||||
|
||||
This release of LlamaIndexTS v0.3.0 marks a significant step forward in our journey to provide developers with robust,
|
||||
flexible tools for building advanced agents. We are excited to see how our community utilizes these new capabilities to
|
||||
create innovative solutions and look forward to continuing to support and enhance LlamaIndexTS in future updates.
|
||||
|
After Width: | Height: | Size: 178 KiB |
@@ -0,0 +1,33 @@
|
||||
# Gemini
|
||||
|
||||
To use Gemini embeddings, you need to import `GeminiEmbedding` from `llamaindex`.
|
||||
|
||||
```ts
|
||||
import { GeminiEmbedding, Settings } from "llamaindex";
|
||||
|
||||
// Update Embed Model
|
||||
Settings.embedModel = new GeminiEmbedding();
|
||||
|
||||
const document = new Document({ text: essay, id_: "essay" });
|
||||
|
||||
const index = await VectorStoreIndex.fromDocuments([document]);
|
||||
|
||||
const queryEngine = index.asQueryEngine();
|
||||
|
||||
const query = "What is the meaning of life?";
|
||||
|
||||
const results = await queryEngine.query({
|
||||
query,
|
||||
});
|
||||
```
|
||||
|
||||
Per default, `GeminiEmbedding` is using the `gemini-pro` model. You can change the model by passing the `model` parameter to the constructor.
|
||||
For example:
|
||||
|
||||
```ts
|
||||
import { GEMINI_MODEL, GeminiEmbedding } from "llamaindex";
|
||||
|
||||
Settings.embedModel = new GeminiEmbedding({
|
||||
model: GEMINI_MODEL.GEMINI_PRO_LATEST,
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,71 @@
|
||||
# Gemini
|
||||
|
||||
## Usage
|
||||
|
||||
```ts
|
||||
import { Gemini, Settings, GEMINI_MODEL } from "llamaindex";
|
||||
|
||||
Settings.llm = new Gemini({
|
||||
model: GEMINI_MODEL.GEMINI_PRO,
|
||||
});
|
||||
```
|
||||
|
||||
## Load and index documents
|
||||
|
||||
For this example, we will use a single document. In a real-world scenario, you would have multiple documents to index.
|
||||
|
||||
```ts
|
||||
const document = new Document({ text: essay, id_: "essay" });
|
||||
|
||||
const index = await VectorStoreIndex.fromDocuments([document]);
|
||||
```
|
||||
|
||||
## Query
|
||||
|
||||
```ts
|
||||
const queryEngine = index.asQueryEngine();
|
||||
|
||||
const query = "What is the meaning of life?";
|
||||
|
||||
const results = await queryEngine.query({
|
||||
query,
|
||||
});
|
||||
```
|
||||
|
||||
## Full Example
|
||||
|
||||
```ts
|
||||
import {
|
||||
Gemini,
|
||||
Document,
|
||||
VectorStoreIndex,
|
||||
Settings,
|
||||
GEMINI_MODEL,
|
||||
} from "llamaindex";
|
||||
|
||||
Settings.llm = new Gemini({
|
||||
model: GEMINI_MODEL.GEMINI_PRO,
|
||||
});
|
||||
|
||||
async function main() {
|
||||
const document = new Document({ text: essay, id_: "essay" });
|
||||
|
||||
// Load and index documents
|
||||
const index = await VectorStoreIndex.fromDocuments([document]);
|
||||
|
||||
// Create a query engine
|
||||
const queryEngine = index.asQueryEngine({
|
||||
retriever,
|
||||
});
|
||||
|
||||
const query = "What is the meaning of life?";
|
||||
|
||||
// Query
|
||||
const response = await queryEngine.query({
|
||||
query,
|
||||
});
|
||||
|
||||
// Log the response
|
||||
console.log(response.response);
|
||||
}
|
||||
```
|
||||
@@ -66,7 +66,11 @@ const config = {
|
||||
[require("@docusaurus/remark-plugin-npm2yarn"), { sync: true }],
|
||||
],
|
||||
},
|
||||
blog: false,
|
||||
blog: {
|
||||
blogTitle: "LlamaIndexTS blog",
|
||||
blogDescription: "The official blog of LlamaIndexTS",
|
||||
postsPerPage: "ALL",
|
||||
},
|
||||
gtag: {
|
||||
trackingID: "G-NB9B8LW9W5",
|
||||
anonymizeIP: true,
|
||||
@@ -97,6 +101,7 @@ const config = {
|
||||
type: "localeDropdown",
|
||||
position: "left",
|
||||
},
|
||||
{ to: "blog", label: "Blog", position: "right" },
|
||||
{
|
||||
href: "https://github.com/run-llama/LlamaIndexTS",
|
||||
label: "GitHub",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "docs",
|
||||
"version": "0.0.5",
|
||||
"version": "0.0.17",
|
||||
"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,83 +0,0 @@
|
||||
import { FunctionTool, OpenAIAgent } from "llamaindex";
|
||||
|
||||
// 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 ==========`);
|
||||
console.log(stepOutput.output.message.content);
|
||||
console.log(`==========================`);
|
||||
|
||||
if (stepOutput.isLast) {
|
||||
console.log(stepOutput.output.message.content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void main().then(() => {
|
||||
console.log("Done");
|
||||
});
|
||||
@@ -66,8 +66,12 @@ async function main() {
|
||||
stream: true,
|
||||
});
|
||||
|
||||
for await (const chunk of stream.response) {
|
||||
process.stdout.write(chunk.response);
|
||||
console.log("Response:");
|
||||
|
||||
for await (const {
|
||||
response: { delta },
|
||||
} of stream) {
|
||||
process.stdout.write(delta);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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"],
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -16,8 +16,10 @@ async function main() {
|
||||
stream: true,
|
||||
});
|
||||
|
||||
for await (const chunk of response.response) {
|
||||
process.stdout.write(chunk.response);
|
||||
for await (const {
|
||||
response: { delta },
|
||||
} of response) {
|
||||
process.stdout.write(delta);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
import { Gemini, GEMINI_MODEL } from "llamaindex";
|
||||
|
||||
(async () => {
|
||||
if (!process.env.GOOGLE_API_KEY) {
|
||||
throw new Error("Please set the GOOGLE_API_KEY environment variable.");
|
||||
}
|
||||
const gemini = new Gemini({
|
||||
model: GEMINI_MODEL.GEMINI_PRO,
|
||||
});
|
||||
const result = await gemini.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);
|
||||
})();
|
||||
@@ -0,0 +1,15 @@
|
||||
import { GEMINI_EMBEDDING_MODEL, GeminiEmbedding } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
if (!process.env.GOOGLE_API_KEY) {
|
||||
throw new Error("Please set the GOOGLE_API_KEY environment variable.");
|
||||
}
|
||||
const embedModel = new GeminiEmbedding({
|
||||
model: GEMINI_EMBEDDING_MODEL.EMBEDDING_001,
|
||||
});
|
||||
const texts = ["hello", "world"];
|
||||
const embeddings = await embedModel.getTextEmbeddingsBatch(texts);
|
||||
console.log(`\nWe have ${embeddings.length} embeddings`);
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -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);
|
||||
})();
|
||||
@@ -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": {
|
||||
|
||||
@@ -10,14 +10,15 @@
|
||||
"start:markdown": "node --import tsx ./src/markdown.ts",
|
||||
"start:pdf": "node --import tsx ./src/pdf.ts",
|
||||
"start:llamaparse": "node --import tsx ./src/llamaparse.ts",
|
||||
"start:notion": "node --import tsx ./src/notion.ts"
|
||||
"start:notion": "node --import tsx ./src/notion.ts",
|
||||
"start:llamaparse2": "node --import tsx ./src/llamaparse_2.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"llamaindex": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.12.7",
|
||||
"tsx": "^4.7.2",
|
||||
"@types/node": "^20.12.11",
|
||||
"tsx": "^4.9.3",
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import fs from "fs/promises";
|
||||
import { LlamaParseReader } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
// Load PDF using LlamaParse. set apiKey here or in environment variable LLAMA_CLOUD_API_KEY
|
||||
const reader = new LlamaParseReader({
|
||||
resultType: "markdown",
|
||||
language: "en",
|
||||
parsingInstruction:
|
||||
"The provided document is a manga comic book. Most pages do NOT have title. It does not contain tables. Try to reconstruct the dialogue happening in a cohesive way. Output any math equation in LATEX markdown (between $$)",
|
||||
});
|
||||
const documents = await reader.loadData("../data/manga.pdf"); // The manga.pdf in the data folder is just a copy of the TOS, due to copyright laws. You have to place your own. I used "The Manga Guide to Calculus" by Hiroyuki Kojima
|
||||
|
||||
// Assuming documents contain an array of pages or sections
|
||||
const parsedManga = documents.map((page) => page.text).join("\n---\n");
|
||||
|
||||
// Output the parsed manga to .md file. Will be placed in ../example/readers/
|
||||
try {
|
||||
await fs.writeFile("./parsedManga.md", parsedManga);
|
||||
console.log("Output successfully written to parsedManga.md");
|
||||
} catch (err) {
|
||||
console.error("Error writing to file:", err);
|
||||
}
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -8,6 +8,7 @@
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"lib": ["ES2022"],
|
||||
"types": ["node"],
|
||||
"outDir": "./lib",
|
||||
"tsBuildInfoFile": "./lib/.tsbuildinfo",
|
||||
"incremental": true,
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
"name": "@llamaindex/monorepo",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "turbo run build",
|
||||
"build:release": "turbo run build lint test --filter=\"!docs\"",
|
||||
"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 .",
|
||||
"format:write": "prettier --ignore-unknown --write .",
|
||||
@@ -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,9 @@
|
||||
# @llamaindex/autotool-01-node-example
|
||||
|
||||
## 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,9 @@
|
||||
# @llamaindex/autotool-02-next-example
|
||||
|
||||
## 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;
|
||||
}
|
||||
|
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.1",
|
||||
"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: {},
|
||||
},
|
||||
};
|
||||
|
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,78 @@
|
||||
{
|
||||
"name": "@llamaindex/autotool",
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"description": "",
|
||||
"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.9",
|
||||
"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,3 +1,4 @@
|
||||
.turbo
|
||||
/README.md
|
||||
LICENSE
|
||||
LICENSE
|
||||
*.tgz
|
||||
@@ -1,5 +1,99 @@
|
||||
# llamaindex
|
||||
|
||||
## 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
|
||||
|
||||
- 46227f2: fix: build error on next.js nodejs runtime
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 5016f21: feat: improve next.js/cloudflare/vite support
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5016f21]
|
||||
- @llamaindex/env@0.1.0
|
||||
|
||||
## 0.2.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 6277105: fix: allow passing empty tools to llms
|
||||
|
||||
## 0.2.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- d8d952d: feat: add gemini llm and embedding
|
||||
|
||||
## 0.2.11
|
||||
|
||||
### 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
|
||||
@@ -0,0 +1,4 @@
|
||||
# Examples
|
||||
|
||||
This directory contains examples of how to use the core package.
|
||||
Each example is not for production use, but rather to show how to use the core package at minimum.
|
||||
@@ -0,0 +1,172 @@
|
||||
# Logs
|
||||
|
||||
logs
|
||||
_.log
|
||||
npm-debug.log_
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
|
||||
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
|
||||
# Runtime data
|
||||
|
||||
pids
|
||||
_.pid
|
||||
_.seed
|
||||
\*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
|
||||
coverage
|
||||
\*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
|
||||
\*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
|
||||
\*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
|
||||
.nuxt
|
||||
dist
|
||||
|
||||
# Gatsby files
|
||||
|
||||
.cache/
|
||||
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
|
||||
.temp
|
||||
.cache
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.\*
|
||||
|
||||
# wrangler project
|
||||
|
||||
.dev.vars
|
||||
.wrangler/
|
||||
@@ -0,0 +1,81 @@
|
||||
# @llamaindex/cloudflare-worker-agent-test
|
||||
|
||||
## 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
|
||||
|
||||
- Updated dependencies [46227f2]
|
||||
- llamaindex@0.3.1
|
||||
|
||||
## 0.0.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5016f21]
|
||||
- llamaindex@0.3.0
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "@llamaindex/cloudflare-worker-agent-test",
|
||||
"version": "0.0.10",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"deploy": "wrangler deploy",
|
||||
"dev": "wrangler dev",
|
||||
"build": "wrangler deploy --dry-run --outdir dist",
|
||||
"start": "wrangler dev",
|
||||
"test": "vitest",
|
||||
"cf-typegen": "wrangler types"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@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.53.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"llamaindex": "workspace:*"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
export default {
|
||||
async fetch(
|
||||
request: Request,
|
||||
env: Env,
|
||||
ctx: ExecutionContext,
|
||||
): Promise<Response> {
|
||||
const { setEnvs } = await import("@llamaindex/env");
|
||||
setEnvs(env);
|
||||
const { OpenAIAgent } = await import("llamaindex");
|
||||
const agent = new OpenAIAgent({
|
||||
tools: [],
|
||||
});
|
||||
const responseStream = await agent.chat({
|
||||
stream: true,
|
||||
message: "Hello? What is the weather today?",
|
||||
});
|
||||
const textEncoder = new TextEncoder();
|
||||
const response = responseStream.pipeThrough<Uint8Array>(
|
||||
// @ts-expect-error: see https://github.com/cloudflare/workerd/issues/2067
|
||||
new TransformStream({
|
||||
transform: (chunk, controller) => {
|
||||
controller.enqueue(textEncoder.encode(chunk.response.delta));
|
||||
},
|
||||
}),
|
||||
);
|
||||
// @ts-expect-error: see https://github.com/cloudflare/workerd/issues/2067
|
||||
return new Response(response);
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
import {
|
||||
createExecutionContext,
|
||||
env,
|
||||
waitOnExecutionContext,
|
||||
} from "cloudflare:test";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import worker from "../src/index";
|
||||
|
||||
const IncomingRequest = Request<unknown, IncomingRequestCfProperties>;
|
||||
|
||||
describe("Hello World worker", () => {
|
||||
// FIXME: https://github.com/cloudflare/workers-sdk/issues/5646
|
||||
it.fails("responds with Hello World! (unit style)", async () => {
|
||||
const request = new IncomingRequest("http://example.com");
|
||||
// Create an empty context to pass to `worker.fetch()`.
|
||||
const ctx = createExecutionContext();
|
||||
const response = await worker.fetch(request, env, ctx);
|
||||
// Wait for all `Promise`s passed to `ctx.waitUntil()` to settle before running test assertions
|
||||
await waitOnExecutionContext(ctx);
|
||||
// fixme: should be not "Hello World!"
|
||||
expect(await response.text()).toMatchInlineSnapshot(`"Hello World!"`);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"types": [
|
||||
"@cloudflare/workers-types/experimental",
|
||||
"@cloudflare/vitest-pool-workers"
|
||||
]
|
||||
},
|
||||
"include": ["./**/*.ts", "../src/env.d.ts"],
|
||||
"exclude": []
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
|
||||
/* Projects */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
|
||||
// "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */
|
||||
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */
|
||||
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
|
||||
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
|
||||
|
||||
/* Language and Environment */
|
||||
"target": "es2021" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||
"lib": [
|
||||
"es2021"
|
||||
] /* Specify a set of bundled library declaration files that describe the target runtime environment. */,
|
||||
"jsx": "react" /* Specify what JSX code is generated. */,
|
||||
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
|
||||
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */
|
||||
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
|
||||
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */
|
||||
// "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */
|
||||
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
|
||||
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
|
||||
|
||||
/* Modules */
|
||||
"module": "es2022" /* Specify what module code is generated. */,
|
||||
// "rootDir": "./", /* Specify the root folder within your source files. */
|
||||
"moduleResolution": "Bundler" /* Specify how TypeScript looks up a file from a given module specifier. */,
|
||||
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
|
||||
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
|
||||
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
|
||||
// "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */
|
||||
"types": [
|
||||
"@cloudflare/workers-types/2023-07-01"
|
||||
] /* Specify type package names to be included without being referenced in a source file. */,
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
"resolveJsonModule": true /* Enable importing .json files */,
|
||||
// "noResolve": true, /* Disallow `import`s, `require`s or `<reference>`s from expanding the number of files TypeScript should add to a project. */
|
||||
|
||||
/* JavaScript Support */
|
||||
"allowJs": true /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */,
|
||||
"checkJs": false /* Enable error reporting in type-checked JavaScript files. */,
|
||||
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */
|
||||
|
||||
/* Emit */
|
||||
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
|
||||
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
|
||||
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
|
||||
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
|
||||
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */
|
||||
// "outDir": "./", /* Specify an output folder for all emitted files. */
|
||||
// "removeComments": true, /* Disable emitting comments. */
|
||||
"noEmit": true /* Disable emitting files from a compilation. */,
|
||||
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
|
||||
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */
|
||||
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
|
||||
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
|
||||
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
|
||||
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
|
||||
// "newLine": "crlf", /* Set the newline character for emitting files. */
|
||||
// "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */
|
||||
// "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */
|
||||
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
|
||||
// "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */
|
||||
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
|
||||
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
|
||||
|
||||
/* Interop Constraints */
|
||||
"isolatedModules": true /* Ensure that each file can be safely transpiled without relying on other imports. */,
|
||||
"allowSyntheticDefaultImports": true /* Allow 'import x from y' when a module doesn't have a default export. */,
|
||||
// "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */,
|
||||
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
|
||||
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true /* Enable all strict type-checking options. */,
|
||||
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */
|
||||
// "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */
|
||||
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
|
||||
// "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */
|
||||
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
|
||||
// "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */
|
||||
// "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */
|
||||
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
|
||||
// "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */
|
||||
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */
|
||||
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
|
||||
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
|
||||
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */
|
||||
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
|
||||
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
},
|
||||
"exclude": ["test"]
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { defineWorkersConfig } from "@cloudflare/vitest-pool-workers/config";
|
||||
|
||||
export default defineWorkersConfig({
|
||||
test: {
|
||||
poolOptions: {
|
||||
workers: {
|
||||
wrangler: { configPath: "./wrangler.toml" },
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
// Generated by Wrangler
|
||||
// After adding bindings to `wrangler.toml`, regenerate this interface via `npm run cf-typegen`
|
||||
interface Env {}
|
||||
@@ -0,0 +1,108 @@
|
||||
#:schema node_modules/wrangler/config-schema.json
|
||||
name = "agent"
|
||||
main = "src/index.ts"
|
||||
compatibility_date = "2024-04-23"
|
||||
compatibility_flags = ["nodejs_compat"]
|
||||
|
||||
# Automatically place your workloads in an optimal location to minimize latency.
|
||||
# If you are running back-end logic in a Worker, running it closer to your back-end infrastructure
|
||||
# rather than the end user may result in better performance.
|
||||
# Docs: https://developers.cloudflare.com/workers/configuration/smart-placement/#smart-placement
|
||||
# [placement]
|
||||
# mode = "smart"
|
||||
|
||||
# Variable bindings. These are arbitrary, plaintext strings (similar to environment variables)
|
||||
# Docs:
|
||||
# - https://developers.cloudflare.com/workers/wrangler/configuration/#environment-variables
|
||||
# Note: Use secrets to store sensitive data.
|
||||
# - https://developers.cloudflare.com/workers/configuration/secrets/
|
||||
# [vars]
|
||||
# MY_VARIABLE = "production_value"
|
||||
|
||||
# Bind the Workers AI model catalog. Run machine learning models, powered by serverless GPUs, on Cloudflare’s global network
|
||||
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#workers-ai
|
||||
# [ai]
|
||||
# binding = "AI"
|
||||
|
||||
# Bind an Analytics Engine dataset. Use Analytics Engine to write analytics within your Pages Function.
|
||||
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#analytics-engine-datasets
|
||||
# [[analytics_engine_datasets]]
|
||||
# binding = "MY_DATASET"
|
||||
|
||||
# Bind a headless browser instance running on Cloudflare's global network.
|
||||
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#browser-rendering
|
||||
# [browser]
|
||||
# binding = "MY_BROWSER"
|
||||
|
||||
# Bind a D1 database. D1 is Cloudflare’s native serverless SQL database.
|
||||
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#d1-databases
|
||||
# [[d1_databases]]
|
||||
# binding = "MY_DB"
|
||||
# database_name = "my-database"
|
||||
# database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
|
||||
# Bind a dispatch namespace. Use Workers for Platforms to deploy serverless functions programmatically on behalf of your customers.
|
||||
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#dispatch-namespace-bindings-workers-for-platforms
|
||||
# [[dispatch_namespaces]]
|
||||
# binding = "MY_DISPATCHER"
|
||||
# namespace = "my-namespace"
|
||||
|
||||
# Bind a Durable Object. Durable objects are a scale-to-zero compute primitive based on the actor model.
|
||||
# Durable Objects can live for as long as needed. Use these when you need a long-running "server", such as in realtime apps.
|
||||
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#durable-objects
|
||||
# [[durable_objects.bindings]]
|
||||
# name = "MY_DURABLE_OBJECT"
|
||||
# class_name = "MyDurableObject"
|
||||
|
||||
# Durable Object migrations.
|
||||
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#migrations
|
||||
# [[migrations]]
|
||||
# tag = "v1"
|
||||
# new_classes = ["MyDurableObject"]
|
||||
|
||||
# Bind a Hyperdrive configuration. Use to accelerate access to your existing databases from Cloudflare Workers.
|
||||
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#hyperdrive
|
||||
# [[hyperdrive]]
|
||||
# binding = "MY_HYPERDRIVE"
|
||||
# id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
|
||||
# Bind a KV Namespace. Use KV as persistent storage for small key-value pairs.
|
||||
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#kv-namespaces
|
||||
# [[kv_namespaces]]
|
||||
# binding = "MY_KV_NAMESPACE"
|
||||
# id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
||||
|
||||
# Bind an mTLS certificate. Use to present a client certificate when communicating with another service.
|
||||
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#mtls-certificates
|
||||
# [[mtls_certificates]]
|
||||
# binding = "MY_CERTIFICATE"
|
||||
# certificate_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
|
||||
|
||||
# Bind a Queue producer. Use this binding to schedule an arbitrary task that may be processed later by a Queue consumer.
|
||||
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#queues
|
||||
# [[queues.producers]]
|
||||
# binding = "MY_QUEUE"
|
||||
# queue = "my-queue"
|
||||
|
||||
# Bind a Queue consumer. Queue Consumers can retrieve tasks scheduled by Producers to act on them.
|
||||
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#queues
|
||||
# [[queues.consumers]]
|
||||
# queue = "my-queue"
|
||||
|
||||
# Bind an R2 Bucket. Use R2 to store arbitrarily large blobs of data, such as files.
|
||||
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#r2-buckets
|
||||
# [[r2_buckets]]
|
||||
# binding = "MY_BUCKET"
|
||||
# bucket_name = "my-bucket"
|
||||
|
||||
# Bind another Worker service. Use this binding to call another Worker without network overhead.
|
||||
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#service-bindings
|
||||
# [[services]]
|
||||
# binding = "MY_SERVICE"
|
||||
# service = "my-service"
|
||||
|
||||
# Bind a Vectorize index. Use to store and query vector embeddings for semantic search, classification and other vector search use-cases.
|
||||
# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#vectorize-indexes
|
||||
# [[vectorize]]
|
||||
# binding = "MY_INDEX"
|
||||
# index_name = "my-index"
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"root": false,
|
||||
"extends": "next/core-web-vitals"
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
# @llamaindex/next-agent-test
|
||||
|
||||
## 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
|
||||
|
||||
- Updated dependencies [46227f2]
|
||||
- llamaindex@0.3.1
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [5016f21]
|
||||
- llamaindex@0.3.0
|
||||
@@ -0,0 +1,36 @@
|
||||
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
# or
|
||||
pnpm dev
|
||||
# or
|
||||
bun 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 Next.js, take a look at the following resources:
|
||||
|
||||
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
|
||||
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
|
||||
|
||||
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
|
||||
|
||||
## Deploy on Vercel
|
||||
|
||||
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
|
||||
|
||||
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
|
||||
@@ -0,0 +1,6 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {};
|
||||
|
||||
import withLlamaIndex from "llamaindex/next";
|
||||
|
||||
export default withLlamaIndex(nextConfig);
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "@llamaindex/next-agent-test",
|
||||
"version": "0.1.10",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"ai": "^3.1.3",
|
||||
"llamaindex": "workspace:*",
|
||||
"next": "14.2.3",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@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.4.5"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/** @type {import('postcss-load-config').Config} */
|
||||
const config = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 629 B After Width: | Height: | Size: 629 B |
@@ -0,0 +1,32 @@
|
||||
"use server";
|
||||
import { createStreamableUI } from "ai/rsc";
|
||||
import { OpenAIAgent } from "llamaindex";
|
||||
import type { ChatMessage } from "llamaindex/llm/types";
|
||||
|
||||
export async function chatWithAgent(
|
||||
question: string,
|
||||
prevMessages: ChatMessage[] = [],
|
||||
) {
|
||||
const agent = new OpenAIAgent({
|
||||
tools: [],
|
||||
});
|
||||
const responseStream = await agent.chat({
|
||||
stream: true,
|
||||
message: question,
|
||||
chatHistory: prevMessages,
|
||||
});
|
||||
const uiStream = createStreamableUI(<div>loading...</div>);
|
||||
responseStream
|
||||
.pipeTo(
|
||||
new WritableStream({
|
||||
start: () => {
|
||||
uiStream.update("response:");
|
||||
},
|
||||
write: async (message) => {
|
||||
uiStream.append(message.response.delta);
|
||||
},
|
||||
}),
|
||||
)
|
||||
.catch(uiStream.error);
|
||||
return uiStream.value;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@@ -0,0 +1,22 @@
|
||||
import type { Metadata } from "next";
|
||||
import { Inter } from "next/font/google";
|
||||
import "./globals.css";
|
||||
|
||||
const inter = Inter({ subsets: ["latin"] });
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={inter.className}>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
"use client";
|
||||
import { chatWithAgent } from "@/actions";
|
||||
import type { JSX } from "react";
|
||||
import { useFormState } from "react-dom";
|
||||
|
||||
export const runtime = "edge";
|
||||
|
||||
export default function Home() {
|
||||
const [state, action] = useFormState<JSX.Element | null>(async () => {
|
||||
return chatWithAgent("hello!", []);
|
||||
}, null);
|
||||
return (
|
||||
<main>
|
||||
{state}
|
||||
<form action={action}>
|
||||
<button>Chat</button>
|
||||
</form>
|
||||
</main>
|
||||
);
|
||||
}
|
||||