mirror of
https://github.com/run-llama/LlamaIndexTS.git
synced 2026-07-03 19:19:08 -04:00
Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f63b702bec | |||
| ccde88fe0b | |||
| b0cd5301bb | |||
| 3e66ddc10d | |||
| c719b968f3 | |||
| c73c659c6d | |||
| 361a685012 | |||
| 680b529e94 | |||
| 389acbd307 | |||
| 2e181be160 | |||
| 7a7ca604c5 | |||
| c2fd4f9fc1 | |||
| 40f5f410c0 | |||
| d671ed6d25 | |||
| 76c9a80057 | |||
| 46a416517c | |||
| 168d11fe51 | |||
| 3dfa5eb9ff | |||
| 9b20859dc5 | |||
| 93691793c5 | |||
| 3b231cf11c | |||
| 7073fca171 | |||
| 9145577bf5 | |||
| 4a18a2eb3d | |||
| 206b491724 | |||
| 9b2e25a184 | |||
| b29521bf6c | |||
| 73e25787e7 | |||
| 3ce80540fe | |||
| dbc1ee3089 | |||
| 3b45191228 | |||
| aaf2f8b2db | |||
| 6ddf1c1b1f | |||
| a8717d5ece | |||
| 7e8e4549f2 | |||
| cc3fe92a22 | |||
| 63ab0dba4e | |||
| 2225ffd1d4 | |||
| bc5334249b | |||
| 41953a3ef9 | |||
| fa66c9ca8e | |||
| 3ee8c83200 | |||
| e919bab568 | |||
| d28b6b7c4f | |||
| 1c7a262ff7 | |||
| 5a1838cc91 | |||
| b9805f4899 | |||
| 109ec63779 | |||
| 82d4b46fe4 | |||
| f8c2d0b8ad | |||
| 6d7bc4ccbb | |||
| 294f502441 | |||
| 056594452c | |||
| 1e59695cef | |||
| f463efd8a5 | |||
| cf95af40d9 | |||
| ddc910dc73 | |||
| f12af27760 | |||
| ffdbc8f5e8 | |||
| ea8817f7e4 | |||
| 359698d04b | |||
| b49fb24948 | |||
| 78841495aa | |||
| c81dd21472 | |||
| 52868ea0f9 | |||
| e0a730e44e | |||
| eda486bb52 | |||
| 10d9c708db | |||
| 556027705e | |||
| 588cd0f0b9 | |||
| 7ca9ddff86 | |||
| 3310eaae29 | |||
| 96dac4ddfd | |||
| f9ee683593 |
@@ -1,5 +0,0 @@
|
||||
---
|
||||
"@llamaindex/openai": patch
|
||||
---
|
||||
|
||||
Update o4-mini to accept reasoning parameters and exclude temperature
|
||||
@@ -8,6 +8,11 @@ on:
|
||||
branches:
|
||||
- main
|
||||
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
||||
TURBO_REMOTE_ONLY: true
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
name: Publish Preview
|
||||
on: [pull_request]
|
||||
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
||||
TURBO_REMOTE_ONLY: true
|
||||
|
||||
jobs:
|
||||
pre_release:
|
||||
name: Pre Release
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [18.x, 20.x, 22.x, 23.x]
|
||||
node-version: [20.x, 22.x, 23.x]
|
||||
name: E2E on Node.js ${{ matrix.node-version }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version: [18.x, 20.x, 22.x, 23.x]
|
||||
node-version: [20.x, 22.x, 23.x]
|
||||
name: Test on Node.js ${{ matrix.node-version }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
@@ -87,6 +87,30 @@ jobs:
|
||||
run: pnpm run type-check
|
||||
- name: Run Circular Dependency Check
|
||||
run: pnpm run circular-check
|
||||
e2e-npm:
|
||||
runs-on: ubuntu-latest
|
||||
name: Test using packages with npm
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version-file: ".nvmrc"
|
||||
- name: Install dependencies
|
||||
run: pnpm install
|
||||
- name: Build packages
|
||||
run: pnpm run build
|
||||
- name: Pack packages
|
||||
run: |
|
||||
pnpm pack --pack-destination ${{ runner.temp }} -C packages/llamaindex
|
||||
pnpm pack --pack-destination ${{ runner.temp }} -C packages/workflow
|
||||
- name: Install packed packages
|
||||
run: npm add ${{ runner.temp }}/*.tgz
|
||||
working-directory: e2e/npm
|
||||
- name: Run tests
|
||||
run: npm test
|
||||
working-directory: e2e/npm
|
||||
e2e-llamaindex-examples:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
@@ -7,3 +7,4 @@ dist/
|
||||
.source/
|
||||
# prttier doesn't support mdx3 we are using
|
||||
*.mdx
|
||||
packages/server/server/
|
||||
@@ -7,9 +7,10 @@
|
||||
</h3>
|
||||
|
||||
[](https://www.npmjs.com/package/llamaindex)
|
||||
[](https://www.npmjs.com/package/llamaindex)
|
||||
[](https://github.com/run-llama/LlamaIndexTS/blob/main/LICENSE)
|
||||
[](https://www.npmjs.com/package/llamaindex)
|
||||
[](https://discord.com/invite/eN6D2HQ4aX)
|
||||
[](https://x.com/llama_index)
|
||||
|
||||
Use your own data with large language models (LLMs, OpenAI ChatGPT and others) in JS runtime environments with TypeScript support.
|
||||
|
||||
@@ -63,7 +64,7 @@ yarn add llamaindex
|
||||
|
||||
### Setup in Node.js, Deno, Bun, TypeScript...?
|
||||
|
||||
See our official document: <https://ts.llamaindex.ai/docs/llamaindex/getting_started/>
|
||||
See our official document: https://ts.llamaindex.ai/docs/llamaindex/getting_started
|
||||
|
||||
### Adding provider packages
|
||||
|
||||
@@ -83,19 +84,7 @@ Check out our NextJS playground at https://llama-playground.vercel.app/. The sou
|
||||
|
||||
## Core concepts for getting started:
|
||||
|
||||
- [Document](/packages/llamaindex/src/Node.ts): A document represents a text file, PDF file or other contiguous piece of data.
|
||||
|
||||
- [Node](/packages/llamaindex/src/Node.ts): The basic data building block. Most commonly, these are parts of the document split into manageable pieces that are small enough to be fed into an embedding model and LLM.
|
||||
|
||||
- [Embedding](/packages/llamaindex/src/embeddings/OpenAIEmbedding.ts): Embeddings are sets of floating point numbers which represent the data in a Node. By comparing the similarity of embeddings, we can derive an understanding of the similarity of two pieces of data. One use case is to compare the embedding of a question with the embeddings of our Nodes to see which Nodes may contain the data needed to answer that question. Because the default service context is OpenAI, the default embedding is `OpenAIEmbedding`. If using different models, say through Ollama, use this [Embedding](/packages/llamaindex/src/embeddings/OllamaEmbedding.ts) (see all [here](/packages/llamaindex/src/embeddings)).
|
||||
|
||||
- [Indices](/packages/llamaindex/src/indices/): Indices store the Nodes and the embeddings of those nodes. QueryEngines retrieve Nodes from these Indices using embedding similarity.
|
||||
|
||||
- [QueryEngine](/packages/llamaindex/src/engines/query/RetrieverQueryEngine.ts): Query engines are what generate the query you put in and give you back the result. Query engines generally combine a pre-built prompt with selected Nodes from your Index to give the LLM the context it needs to answer your query. To build a query engine from your Index (recommended), use the [`asQueryEngine`](/packages/llamaindex/src/indices/BaseIndex.ts) method on your Index. See all query engines [here](/packages/llamaindex/src/engines/query).
|
||||
|
||||
- [ChatEngine](/packages/llamaindex/src/engines/chat/SimpleChatEngine.ts): A ChatEngine helps you build a chatbot that will interact with your Indices. See all chat engines [here](/packages/llamaindex/src/engines/chat).
|
||||
|
||||
- [SimplePrompt](/packages/llamaindex/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.
|
||||
See our documentation: https://ts.llamaindex.ai/docs/llamaindex/getting_started/concepts
|
||||
|
||||
## Contributing:
|
||||
|
||||
|
||||
@@ -1,5 +1,92 @@
|
||||
# @llamaindex/doc
|
||||
|
||||
## 0.2.19
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [680b529]
|
||||
- Updated dependencies [b0cd530]
|
||||
- Updated dependencies [361a685]
|
||||
- Updated dependencies [3e66ddc]
|
||||
- @llamaindex/workflow@1.1.3
|
||||
- @llamaindex/core@0.6.6
|
||||
- llamaindex@0.11.0
|
||||
- @llamaindex/openai@0.4.0
|
||||
- @llamaindex/cloud@4.0.8
|
||||
- @llamaindex/node-parser@2.0.6
|
||||
- @llamaindex/readers@3.1.4
|
||||
|
||||
## 0.2.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- d671ed6: Add functionality for search params when querying Qdrant vector store.
|
||||
- Updated dependencies [76c9a80]
|
||||
- Updated dependencies [168d11f]
|
||||
- Updated dependencies [d671ed6]
|
||||
- Updated dependencies [40f5f41]
|
||||
- @llamaindex/openai@0.3.7
|
||||
- @llamaindex/workflow@1.1.2
|
||||
- @llamaindex/core@0.6.5
|
||||
- @llamaindex/cloud@4.0.7
|
||||
- llamaindex@0.10.6
|
||||
- @llamaindex/node-parser@2.0.5
|
||||
- @llamaindex/readers@3.1.3
|
||||
|
||||
## 0.2.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [9b2e25a]
|
||||
- @llamaindex/openai@0.3.6
|
||||
- @llamaindex/core@0.6.4
|
||||
- llamaindex@0.10.5
|
||||
- @llamaindex/cloud@4.0.6
|
||||
- @llamaindex/node-parser@2.0.4
|
||||
- @llamaindex/readers@3.1.2
|
||||
- @llamaindex/workflow@1.1.1
|
||||
|
||||
## 0.2.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [7e8e454]
|
||||
- Updated dependencies [2225ffd]
|
||||
- Updated dependencies [6ddf1c1]
|
||||
- Updated dependencies [bc53342]
|
||||
- Updated dependencies [41953a3]
|
||||
- @llamaindex/workflow@1.1.0
|
||||
- @llamaindex/cloud@4.0.5
|
||||
- llamaindex@0.10.4
|
||||
|
||||
## 0.2.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3ee8c83]
|
||||
- @llamaindex/core@0.6.3
|
||||
- llamaindex@0.10.3
|
||||
- @llamaindex/openai@0.3.5
|
||||
- @llamaindex/cloud@4.0.4
|
||||
- @llamaindex/node-parser@2.0.3
|
||||
- @llamaindex/readers@3.1.1
|
||||
- @llamaindex/workflow@1.0.4
|
||||
|
||||
## 0.2.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1e59695]
|
||||
- @llamaindex/readers@3.1.0
|
||||
|
||||
## 0.2.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [e5c3f95]
|
||||
- @llamaindex/openai@0.3.4
|
||||
- llamaindex@0.10.2
|
||||
|
||||
## 0.2.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@llamaindex/doc",
|
||||
"version": "0.2.12",
|
||||
"version": "0.2.19",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"postinstall": "fumadocs-mdx",
|
||||
@@ -15,7 +15,7 @@
|
||||
"dependencies": {
|
||||
"@huggingface/transformers": "^3.5.0",
|
||||
"@icons-pack/react-simple-icons": "^10.1.0",
|
||||
"@llama-flow/docs": "0.0.3",
|
||||
"@llama-flow/docs": "0.0.8",
|
||||
"@llamaindex/chat-ui": "0.2.0",
|
||||
"@llamaindex/cloud": "workspace:*",
|
||||
"@llamaindex/core": "workspace:*",
|
||||
@@ -90,9 +90,9 @@
|
||||
"remark-stringify": "^11.0.0",
|
||||
"tailwindcss": "^4.0.9",
|
||||
"tsx": "^4.19.3",
|
||||
"typedoc": "0.28.2",
|
||||
"typedoc": "0.28.3",
|
||||
"typedoc-plugin-markdown": "^4.6.2",
|
||||
"typedoc-plugin-merge-modules": "^7.0.0",
|
||||
"typedoc-plugin-merge-modules": " ^7.0.0",
|
||||
"typescript": "^5.7.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { generateFiles as openapiGenerateFiles } from "fumadocs-openapi";
|
||||
import {
|
||||
createGenerator,
|
||||
generateFiles as typescriptGenerateFiles,
|
||||
@@ -14,18 +13,12 @@ const apiRefOut = "./src/content/docs/api";
|
||||
// clean generated files
|
||||
rimrafSync(out, {
|
||||
filter(v) {
|
||||
return !v.endsWith("index.mdx") && !v.endsWith("meta.json");
|
||||
return !v.endsWith("index.md") && !v.endsWith("meta.json");
|
||||
},
|
||||
});
|
||||
|
||||
void openapiGenerateFiles({
|
||||
input: ["../../packages/cloud/openapi.json"],
|
||||
output: "./src/content/docs/cloud/api",
|
||||
groupBy: "tag",
|
||||
});
|
||||
|
||||
void typescriptGenerateFiles(generator, {
|
||||
input: ["./src/content/docs/api/**/*.mdx"],
|
||||
input: ["./src/content/docs/api/**/*.md"],
|
||||
output: (file) => path.resolve(path.dirname(file), path.basename(file)),
|
||||
transformOutput,
|
||||
});
|
||||
@@ -34,19 +27,22 @@ function transformOutput(filePath: string, content: string) {
|
||||
const fileName = path.basename(filePath);
|
||||
let title = fileName.split(".")[0];
|
||||
if (title === "index") title = "LlamaIndex API Reference";
|
||||
return `---\ntitle: ${title}\n---\n\n${transformAbsoluteUrl(content, filePath)}`;
|
||||
return `---\ntitle: ${title}\n---\n\n${transformAbsoluteUrl(
|
||||
content.replace(/(?<!\\)\{([^}]+)(?<!\\)}/g, "\\{$1\\}"),
|
||||
filePath,
|
||||
)}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the content by converting relative MDX links to absolute docs API links
|
||||
* Example: [text](../type-aliases/TaskHandler.mdx) -> [text](/docs/api/type-aliases/TaskHandler)
|
||||
* [text](BaseChatEngine.mdx) -> [text](/docs/api/classes/BaseChatEngine)
|
||||
* [text](BaseVectorStore.mdx#constructors) -> [text](/docs/api/classes/BaseVectorStore#constructors)
|
||||
* [text](TaskStep.mdx) -> [text](/docs/api/type-aliases/TaskStep)
|
||||
* Transforms the content by converting relative MD links to absolute docs API links
|
||||
* Example: [text](../type-aliases/TaskHandler.md) -> [text](/docs/api/type-aliases/TaskHandler)
|
||||
* [text](BaseChatEngine.md) -> [text](/docs/api/classes/BaseChatEngine)
|
||||
* [text](BaseVectorStore.md#constructors) -> [text](/docs/api/classes/BaseVectorStore#constructors)
|
||||
* [text](TaskStep.md) -> [text](/docs/api/type-aliases/TaskStep)
|
||||
*/
|
||||
function transformAbsoluteUrl(content: string, filePath: string) {
|
||||
const group = path.dirname(filePath).split(path.sep).pop();
|
||||
return content.replace(/\]\(([^)]+)\.mdx([^)]*)\)/g, (_, slug, anchor) => {
|
||||
return content.replace(/\]\(([^)]+)\.md([^)]*)\)/g, (_, slug, anchor) => {
|
||||
const slugParts = slug.split("/");
|
||||
const fileName = slugParts[slugParts.length - 1];
|
||||
const fileGroup = slugParts[slugParts.length - 2] ?? group;
|
||||
|
||||
@@ -4,7 +4,6 @@ import matter from "gray-matter";
|
||||
import path from "path";
|
||||
|
||||
const CONTENT_DIR = path.join(process.cwd(), "src/content/docs");
|
||||
const BUILD_DIR = path.join(process.cwd(), ".next");
|
||||
|
||||
// Regular expression to find internal links
|
||||
// This captures Markdown links [text](/docs/path) and href attributes href="/docs/path"
|
||||
@@ -14,6 +13,8 @@ const INTERNAL_LINK_REGEX = /(?:(?:\]\(|\bhref=["'])\/docs\/([^")]+))/g;
|
||||
// This captures relative links like [text](./path) or 
|
||||
const RELATIVE_LINK_REGEX = /(?:\]\()(?:\s*)(?:\.\.?)\//g;
|
||||
|
||||
const ALLOWED_LINKS = ["/docs/llamaflow"];
|
||||
|
||||
interface LinkValidationResult {
|
||||
file: string;
|
||||
invalidLinks: Array<{ link: string; line: number }>;
|
||||
@@ -28,14 +29,14 @@ interface RelativeLinkResult {
|
||||
* Get all valid documentation routes from the content directory
|
||||
*/
|
||||
async function getValidRoutes(): Promise<Set<string>> {
|
||||
const mdxFiles = await glob("**/*.mdx", { cwd: CONTENT_DIR });
|
||||
const mdxFiles = await glob("**/*.{md,mdx}", { cwd: CONTENT_DIR });
|
||||
|
||||
const routes = new Set<string>();
|
||||
|
||||
// Add each MDX file as a valid route
|
||||
for (const file of mdxFiles) {
|
||||
// Remove .mdx extension and normalize to route format
|
||||
let route = file.replace(/\.mdx$/, "");
|
||||
let route = file.replace(/\.mdx?$/, "");
|
||||
|
||||
// Handle index files
|
||||
if (route.endsWith("/index")) {
|
||||
@@ -124,9 +125,6 @@ function findRelativeLinksInFile(
|
||||
return relativeLinks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate internal links in all MDX files
|
||||
*/
|
||||
/**
|
||||
* Find relative links in all MDX files
|
||||
*/
|
||||
@@ -160,6 +158,11 @@ async function validateLinks(): Promise<LinkValidationResult[]> {
|
||||
const links = extractLinksFromFile(filePath);
|
||||
|
||||
const invalidLinks = links.filter(({ link }) => {
|
||||
// Check if the link is in the allowed list
|
||||
if (ALLOWED_LINKS.includes(`/docs/${link}`)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the link exists in valid routes
|
||||
// First normalize the link (remove any query string or hash)
|
||||
const baseLink = link.split("?")[0].split("#")[0];
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { rehypeCodeDefaultOptions } from "fumadocs-core/mdx-plugins";
|
||||
import {
|
||||
rehypeCodeDefaultOptions,
|
||||
remarkStructure,
|
||||
} from "fumadocs-core/mdx-plugins";
|
||||
import { fileGenerator, remarkDocGen, remarkInstall } from "fumadocs-docgen";
|
||||
import { defineConfig, defineDocs } from "fumadocs-mdx/config";
|
||||
import { transformerTwoslash } from "fumadocs-twoslash";
|
||||
import { createFileSystemTypesCache } from "fumadocs-twoslash/cache-fs";
|
||||
import rehypeKatex from "rehype-katex";
|
||||
import remarkMath from "remark-math";
|
||||
|
||||
@@ -24,11 +26,7 @@ export default defineConfig({
|
||||
},
|
||||
transformers: [
|
||||
...(rehypeCodeDefaultOptions.transformers ?? []),
|
||||
transformerTwoslash({
|
||||
typesCache: createFileSystemTypesCache({
|
||||
dir: ".next/cache/twoslash",
|
||||
}),
|
||||
}),
|
||||
transformerTwoslash(),
|
||||
{
|
||||
name: "transformers:remove-notation-escape",
|
||||
code(hast) {
|
||||
@@ -49,6 +47,7 @@ export default defineConfig({
|
||||
],
|
||||
},
|
||||
remarkPlugins: [
|
||||
remarkStructure,
|
||||
remarkMath,
|
||||
[remarkInstall, { persist: { id: "package-manager" } }],
|
||||
[remarkDocGen, { generators: [fileGenerator()] }],
|
||||
|
||||
@@ -26,7 +26,7 @@ const llm = openai();
|
||||
const response = await llm.chat({
|
||||
messages: [{ content: "Tell me a joke.", role: "user" }],
|
||||
});`,
|
||||
`import { agent } from "llamaindex";
|
||||
`import { agent } from "@llamaindex/workflow";
|
||||
import { openai } from "@llamaindex/openai";
|
||||
|
||||
const analyseAgent = agent({
|
||||
@@ -36,7 +36,7 @@ const analyseAgent = agent({
|
||||
});
|
||||
const response = await analyseAgent.run(\`Analyse the given data:
|
||||
\${data}\`);`,
|
||||
`import { agent, multiAgent } from "llamaindex";
|
||||
`import { agent, multiAgent } from "@llamaindex/workflow";
|
||||
import { openai } from "@llamaindex/openai";
|
||||
|
||||
const analyseAgent = agent({
|
||||
@@ -113,8 +113,9 @@ export default function HomePage() {
|
||||
description="Truly powerful retrieval-augmented generation applications use agentic techniques, and LlamaIndex.TS makes it easy to build them."
|
||||
>
|
||||
<CodeBlock
|
||||
code={`import { agent, SimpleDirectoryReader, VectorStoreIndex } from "llamaindex";
|
||||
code={`import { SimpleDirectoryReader, VectorStoreIndex } from "llamaindex";
|
||||
import { openai } from "@llamaindex/openai";
|
||||
import { agent } from "@llamaindex/workflow";
|
||||
|
||||
// load documents from current directoy into an index
|
||||
const reader = new SimpleDirectoryReader();
|
||||
|
||||
@@ -4,7 +4,7 @@ import { createFromSource } from "fumadocs-core/search/server";
|
||||
|
||||
// TODO: migrate to another search service, I don't think Vercel can handle that many of documents.
|
||||
export const { GET } = createFromSource(source, (page) => ({
|
||||
id: page.url,
|
||||
id: page.file.path,
|
||||
title: page.data.title,
|
||||
description: page.data.description,
|
||||
url: page.url,
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import { baseOptions } from "@/app/layout.config";
|
||||
import { AITrigger } from "@/components/ai-chat";
|
||||
import { buttonVariants } from "@/components/ui/button";
|
||||
import { source } from "@/lib/source";
|
||||
import { cn } from "@/lib/utils";
|
||||
import "fumadocs-twoslash/twoslash.css";
|
||||
import { DocsLayout } from "fumadocs-ui/layouts/docs";
|
||||
import { MessageCircle } from "lucide-react";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
export default function Layout({ children }: { children: ReactNode }) {
|
||||
@@ -13,23 +9,9 @@ export default function Layout({ children }: { children: ReactNode }) {
|
||||
<DocsLayout
|
||||
tree={source.pageTree}
|
||||
{...baseOptions}
|
||||
links={[]}
|
||||
nav={{
|
||||
...baseOptions.nav,
|
||||
children: (
|
||||
<AITrigger
|
||||
className={cn(
|
||||
buttonVariants({
|
||||
variant: "secondary",
|
||||
size: "xs",
|
||||
className:
|
||||
"text-fd-muted-foreground ms-2 gap-1.5 rounded-full px-2 md:flex-1",
|
||||
}),
|
||||
)}
|
||||
>
|
||||
<MessageCircle className="size-3" />
|
||||
Ask LlamaCloud
|
||||
</AITrigger>
|
||||
),
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -27,9 +27,19 @@ export const baseOptions: BaseLayoutProps = {
|
||||
githubUrl: "https://github.com/run-llama/LlamaIndexTS",
|
||||
links: [
|
||||
{
|
||||
text: "Docs",
|
||||
text: "TypeScript",
|
||||
url: DOCUMENT_URL,
|
||||
active: "nested-url",
|
||||
},
|
||||
{
|
||||
text: "Python",
|
||||
url: "https://docs.llamaindex.ai",
|
||||
active: "url",
|
||||
},
|
||||
{
|
||||
text: "LlamaCloud",
|
||||
url: "https://docs.cloud.llamaindex.ai/",
|
||||
active: "url",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
@@ -13,11 +13,7 @@ import remarkStringify from "remark-stringify";
|
||||
export const revalidate = false;
|
||||
|
||||
export async function GET() {
|
||||
const files = await fg([
|
||||
"./src/content/docs/**/*.mdx",
|
||||
// remove generated openapi files
|
||||
"!./src/content/docs/cloud/api/**/*",
|
||||
]);
|
||||
const files = await fg(["./src/content/docs/**/*.mdx"]);
|
||||
|
||||
const scan = files.map(async (file) => {
|
||||
const fileContent = await fs.readFile(file);
|
||||
|
||||
@@ -11,8 +11,3 @@ export const CodeNodeParserDemo = dynamic(() =>
|
||||
(mod) => mod.CodeNodeParserDemo,
|
||||
),
|
||||
);
|
||||
export const WorkflowStreamingDemo = dynamic(() =>
|
||||
import("@/components/demo/workflow-streaming-ui").then(
|
||||
(mod) => mod.WorkflowStreamingDemo,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
"use client";
|
||||
import FlowInput from "@/components/flow-input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
StartEvent,
|
||||
StopEvent,
|
||||
Workflow,
|
||||
WorkflowEvent,
|
||||
} from "@llamaindex/workflow";
|
||||
import { ReactNode, startTransition, useState } from "react";
|
||||
import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
|
||||
|
||||
class ComputeEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
class ComputeResultEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
type ContextData = {
|
||||
sum: number;
|
||||
};
|
||||
|
||||
const workflow = new Workflow<ContextData, number, number>();
|
||||
|
||||
const max = 1000;
|
||||
const min = 100;
|
||||
|
||||
workflow.addStep(
|
||||
{
|
||||
inputs: [StartEvent<number>],
|
||||
outputs: [StopEvent<number>],
|
||||
},
|
||||
async (context, event) => {
|
||||
const total = event.data;
|
||||
for (let i = 0; i < total; i++) {
|
||||
context.sendEvent(new ComputeEvent(i));
|
||||
}
|
||||
console.log("waiting");
|
||||
const computeResults = await Promise.all(
|
||||
Array.from({ length: total }).map(() =>
|
||||
context.requireEvent(ComputeResultEvent),
|
||||
),
|
||||
);
|
||||
context.data.sum = computeResults.reduce(
|
||||
(acc, result) => acc + result.data,
|
||||
0,
|
||||
);
|
||||
console.log("stop");
|
||||
return new StopEvent(context.data.sum);
|
||||
},
|
||||
);
|
||||
|
||||
workflow.addStep(
|
||||
{
|
||||
inputs: [ComputeEvent],
|
||||
outputs: [ComputeResultEvent],
|
||||
},
|
||||
async (context, event) => {
|
||||
await new Promise((resolve) =>
|
||||
setTimeout(resolve, Math.floor(Math.random() * (max - min + 1) + min)),
|
||||
);
|
||||
return new ComputeResultEvent(event.data);
|
||||
},
|
||||
);
|
||||
|
||||
function ScrollToBottom() {
|
||||
const { isAtBottom, scrollToBottom } = useStickToBottomContext();
|
||||
|
||||
return (
|
||||
!isAtBottom && (
|
||||
<button
|
||||
className="i-ph-arrow-circle-down-fill absolute bottom-0 left-[50%] translate-x-[-50%] rounded-lg text-4xl"
|
||||
onClick={() => scrollToBottom()}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export function WorkflowStreamingDemo() {
|
||||
const [ui, setUI] = useState<ReactNode[]>([
|
||||
<div key={0} className="bg-gray-100 dark:bg-gray-800">
|
||||
Waiting for workflow to start
|
||||
</div>,
|
||||
]);
|
||||
const [total, setTotal] = useState<number>(10);
|
||||
|
||||
return (
|
||||
<div className="flex w-full flex-col items-start gap-2">
|
||||
<div className="flex flex-row items-center justify-center">
|
||||
<div className="mr-2 text-lg">Compute total</div>{" "}
|
||||
<FlowInput value={total} onChange={(value) => setTotal(value)} />
|
||||
</div>
|
||||
<Button
|
||||
onClick={async () => {
|
||||
startTransition(() => {
|
||||
setUI([]);
|
||||
});
|
||||
const context = workflow.run(total, {
|
||||
sum: 0,
|
||||
});
|
||||
let i = 0;
|
||||
for await (const event of context) {
|
||||
console.log(event);
|
||||
if (event instanceof ComputeEvent) {
|
||||
setUI((ui) => [
|
||||
...ui,
|
||||
<div key={i++} className="bg-yellow-100 dark:bg-yellow-800">
|
||||
Computing task id: {event.data}
|
||||
</div>,
|
||||
]);
|
||||
} else if (event instanceof ComputeResultEvent) {
|
||||
setUI((ui) => [
|
||||
...ui,
|
||||
<div key={i++} className="bg-green-100 dark:bg-green-800">
|
||||
Computed task id: {event.data}
|
||||
</div>,
|
||||
]);
|
||||
} else if (event instanceof StartEvent) {
|
||||
setUI((ui) => [
|
||||
...ui,
|
||||
<div key={i++} className="bg-blue-100 dark:bg-blue-800">
|
||||
Started workflow with total {event.data}
|
||||
</div>,
|
||||
]);
|
||||
} else if (event instanceof StopEvent) {
|
||||
setUI((ui) => [
|
||||
...ui,
|
||||
<div key={i++} className="bg-red-100 dark:bg-red-800">
|
||||
Workflow stopped
|
||||
</div>,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
Start Workflow
|
||||
</Button>
|
||||
<StickToBottom className="flex max-h-96 w-full flex-col gap-2 overflow-y-auto rounded-lg border border-gray-200 p-2">
|
||||
<StickToBottom.Content className="flex flex-col gap-2">
|
||||
{ui}
|
||||
</StickToBottom.Content>
|
||||
<ScrollToBottom />
|
||||
</StickToBottom>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
title: LlamaCloud
|
||||
description: LlamaCloud is a new generation of managed parsing, ingestion, and retrieval services, designed to bring production-grade context-augmentation to your LLM and RAG applications.
|
||||
---
|
||||
|
||||
This is TypeScript binding for LlamaCloud API. It provides a simple way to interact with LlamaCloud API.
|
||||
|
||||
If you are looking for the official documentation, please visit the [Official Document](https://docs.cloud.llamaindex.ai/)
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"title": "LlamaCloud",
|
||||
"description": "The Cloud framework for LLM",
|
||||
"root": true,
|
||||
"pages": ["---Guide---", "index", "..."]
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
title: High-Level Concepts
|
||||
---
|
||||
|
||||
This is a quick guide to the high-level concepts you'll encounter frequently when building LLM applications.
|
||||
|
||||
## Large Language Models (LLMs)
|
||||
|
||||
LLMs are the fundamental innovation that launched LlamaIndex. They are an artificial intelligence (AI) computer system that can understand, generate, and manipulate natural language, including answering questions based on their training data or data provided to them at query time.
|
||||
|
||||
## Agentic Applications
|
||||
|
||||
When an LLM is used within an application, it is often used to make decisions, take actions, and/or interact with the world. This is the core definition of an **agentic application**.
|
||||
|
||||
While the definition of an agentic application is broad, there are several key characteristics that define an agentic application:
|
||||
|
||||
- **LLM Augmentation**: The LLM is augmented with tools (i.e. arbitrary callable functions in code), memory, and/or dynamic prompts.
|
||||
- **Prompt Chaining**: Several LLM calls are used that build on each other, with the output of one LLM call being used as the input to the next.
|
||||
- **Routing**: The LLM is used to route the application to the next appropriate step or state in the application.
|
||||
- **Parallelism**: The application can perform multiple steps or actions in parallel.
|
||||
- **Orchestration**: A hierarchical structure of LLMs is used to orchestrate lower-level actions and LLMs.
|
||||
- **Reflection**: The LLM is used to reflect and validate outputs of previous steps or LLM calls, which can be used to guide the application to the next appropriate step or state.
|
||||
|
||||
In LlamaIndex, you can build agentic applications by using the workflows to orchestrate a sequence of steps and LLMs. You can [learn more about workflows](/docs/llamaindex/tutorials/workflows).
|
||||
|
||||
## Agents
|
||||
|
||||
We define an agent as a specific instance of an "agentic application". An agent is a piece of software that semi-autonomously performs tasks by combining LLMs with other tools and memory, orchestrated in a reasoning loop that decides which tool to use next (if any).
|
||||
|
||||
What this means in practice, is something like:
|
||||
- An agent receives a user message
|
||||
- The agent uses an LLM to determine the next appropriate action to take using the previous chat history, tools, and the latest user message
|
||||
- The agent may invoke one or more tools to assist in the users request
|
||||
- If tools are used, the agent will then interpret the tool outputs and use them to inform the next action
|
||||
- Once the agent stops taking actions, it returns the final output to the user
|
||||
|
||||
You can [learn more about agents](/docs/llamaindex/tutorials/basic_agent).
|
||||
|
||||
## Retrieval Augmented Generation (RAG)
|
||||
|
||||
Retrieval-Augmented Generation (RAG) is a core technique for building data-backed LLM applications with LlamaIndex. It allows LLMs to answer questions about your private data by providing it to the LLM at query time, rather than training the LLM on your data. To avoid sending **all** of your data to the LLM every time, RAG indexes your data and selectively sends only the relevant parts along with your query. You can [learn more about RAG](/docs/llamaindex/tutorials/rag).
|
||||
|
||||
## Use cases
|
||||
|
||||
There are endless use cases for data-backed LLM applications but they can be roughly grouped into four categories:
|
||||
|
||||
[**Agents**](/docs/llamaindex/tutorials/basic_agent):
|
||||
An agent is an automated decision-maker powered by an LLM that interacts with the world via a set of [tools](/docs/llamaindex/modules/agents/tool). Agents can take an arbitrary number of steps to complete a given task, dynamically deciding on the best course of action rather than following pre-determined steps. This gives it additional flexibility to tackle more complex tasks.
|
||||
|
||||
[**Workflows**](/docs/llamaindex/tutorials/workflows):
|
||||
A Workflow in LlamaIndex is a specific event-driven abstraction that allows you to orchestrate a sequence of steps and LLMs calls. Workflows can be used to implement any agentic application, and are a core component of LlamaIndex.
|
||||
|
||||
[**Structured Data Extraction**](/docs/llamaindex/tutorials/structured_data_extraction):
|
||||
Pydantic extractors allow you to specify a precise data structure to extract from your data and use LLMs to fill in the missing pieces in a type-safe way. This is useful for extracting structured data from unstructured sources like PDFs, websites, and more, and is key to automating workflows.
|
||||
|
||||
[**Query Engines**](/docs/llamaindex/modules/rag/query_engines):
|
||||
A query engine is an end-to-end flow that allows you to ask questions over your data. It takes in a natural language query, and returns a response, along with reference context retrieved and passed to the LLM.
|
||||
|
||||
[**Chat Engines**](/docs/llamaindex/modules/rag/chat_engine):
|
||||
A chat engine is an end-to-end flow for having a conversation with your data (multiple back-and-forth instead of a single question-and-answer).
|
||||
@@ -9,10 +9,10 @@ To install llamaindex, run the following command:
|
||||
npm i llamaindex
|
||||
```
|
||||
|
||||
In most cases, you'll also need an LLM package to use LlamaIndex. For example, to use the OpenAI LLM, you would install the following:
|
||||
In most cases, you'll also need an LLM package and the Workflow package to use LlamaIndex. For example, to use the OpenAI LLM with agents, you would install the following:
|
||||
|
||||
```package-install
|
||||
npm i @llamaindex/openai
|
||||
npm i @llamaindex/openai @llamaindex/workflow
|
||||
```
|
||||
|
||||
Go to [LLM APIs](/docs/llamaindex/modules/models/llms) to find out how to use other LLMs.
|
||||
|
||||
@@ -40,19 +40,7 @@ Make sure to set [moduleResolution](https://www.typescriptlang.org/docs/handbook
|
||||
}
|
||||
```
|
||||
|
||||
We recommend using `bundler` or `nodenext`, but due to popularity of `node`, we still added support for it, but with import path limitations.
|
||||
|
||||
So you may encounter type errors when importing sub paths from the `llamaindex` package like:
|
||||
|
||||
```ts
|
||||
import { Settings } from "llamaindex";
|
||||
```
|
||||
|
||||
The simplest way to fix this without changing `moduleResolution` is to import directly from `llamaindex`:
|
||||
|
||||
```ts
|
||||
import { Settings } from "llamaindex";
|
||||
```
|
||||
We recommend using `bundler` or `nodenext`, but due to popularity of `node`, we still added support for it.
|
||||
|
||||
## Enable AsyncIterable for `Web Stream` API
|
||||
|
||||
@@ -68,7 +56,8 @@ Some modules uses `Web Stream` API like `ReadableStream` and `WritableStream`, y
|
||||
```
|
||||
|
||||
```typescript
|
||||
import { agent, tool } from 'llamaindex'
|
||||
import { tool } from 'llamaindex'
|
||||
import { agent } from "@llamaindex/workflow";
|
||||
import { openai } from "@llamaindex/openai";
|
||||
|
||||
Settings.llm = openai({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"title": "Getting Started",
|
||||
"pages": ["installation", "create_llama", "examples"]
|
||||
"pages": ["concepts", "installation", "create_llama", "examples"]
|
||||
}
|
||||
|
||||
@@ -12,7 +12,8 @@ Agent Workflows are a powerful system that enables you to create and orchestrate
|
||||
The simplest use case is creating a single agent with specific tools. Here's an example of creating an assistant that tells jokes:
|
||||
|
||||
```typescript
|
||||
import { agent, tool } from "llamaindex";
|
||||
import { tool } from "llamaindex";
|
||||
import { agent } from "@llamaindex/workflow";
|
||||
import { openai } from "@llamaindex/openai";
|
||||
|
||||
// Define a joke-telling tool
|
||||
@@ -40,17 +41,17 @@ console.log(result); // Baby Llama is called cria
|
||||
Agent Workflows provide a unified interface for event streaming, making it easy to track and respond to different events during execution:
|
||||
|
||||
```typescript
|
||||
import { AgentToolCall, AgentStream } from "llamaindex";
|
||||
import { agentToolCallEvent, agentStreamEvent } from "@llamaindex/workflow";
|
||||
|
||||
// Get the workflow execution context
|
||||
const context = workflow.run("Tell me something funny");
|
||||
const events = workflow.runStream("Tell me something funny");
|
||||
|
||||
// Stream and handle events
|
||||
for await (const event of context) {
|
||||
if (event instanceof AgentToolCall) {
|
||||
for await (const event of events) {
|
||||
if (agentToolCallEvent.include(event)) {
|
||||
console.log(`Tool being called: ${event.data.toolName}`);
|
||||
}
|
||||
if (event instanceof AgentStream) {
|
||||
if (agentStreamEvent.include(event)) {
|
||||
process.stdout.write(event.data.delta);
|
||||
}
|
||||
}
|
||||
@@ -68,7 +69,8 @@ An Agent Workflow can orchestrate multiple agents, enabling complex interactions
|
||||
Here's an example of a multi-agent system that combines joke-telling and weather information:
|
||||
|
||||
```typescript
|
||||
import { multiAgent, agent, tool } from "llamaindex";
|
||||
import { tool } from "llamaindex";
|
||||
import { multiAgent, agent } from "@llamaindex/workflow";
|
||||
import { openai } from "@llamaindex/openai";
|
||||
import { z } from "zod";
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@ The `parameters` field in the tool configuration is defined using `zod`, a TypeS
|
||||
|
||||
Example:
|
||||
```ts
|
||||
import { agent, tool } from "llamaindex";
|
||||
import { tool } from "llamaindex";
|
||||
import { agent } from "@llamaindex/workflow";
|
||||
import { z } from "zod";
|
||||
|
||||
// first arg is LLM input, second is bound arg
|
||||
@@ -46,7 +47,7 @@ In this example, `z.object` is used to define a schema for the `parameters` wher
|
||||
You can import built-in tools from the `@llamaindex/tools` package.
|
||||
|
||||
```ts
|
||||
import { agent } from "llamaindex";
|
||||
import { agent } from "@llamaindex/workflow";
|
||||
import { wiki } from "@llamaindex/tools";
|
||||
|
||||
const researchAgent = agent({
|
||||
@@ -57,6 +58,41 @@ const researchAgent = agent({
|
||||
});
|
||||
```
|
||||
|
||||
## MCP tools
|
||||
|
||||
If you have a MCP server running, you can fetch tools from the server and use them in your agents.
|
||||
|
||||
```ts
|
||||
// 1. Import MCP tools adapter
|
||||
import { mcp } from "@llamaindex/tools";
|
||||
import { agent } from "@llamaindex/workflow";
|
||||
|
||||
// 2. Initialize a MCP client
|
||||
// by npx
|
||||
const server = mcp({
|
||||
command: "npx",
|
||||
args: ["-y", "@modelcontextprotocol/server-filesystem", "."],
|
||||
verbose: true,
|
||||
});
|
||||
// or by SSE
|
||||
const server = mcp({
|
||||
url: "http://localhost:8000/mcp",
|
||||
verbose: true,
|
||||
});
|
||||
|
||||
// 3. Get tools from MCP server
|
||||
const tools = await server.tools();
|
||||
|
||||
// Now you can create an agent with the tools
|
||||
const agent = agent({
|
||||
name: "My Agent",
|
||||
systemPrompt: "You are a helpful assistant that can use the provided tools to answer questions.",
|
||||
llm: openai({ model: "gpt-4o" }),
|
||||
tools: tools,
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## Function tool
|
||||
|
||||
You can still use the `FunctionTool` class to define a tool.
|
||||
@@ -79,7 +115,8 @@ Note: calling the `bind` method will return a new `FunctionTool` instance, witho
|
||||
|
||||
Example to pass a `userToken` as additional argument:
|
||||
```ts
|
||||
import { agent, tool } from "llamaindex";
|
||||
import { tool } from "llamaindex";
|
||||
import { agent } from "@llamaindex/workflow";
|
||||
|
||||
// first arg is LLM input, second is bound arg
|
||||
const queryKnowledgeBase = async ({ question }, { userToken }) => {
|
||||
|
||||
@@ -2,149 +2,17 @@
|
||||
title: Workflows
|
||||
---
|
||||
|
||||
A `Workflow` in LlamaIndexTS is an event-driven abstraction used to chain together several events. Workflows are made up of `steps`, with each step responsible for handling certain event types and emitting new events.
|
||||
A `Workflow` in LlamaIndex is a lightweight, event-driven abstraction used to chain together several events. Workflows are made up of `handlers`, with each one responsible for processing specific event types and emitting new events.
|
||||
|
||||
Workflows in LlamaIndexTS work by defining step functions that handle specific event types and emit new events.
|
||||
|
||||
When a step function is added to a workflow, you need to specify the input and optionally the output event types (used for validation). The specification of the input events ensures each step only runs when an accepted event is ready.
|
||||
|
||||
You can create a `Workflow` to do anything! Build an agent, a RAG flow, an extraction flow, or anything else you want.
|
||||
Workflows are designed to be flexible and can be used to build agents, RAG flows, extraction flows, or anything else you want to implement.
|
||||
|
||||
To use workflows install this package:
|
||||
|
||||
```package-install
|
||||
npm i @llamaindex/workflow
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
This package is a stable, production-ready version of our [llama-flow](/docs/llamaflow) project.
|
||||
|
||||
As an illustrative example, let's consider a naive workflow where a joke is generated and then critiqued.
|
||||
While you can still reference the llama-flow documentation for detailed information about the underlying concepts, we recommend using the `@llamaindex/workflow` package for all new projects to ensure stability and long-term availability.
|
||||
|
||||
<include cwd>../../examples/workflow/joke.ts</include>
|
||||
|
||||
There's a few moving pieces here, so let's go through this piece by piece.
|
||||
|
||||
### Defining Workflow Events
|
||||
|
||||
```typescript
|
||||
export class JokeEvent extends WorkflowEvent<{ joke: string }> {}
|
||||
```
|
||||
|
||||
Events are user-defined classes that extend `WorkflowEvent` and contain arbitrary data provided as template argument. In this case, our workflow relies on a single user-defined event, the `JokeEvent` with a `joke` attribute of type `string`.
|
||||
|
||||
### Setting up the Workflow Class
|
||||
|
||||
```typescript
|
||||
const llm = new OpenAI();
|
||||
...
|
||||
const jokeFlow = new Workflow<unknown, string, string>();
|
||||
```
|
||||
|
||||
Our workflow is implemented by initiating the `Workflow` class with three generic types: the context type (unknown), input type (string), and output type (string). The context type is `unknown`, as we're not using a shared context in this example.
|
||||
|
||||
For simplicity, we created an `OpenAI` llm instance that we're using for inference in our workflow.
|
||||
|
||||
### Workflow Entry Points
|
||||
|
||||
```typescript
|
||||
const generateJoke = async (_: unknown, ev: StartEvent<string>) => {
|
||||
const prompt = `Write your best joke about ${ev.data}.`;
|
||||
const response = await llm.complete({ prompt });
|
||||
return new JokeEvent({ joke: response.text });
|
||||
};
|
||||
```
|
||||
|
||||
Here, we come to the entry-point of our workflow. While events are user-defined, there are two special-case events, the `StartEvent` and the `StopEvent`. These events are predefined, but we can specify the payload type using generic types. We're using `StartEvent<string>` to indicate that we're going to send an input of type string.
|
||||
|
||||
To add this step to the workflow, we use the `addStep` method with an object specifying the input and output event types:
|
||||
|
||||
```typescript
|
||||
jokeFlow.addStep(
|
||||
{
|
||||
inputs: [StartEvent<string>],
|
||||
outputs: [JokeEvent],
|
||||
},
|
||||
generateJoke
|
||||
);
|
||||
```
|
||||
|
||||
### Workflow Exit Points
|
||||
|
||||
```typescript
|
||||
const critiqueJoke = async (_: unknown, ev: JokeEvent) => {
|
||||
const prompt = `Give a thorough critique of the following joke: ${ev.data.joke}`;
|
||||
const response = await llm.complete({ prompt });
|
||||
return new StopEvent(response.text);
|
||||
};
|
||||
```
|
||||
|
||||
Here, we have our second and last step in the workflow. We know it's the last step because the special `StopEvent` is returned. When the workflow encounters a returned `StopEvent`, it immediately stops the workflow and returns the result. Note that we're using the generic type `StopEvent<string>` to indicate that we're returning a string.
|
||||
|
||||
Add this step to the workflow:
|
||||
|
||||
```typescript
|
||||
jokeFlow.addStep(
|
||||
{
|
||||
inputs: [JokeEvent],
|
||||
outputs: [StopEvent<string>],
|
||||
},
|
||||
critiqueJoke
|
||||
);
|
||||
```
|
||||
|
||||
### Running the Workflow
|
||||
|
||||
```typescript
|
||||
const result = await jokeFlow.run("pirates");
|
||||
console.log(result.data.result);
|
||||
```
|
||||
|
||||
Lastly, we run the workflow. The `.run()` method is async, so we use await here to wait for the result.
|
||||
|
||||
## Working with Shared Context/State
|
||||
|
||||
Optionally, you can choose to use a shared context between steps by specifying a context type when creating the workflow. Here's an example where multiple steps access a shared state:
|
||||
|
||||
```typescript
|
||||
import { HandlerContext } from "llamaindex";
|
||||
|
||||
type MyContextData = {
|
||||
query: string;
|
||||
intermediateResults: any[];
|
||||
}
|
||||
|
||||
const query = async (context: HandlerContext<MyContextData>, ev: MyEvent) => {
|
||||
// get the query from the context
|
||||
const query = context.data.query;
|
||||
// do something with context and event
|
||||
const val = ...
|
||||
// store in context
|
||||
context.data.intermediateResults.push(val);
|
||||
|
||||
return new StopEvent({ result });
|
||||
};
|
||||
```
|
||||
|
||||
## Waiting for Multiple Events
|
||||
|
||||
The context does more than just hold data, it also provides utilities to buffer and wait for multiple events.
|
||||
|
||||
For example, you might have a step that waits for a query and retrieved nodes before synthesizing a response:
|
||||
|
||||
```typescript
|
||||
const synthesize = async (context: Context, ev1: QueryEvent, ev2: RetrieveEvent) => {
|
||||
const subPrompts = [`Answer this query using the context provided: ${ev1.data.query}`, `Context: ${ev2.data.context}`];
|
||||
const prompt = subPrompts.join("\n");
|
||||
const response = await llm.complete({ prompt });
|
||||
return new StopEvent({ result: response.text });
|
||||
};
|
||||
```
|
||||
|
||||
Passing multiple events, we can buffer and wait for ALL expected events to arrive. The receiving step function will only be called once all events have arrived.
|
||||
|
||||
## Manually Triggering Events
|
||||
|
||||
Normally, events are triggered by returning another event during a step. However, events can also be manually dispatched using the `ctx.sendEvent(event)` method within a workflow.
|
||||
|
||||
## Examples
|
||||
|
||||
You can find many useful examples of using workflows in the [examples folder](https://github.com/run-llama/LlamaIndexTS/blob/main/examples/workflow).
|
||||
|
||||
@@ -5,6 +5,12 @@ title: DiscordReader
|
||||
DiscordReader is a simple data loader that reads all messages in a given Discord channel and returns them as Document objects.
|
||||
It uses the [@discordjs/rest](https://github.com/discordjs/discord.js/tree/main/packages/rest) library to fetch the messages.
|
||||
|
||||
## Installation
|
||||
|
||||
```package-install
|
||||
npm install @llamaindex/discord
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
First step is to create a Discord Application and generating a bot token [here](https://discord.com/developers/applications).
|
||||
@@ -12,7 +18,7 @@ In your Discord Application, go to the `OAuth2` tab and generate an invite URL b
|
||||
This will invite the bot with the necessary permissions to read messages.
|
||||
Copy the URL in your browser and select the server you want your bot to join.
|
||||
|
||||
<include cwd>../../examples/readers/src/discord.ts</include>
|
||||
<include cwd>../../examples/readers/discord/reader.ts</include>
|
||||
|
||||
### Params
|
||||
|
||||
|
||||
@@ -21,27 +21,18 @@ To install readers call:
|
||||
|
||||
We offer readers for different file formats.
|
||||
|
||||
```ts twoslash
|
||||
import { CSVReader } from '@llamaindex/readers/csv'
|
||||
import { PDFReader } from '@llamaindex/readers/pdf'
|
||||
import { JSONReader } from '@llamaindex/readers/json'
|
||||
import { MarkdownReader } from '@llamaindex/readers/markdown'
|
||||
import { HTMLReader } from '@llamaindex/readers/html'
|
||||
// you can find more readers in the documentation
|
||||
```ts twoslash
|
||||
import { CSVReader } from '@llamaindex/readers/csv';
|
||||
import { DocxReader } from '@llamaindex/readers/docx';
|
||||
import { HTMLReader } from '@llamaindex/readers/html';
|
||||
import { ImageReader } from '@llamaindex/readers/image';
|
||||
import { JSONReader } from '@llamaindex/readers/json';
|
||||
import { MarkdownReader } from '@llamaindex/readers/markdown';
|
||||
import { ObsidianReader } from '@llamaindex/readers/obsidian';
|
||||
import { PDFReader } from '@llamaindex/readers/pdf';
|
||||
import { TextFileReader } from '@llamaindex/readers/text';
|
||||
```
|
||||
|
||||
Additionally the following loaders exist without separate documentation:
|
||||
|
||||
- `AssemblyAIReader` transcribes audio using [AssemblyAI](https://www.assemblyai.com/).
|
||||
- [AudioTranscriptReader](/docs/api/classes/AudioTranscriptReader): loads entire transcript as a single document.
|
||||
- [AudioTranscriptParagraphsReader](/docs/api/classes/AudioTranscriptParagraphsReader): creates a document per paragraph.
|
||||
- [AudioTranscriptSentencesReader](/docs/api/classes/AudioTranscriptSentencesReader): creates a document per sentence.
|
||||
- [AudioSubtitlesReader](/docs/api/classes/AudioTranscriptParagraphsReader): creates a document containing the subtitles of a transcript.
|
||||
- [NotionReader](/docs/api/classes/NotionReader) loads [Notion](https://www.notion.so/) pages.
|
||||
- [SimpleMongoReader](/docs/api/classes/SimpleMongoReader) loads data from a [MongoDB](https://www.mongodb.com/).
|
||||
|
||||
Check the [LlamaIndexTS Github](https://github.com/run-llama/LlamaIndexTS) for the most up to date overview of integrations.
|
||||
|
||||
## SimpleDirectoryReader
|
||||
|
||||
[Open in StackBlitz](https://stackblitz.com/github/run-llama/LlamaIndexTS/tree/main/examples/readers?file=src/simple-directory-reader.ts&title=Simple%20Directory%20Reader)
|
||||
|
||||
@@ -112,6 +112,3 @@ The returned `imageDocs` have the alt text assigned as text and the image path a
|
||||
|
||||
You can see the full example file [here](https://github.com/run-llama/LlamaIndexTS/blob/main/examples/readers/src/llamaparse-json.ts).
|
||||
|
||||
## API Reference
|
||||
|
||||
- [LlamaParseReader](/docs/api/classes/LlamaParseReader)
|
||||
|
||||
@@ -32,7 +32,7 @@ They can be divided into two groups.
|
||||
#### Advanced params:
|
||||
|
||||
- `resultType` can be set to `markdown`, `text` or `json`. Defaults to `text`. More information about `json` mode on the next pages.
|
||||
- `language` primarily helps with OCR recognition. Defaults to `en`. Click [here](/docs/api/type-aliases/Language) for a list of supported languages.
|
||||
- `language` primarily helps with OCR recognition. Defaults to `en`.
|
||||
- `parsingInstructions?` Optional. Can help with complicated document structures. See this [LlamaIndex Blog Post](https://www.llamaindex.ai/blog/launching-the-first-genai-native-document-parsing-platform) for an example.
|
||||
- `skipDiagonalText?` Optional. Set to true to ignore diagonal text. (Text that is not rotated 0, 90, 180 or 270 degrees)
|
||||
- `invalidateCache?` Optional. Set to true to ignore the LlamaCloud cache. All document are kept in cache for 48hours after the job was completed to avoid processing the same document twice. Can be useful for testing when trying to re-parse the same document with, e.g. different `parsingInstructions`.
|
||||
@@ -61,4 +61,3 @@ Below a full example of `LlamaParse` integrated in `SimpleDirectoryReader` with
|
||||
## API Reference
|
||||
|
||||
- [SimpleDirectoryReader](/docs/api/classes/SimpleDirectoryReader)
|
||||
- [LlamaParseReader](/docs/api/classes/LlamaParseReader)
|
||||
|
||||
@@ -98,5 +98,4 @@ You can assign any other values of the JSON response to the Document as needed.
|
||||
|
||||
## API Reference
|
||||
|
||||
- [LlamaParseReader](/docs/api/classes/LlamaParseReader)
|
||||
- [SimpleDirectoryReader](/docs/api/classes/SimpleDirectoryReader)
|
||||
|
||||
@@ -88,7 +88,7 @@ async function main() {
|
||||
|
||||
const response = await queryEngine.query({
|
||||
query: "What did the author do in college?",
|
||||
});
|
||||
}); // Additional filters and params can be passed as options
|
||||
|
||||
// Output response
|
||||
console.log(response.toString());
|
||||
|
||||
@@ -2,89 +2,43 @@
|
||||
title: Azure OpenAI
|
||||
---
|
||||
|
||||
To use Azure OpenAI, you only need to set a few environment variables together with the `OpenAI` class.
|
||||
|
||||
For example:
|
||||
|
||||
## Environment Variables
|
||||
|
||||
```
|
||||
export AZURE_OPENAI_KEY="<YOUR KEY HERE>"
|
||||
export AZURE_OPENAI_ENDPOINT="<YOUR ENDPOINT, see https://learn.microsoft.com/en-us/azure/ai-services/openai/quickstart?tabs=command-line%2Cpython&pivots=rest-api>"
|
||||
export AZURE_OPENAI_DEPLOYMENT="gpt-4" # or some other deployment name
|
||||
```
|
||||
To use Azure OpenAI, you only need to install the `@llamaindex/azure` package:
|
||||
|
||||
## Installation
|
||||
|
||||
```package-install
|
||||
npm i llamaindex @llamaindex/openai
|
||||
npm i llamaindex @llamaindex/azure
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
The class `AzureOpenAI` is used for setting the LLM and `AzureOpenAIEmbedding` is used for setting the embedding model, e.g.:
|
||||
|
||||
```ts
|
||||
import { Settings } from "llamaindex";
|
||||
import { OpenAI } from "@llamaindex/openai";
|
||||
import { AzureOpenAI, AzureOpenAIEmbedding } from "@llamaindex/azure";
|
||||
|
||||
Settings.llm = new OpenAI({ model: "gpt-4", temperature: 0 });
|
||||
```
|
||||
|
||||
## 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,
|
||||
Settings.llm = new AzureOpenAI({
|
||||
apiKey: '[key]',
|
||||
deployment: '[model]',
|
||||
apiVersion: '[version]',
|
||||
endpoint: `https://[deployment].openai.azure.com/`,
|
||||
});
|
||||
Settings.embedModel = new AzureOpenAIEmbedding({
|
||||
apiKey: '[key]',
|
||||
deployment: '[embedding-model]',
|
||||
apiVersion: '[version]',
|
||||
endpoint: `https://[deployment].openai.azure.com/`,
|
||||
});
|
||||
```
|
||||
|
||||
## Full Example
|
||||
Instead of explicitly setting the API key, deployment, version, and endpoint in the constructor, you can use the following environment variables: `AZURE_OPENAI_DEPLOYMENT` for the model deployment name, `AZURE_OPENAI_KEY` for your API key, `AZURE_OPENAI_ENDPOINT` for your Azure endpoint URL, and `AZURE_OPENAI_API_VERSION` for the API version.
|
||||
|
||||
```ts
|
||||
import { Document, VectorStoreIndex, Settings } from "llamaindex";
|
||||
import { OpenAI } from "@llamaindex/openai";
|
||||
## Examples
|
||||
|
||||
Settings.llm = new OpenAI({ model: "gpt-4", temperature: 0 });
|
||||
|
||||
async function main() {
|
||||
const document = new Document({ text: essay, id_: "essay" });
|
||||
|
||||
// Load and index documents
|
||||
const index = await VectorStoreIndex.fromDocuments([document]);
|
||||
|
||||
// get retriever
|
||||
const retriever = index.asRetriever();
|
||||
|
||||
// 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);
|
||||
}
|
||||
```
|
||||
See the [Azure examples](https://github.com/run-llama/LlamaIndexTS/tree/main/examples/storage/azure) for more examples of how to use Azure OpenAI.
|
||||
|
||||
## API Reference
|
||||
|
||||
- [OpenAI](/docs/api/classes/OpenAI)
|
||||
- [AzureOpenAI](/docs/api/classes/AzureOpenAI)
|
||||
- [AzureOpenAIEmbedding](/docs/api/classes/AzureOpenAIEmbedding)
|
||||
@@ -120,11 +120,11 @@ async function main() {
|
||||
|
||||
```ts
|
||||
import { BEDROCK_MODELS, Bedrock } from "@llamaindex/community";
|
||||
import { FunctionTool, LLMAgent } from "llamaindex";
|
||||
import { tool } from "llamaindex";
|
||||
import { agent } from "@llamaindex/workflow";
|
||||
import { z } from "zod";
|
||||
|
||||
const sumNumbers = FunctionTool.from(
|
||||
({ a, b }: { a: number; b: number }) => `${a + b}`,
|
||||
const sumNumbers = tool(
|
||||
{
|
||||
name: "sumNumbers",
|
||||
description: "Use this function to sum two numbers",
|
||||
@@ -136,11 +136,11 @@ const sumNumbers = FunctionTool.from(
|
||||
description: "The second number",
|
||||
}),
|
||||
}),
|
||||
execute: ({ a, b }: { a: number; b: number }) => `${a + b}`,
|
||||
},
|
||||
);
|
||||
|
||||
const divideNumbers = FunctionTool.from(
|
||||
({ a, b }: { a: number; b: number }) => `${a / b}`,
|
||||
const divideNumbers = tool(
|
||||
{
|
||||
name: "divideNumbers",
|
||||
description: "Use this function to divide two numbers",
|
||||
@@ -152,6 +152,7 @@ const divideNumbers = FunctionTool.from(
|
||||
description: "The divisor b to divide by",
|
||||
}),
|
||||
}),
|
||||
execute: ({ a, b }: { a: number; b: number }) => `${a / b}`,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -161,15 +162,15 @@ const bedrock = new Bedrock({
|
||||
});
|
||||
|
||||
async function main() {
|
||||
const agent = new LLMAgent({
|
||||
const myAgent = agent({
|
||||
llm: bedrock,
|
||||
tools: [sumNumbers, divideNumbers],
|
||||
});
|
||||
|
||||
const response = await agent.chat({
|
||||
message: "How much is 5 + 5? then divide by 2",
|
||||
});
|
||||
const response = await myAgent.run(
|
||||
"How much is 5 + 5? then divide by 2",
|
||||
);
|
||||
|
||||
console.log(response.message);
|
||||
console.log(response);
|
||||
}
|
||||
```
|
||||
|
||||
@@ -55,7 +55,7 @@ const results = await queryEngine.query({
|
||||
|
||||
## Full Example
|
||||
|
||||
<include cwd>../../examples/groq.ts</include>
|
||||
<include cwd>../../examples/models/groq.ts</include>
|
||||
|
||||
## API Reference
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ npm i @llamaindex/server
|
||||
|
||||
## Quick Start
|
||||
|
||||
Create index.ts file and add the following code:
|
||||
Create an `index.ts` file and add the following code:
|
||||
|
||||
```ts
|
||||
import { LlamaIndexServer } from "@llamaindex/server";
|
||||
@@ -43,20 +43,20 @@ new LlamaIndexServer({
|
||||
|
||||
In the same directory as `index.ts`, run the following command to start the server:
|
||||
|
||||
```bash
|
||||
tsx index.ts
|
||||
```
|
||||
```bash
|
||||
tsx index.ts
|
||||
```
|
||||
The server will start at `http://localhost:3000`
|
||||
|
||||
You can also make a request to the server:
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:3000/api/chat" -H "Content-Type: application/json" -d '{"message": "Who is the first president of the United States?"}'
|
||||
```
|
||||
```bash
|
||||
curl -X POST "http://localhost:3000/api/chat" -H "Content-Type: application/json" -d '{"message": "Who is the first president of the United States?"}'
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
The LlamaIndexServer accepts the following configuration
|
||||
The `LlamaIndexServer` accepts the following configuration options:
|
||||
|
||||
- `workflow`: A callable function that creates a workflow instance for each request
|
||||
- `uiConfig`: An object to configure the chat UI containing the following properties:
|
||||
@@ -68,6 +68,72 @@ The LlamaIndexServer accepts the following configuration
|
||||
LlamaIndexServer accepts all the configuration options from Nextjs Custom Server such as `port`, `hostname`, `dev`, etc.
|
||||
See all Nextjs Custom Server options [here](https://nextjs.org/docs/app/building-your-application/configuring/custom-server).
|
||||
|
||||
## AI-generated UI Components
|
||||
|
||||
The LlamaIndex server provides support for rendering workflow events using custom UI components, allowing you to extend and customize the chat interface.
|
||||
These components can be auto-generated using an LLM by providing a JSON schema of the workflow event.
|
||||
|
||||
### UI Event Schema
|
||||
|
||||
To display custom UI components, your workflow needs to emit UI events that have an event type for identification and a data object:
|
||||
|
||||
```typescript
|
||||
class UIEvent extends WorkflowEvent<{
|
||||
type: "ui_event";
|
||||
data: UIEventData;
|
||||
}> {}
|
||||
```
|
||||
|
||||
The `data` object can be any JSON object. To enable AI generation of the UI component, you need to provide a schema for that data (here we're using Zod):
|
||||
|
||||
```typescript
|
||||
const MyEventDataSchema = z.object({
|
||||
stage: z.enum(["retrieve", "analyze", "answer"]).describe("The current stage the workflow process is in."),
|
||||
progress: z.number().min(0).max(1).describe("The progress in percent of the current stage"),
|
||||
}).describe("WorkflowStageProgress");
|
||||
|
||||
type UIEventData = z.infer<typeof MyEventDataSchema>;
|
||||
```
|
||||
|
||||
### Generate UI Components
|
||||
|
||||
The `generateEventComponent` function uses an LLM to generate a custom UI component based on the JSON schema of a workflow event. The schema should contain accurate descriptions of each field so that the LLM can generate matching components for your use case. We've done this for you in the example above using the `describe` function from Zod:
|
||||
|
||||
```typescript
|
||||
import { OpenAI } from "llamaindex";
|
||||
import { generateEventComponent } from "@llamaindex/server";
|
||||
import { MyEventDataSchema } from "./your-workflow";
|
||||
|
||||
// Also works well with Claude 3.5 Sonnet and Google Gemini 2.5 Pro
|
||||
const llm = new OpenAI({ model: "gpt-4.1" });
|
||||
const code = generateEventComponent(MyEventDataSchema, llm);
|
||||
```
|
||||
|
||||
After generating the code, we need to save it to a file. The file name must match the event type from your workflow (e.g., `ui_event.jsx` for handling events with `ui_event` type):
|
||||
|
||||
```ts
|
||||
fs.writeFileSync("components/ui_event.jsx", code);
|
||||
```
|
||||
|
||||
Feel free to modify the generated code to match your needs. If you're not satisfied with the generated code, we suggest improving the provided JSON schema first or trying another LLM.
|
||||
|
||||
> Note that `generateEventComponent` is generating JSX code, but you can also provide a TSX file.
|
||||
|
||||
|
||||
### Server Setup
|
||||
|
||||
To use the generated UI components, you need to initialize the LlamaIndex server with the `componentsDir` that contains your custom UI components:
|
||||
|
||||
```ts
|
||||
new LlamaIndexServer({
|
||||
workflow: createWorkflow,
|
||||
uiConfig: {
|
||||
appTitle: "LlamaIndex App",
|
||||
componentsDir: "components",
|
||||
},
|
||||
}).start();
|
||||
```
|
||||
|
||||
## Default Endpoints and Features
|
||||
|
||||
### Chat Endpoint
|
||||
@@ -85,69 +151,19 @@ The server always provides a chat interface at the root path (`/`) with:
|
||||
### Static File Serving
|
||||
|
||||
- The server automatically mounts the `data` and `output` folders at `{server_url}{api_prefix}/files/data` (default: `/api/files/data`) and `{server_url}{api_prefix}/files/output` (default: `/api/files/output`) respectively.
|
||||
- Your workflows can use both folders to store and access files. As a convention, the `data` folder is used for documents that are ingested and the `output` folder is used for documents that are generated by the workflow.
|
||||
- Your workflows can use both folders to store and access files. By convention, the `data` folder is used for documents that are ingested, and the `output` folder is used for documents generated by the workflow.
|
||||
|
||||
|
||||
## Custom UI Components
|
||||
|
||||
The LlamaIndex server provides support for rendering workflow events using custom UI components, allowing you to extend and customize the chat interface.
|
||||
|
||||
### Overview
|
||||
|
||||
Custom UI components are a powerful feature that enables you to:
|
||||
|
||||
- Add custom interface elements to the chat UI using React JSX or TSX files
|
||||
- Extend the default chat interface functionality
|
||||
- Create specialized visualizations or interactions
|
||||
|
||||
### Configuration
|
||||
|
||||
Your workflow must emit events that fit this structure, allowing the LlamaIndex server to display the right UI components based on the event type.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "<event_name>",
|
||||
"data": <data model>
|
||||
}
|
||||
```
|
||||
|
||||
### Server Setup
|
||||
|
||||
1. Initialize the LlamaIndex server with a component directory:
|
||||
|
||||
```ts
|
||||
new LlamaIndexServer({
|
||||
workflow: createWorkflow,
|
||||
uiConfig: {
|
||||
appTitle: "LlamaIndex App",
|
||||
componentsDir: "components",
|
||||
},
|
||||
}).start();
|
||||
```
|
||||
|
||||
2. Add the custom component code to the directory following the naming pattern:
|
||||
|
||||
- File Extension: `.jsx` and `.tsx` for React components
|
||||
- File Name: Should match the event type from your workflow (e.g., `deep_research_event.jsx` for handling `deep_research_event` type that you defined in your workflow). If there are TSX and JSX files with the same name, the TSX file will be used.
|
||||
- Component Name: Export a default React component named `Component` that receives props from the event data
|
||||
|
||||
Example component structure:
|
||||
|
||||
```jsx
|
||||
function Component({ events }) {
|
||||
// Your component logic here
|
||||
return (
|
||||
// Your UI code here
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. Always provide a workflow factory that creates fresh workflow instances
|
||||
2. Use environment variables for sensitive configuration
|
||||
3. Use starter questions to guide users in the chat UI
|
||||
1. Always provide a workflow factory that creates a fresh workflow instance for each request.
|
||||
2. Use environment variables for sensitive configuration (e.g., API keys).
|
||||
3. Use starter questions to guide users in the chat UI.
|
||||
|
||||
## Getting Started with a New Project
|
||||
|
||||
Want to start a new project with LlamaIndexServer? Check out our [create-llama](https://github.com/run-llama/create-llama) tool to quickly generate a new project with LlamaIndexServer.
|
||||
Want to start a new project with LlamaIndexServer? Check out our [create-llama](https://github.com/run-llama/create-llama) tool to quickly generate a new project with LlamaIndexServer.
|
||||
|
||||
## API Reference
|
||||
|
||||
- [LlamaIndexServer](https://github.com/run-llama/create-llama/blob/main/packages/server)
|
||||
@@ -15,7 +15,7 @@ In LlamaIndex, an agent is a semi-autonomous piece of software powered by an LLM
|
||||
You'll need to have a recent version of [Node.js](https://nodejs.org/en) installed. Then you can install LlamaIndex.TS by running
|
||||
|
||||
```package-install
|
||||
npm i llamaindex @llamaindex/openai @llamaindex/readers @llamaindex/huggingface
|
||||
npm i llamaindex @llamaindex/openai @llamaindex/readers @llamaindex/huggingface @llamaindex/workflow
|
||||
```
|
||||
|
||||
## Choose your model
|
||||
|
||||
@@ -35,11 +35,16 @@ First we'll need to pull in our dependencies. These are:
|
||||
import "dotenv/config";
|
||||
import {
|
||||
agent,
|
||||
AgentStream,
|
||||
tool,
|
||||
agentStreamEvent,
|
||||
openai,
|
||||
} from "@llamaindex/workflow";
|
||||
import {
|
||||
tool,
|
||||
Settings,
|
||||
} from "llamaindex";
|
||||
import {
|
||||
openai,
|
||||
} from "@llamaindex/openai";
|
||||
import { z } from "zod";
|
||||
```
|
||||
|
||||
@@ -108,11 +113,10 @@ const myAgent = agent({ tools });
|
||||
|
||||
### Ask the agent a question
|
||||
|
||||
We can use the `chat` interface to ask our agent a question, and it will use the tools we've defined to find an answer.
|
||||
We can use the `run` method to ask our agent a question, and it will use the tools we've defined to find an answer.
|
||||
|
||||
```javascript
|
||||
const context = myAgent.run("Sum 101 and 303");
|
||||
const result = await context;
|
||||
const result = await myAgent.run("Sum 101 and 303");
|
||||
console.log(result.data);
|
||||
```
|
||||
You will see the following output:
|
||||
@@ -123,12 +127,13 @@ You will see the following output:
|
||||
{ result: 'The sum of 101 and 303 is 404.' }
|
||||
```
|
||||
|
||||
To stream the response, you can use the `AgentStream` event which provides chunks of the response as they become available. This allows you to display the response incrementally rather than waiting for the full response:
|
||||
To stream the response, you need to call `runStream`, which returns a stream of events.
|
||||
The `agentStreamEvent` provides chunks of the response as they become available. This allows you to display the response incrementally rather than waiting for the full response:
|
||||
|
||||
```javascript
|
||||
const context = myAgent.run("Add 101 and 303");
|
||||
for await (const event of context) {
|
||||
if (event instanceof AgentStream) {
|
||||
const events = myAgent.runStream("Add 101 and 303");
|
||||
for await (const event of events) {
|
||||
if (agentStreamEvent.include(event)) {
|
||||
process.stdout.write(event.data.delta);
|
||||
}
|
||||
}
|
||||
@@ -140,18 +145,18 @@ for await (const event of context) {
|
||||
The sum of 101 and 303 is 404.
|
||||
```
|
||||
|
||||
Note that we're filtering for `agentStreamEvent` as an agent might return other events - more about that in the following section.
|
||||
|
||||
### Logging workflow events
|
||||
|
||||
To log the workflow events, you can check the event type and log the event data.
|
||||
|
||||
```javascript
|
||||
const context = myAgent.run("Sum 202 and 404");
|
||||
for await (const event of context) {
|
||||
if (event instanceof AgentStream) {
|
||||
const events = myAgent.runStream("Sum 202 and 404");
|
||||
for await (const event of events) {
|
||||
if (agentStreamEvent.include(event)) {
|
||||
// Stream the response
|
||||
for (const chunk of event.data.delta) {
|
||||
process.stdout.write(chunk);
|
||||
}
|
||||
process.stdout.write(event.data.delta);
|
||||
} else {
|
||||
// Log other events
|
||||
console.log("\nWorkflow event:", JSON.stringify(event, null, 2));
|
||||
|
||||
@@ -30,16 +30,16 @@ Settings.llm = ollama({
|
||||
|
||||
### Run local agent
|
||||
|
||||
You can also create local agent by importing `agent` from `llamaindex`.
|
||||
You can also create local agent by importing `agent` from `@llamaindex/workflow`.
|
||||
|
||||
```javascript
|
||||
import { agent } from "llamaindex";
|
||||
import { agent } from "@llamaindex/workflow";
|
||||
|
||||
const workflow = agent({
|
||||
tools: [getWeatherTool],
|
||||
});
|
||||
|
||||
const workflowContext = workflow.run(
|
||||
const resutl = workflow.run(
|
||||
"What's the weather like in San Francisco?",
|
||||
);
|
||||
```
|
||||
|
||||
@@ -25,7 +25,8 @@ We'll be bringing in `SimpleDirectoryReader`, `HuggingFaceEmbedding`, `VectorSto
|
||||
|
||||
```javascript
|
||||
import { QueryEngineTool, Settings, VectorStoreIndex } from "llamaindex";
|
||||
import { OpenAI, OpenAIAgent } from "@llamaindex/openai";
|
||||
import { agent } from "@llamaindex/workflow";
|
||||
import { openai } from "@llamaindex/openai";
|
||||
import { HuggingFaceEmbedding } from "@llamaindex/huggingface";
|
||||
import { SimpleDirectoryReader } from "@llamaindex/readers/directory";
|
||||
```
|
||||
@@ -58,25 +59,9 @@ We will convert our text into embeddings using the `VectorStoreIndex` class thro
|
||||
const index = await VectorStoreIndex.fromDocuments(documents);
|
||||
```
|
||||
|
||||
### Configure a retriever
|
||||
|
||||
Before LlamaIndex can send a query to the LLM, it needs to find the most relevant chunks to send. That's the purpose of a `Retriever`. We're going to get `VectorStoreIndex` to act as a retriever for us
|
||||
|
||||
```javascript
|
||||
const retriever = await index.asRetriever();
|
||||
```
|
||||
|
||||
### Configure how many documents to retrieve
|
||||
|
||||
By default LlamaIndex will retrieve just the 2 most relevant chunks of text. This document is complex though, so we'll ask for more context.
|
||||
|
||||
```javascript
|
||||
retriever.similarityTopK = 10;
|
||||
```
|
||||
|
||||
### Use index.queryTool
|
||||
|
||||
`index.queryTool` creates a `QueryEngineTool` that can be used be an agent to query data from the index.
|
||||
`index.queryTool` creates a `QueryEngineTool` that can be used be an agent to query data from the index:
|
||||
|
||||
```javascript
|
||||
const tools = [
|
||||
@@ -85,9 +70,17 @@ const tools = [
|
||||
name: "san_francisco_budget_tool",
|
||||
description: `This tool can answer detailed questions about the individual components of the budget of San Francisco in 2023-2024.`,
|
||||
},
|
||||
options: { similarityTopK: 10 },
|
||||
}),
|
||||
];
|
||||
```
|
||||
|
||||
The `metadata` that we're setting helps the agent to decide when to use the tool.
|
||||
Note that by default LlamaIndex will retrieve just the 2 most relevant chunks of text. This document is complex though, so we'll ask for more context by setting `similarityTopK` to 10.
|
||||
|
||||
Now, we can create an agent using the `QueryEngineTool`:
|
||||
|
||||
```javascript
|
||||
// Create an agent using the tools array
|
||||
const ragAgent = agent({ tools });
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ const tools = [
|
||||
name: "san_francisco_budget_tool",
|
||||
description: `This tool can answer detailed questions about the individual components of the budget of San Francisco in 2023-2024.`,
|
||||
},
|
||||
options: { similarityTopK: 10 },
|
||||
}),
|
||||
tool({
|
||||
name: "sumNumbers",
|
||||
|
||||
@@ -8,9 +8,10 @@ We have a comprehensive, step-by-step [guide to building agents in LlamaIndex.TS
|
||||
|
||||
In a new folder:
|
||||
|
||||
```bash npm2yarn
|
||||
```package-install
|
||||
npm init
|
||||
npm i -D typescript @types/node
|
||||
npm i @llamaindex/openai @llamaindex/workflow llamaindex zod
|
||||
```
|
||||
|
||||
## Run agent
|
||||
@@ -20,15 +21,14 @@ Create the file `example.ts`. This code will:
|
||||
- Create two tools for use by the agent:
|
||||
- A `sumNumbers` tool that adds two numbers
|
||||
- A `divideNumbers` tool that divides numbers
|
||||
-
|
||||
- Give an example of the data structure we wish to generate
|
||||
- Prompt the LLM with instructions and the example, plus a sample transcript
|
||||
|
||||
<include cwd>../../examples/agent/openai.ts</include>
|
||||
<include cwd>../../examples/agents/agent/openai.ts</include>
|
||||
|
||||
To run the code:
|
||||
|
||||
```bash
|
||||
```package-install
|
||||
npx tsx example.ts
|
||||
```
|
||||
|
||||
@@ -36,9 +36,18 @@ You should expect output something like:
|
||||
|
||||
```
|
||||
{
|
||||
content: 'The sum of 5 + 5 is 10. When you divide 10 by 2, you get 5.',
|
||||
role: 'assistant',
|
||||
options: {}
|
||||
result: '5 + 5 is 10. Then, 10 divided by 2 is 5.',
|
||||
state: {
|
||||
memory: ChatMemoryBuffer {
|
||||
chatStore: SimpleChatStore {},
|
||||
chatStoreKey: 'chat_history',
|
||||
tokenLimit: 750000
|
||||
},
|
||||
scratchpad: [],
|
||||
currentAgentName: 'Agent',
|
||||
agents: [ 'Agent' ],
|
||||
nextAgentName: null
|
||||
}
|
||||
}
|
||||
Done
|
||||
```
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"basic_agent",
|
||||
"rag",
|
||||
"agents",
|
||||
"workflow",
|
||||
"workflows",
|
||||
"local_llm",
|
||||
"chatbot",
|
||||
"structured_data_extraction"
|
||||
|
||||
@@ -16,7 +16,7 @@ LlamaIndex uses a two stage method when using an LLM with your data:
|
||||
1. **indexing stage**: preparing a knowledge base, and
|
||||
2. **querying stage**: retrieving relevant context from the knowledge to assist the LLM in responding to a question
|
||||
|
||||

|
||||

|
||||
|
||||
This process is also known as Retrieval Augmented Generation (RAG).
|
||||
|
||||
@@ -28,7 +28,7 @@ Let's explore each stage in detail.
|
||||
|
||||
LlamaIndex.TS help you prepare the knowledge base with a suite of data connectors and indexes.
|
||||
|
||||

|
||||

|
||||
|
||||
[**Data Loaders**](/docs/llamaindex/modules/data/readers):
|
||||
A data connector (i.e. `Reader`) ingest data from different data sources and data formats into a simple `Document` representation (text and simple metadata).
|
||||
@@ -54,7 +54,7 @@ LlamaIndex provides composable modules that help you build and integrate RAG pip
|
||||
|
||||
These building blocks can be customized to reflect ranking preferences, as well as composed to reason over multiple knowledge bases in a structured way.
|
||||
|
||||

|
||||

|
||||
|
||||
#### Building Blocks
|
||||
|
||||
|
||||
@@ -8,9 +8,10 @@ One of the most common use-cases for LlamaIndex is Retrieval-Augmented Generatio
|
||||
|
||||
In a new folder, run:
|
||||
|
||||
```bash npm2yarn
|
||||
```package-install
|
||||
npm init
|
||||
npm i -D typescript @types/node
|
||||
npm i llamaindex
|
||||
```
|
||||
|
||||
Then, check out the [installation](/docs/llamaindex/getting_started/installation) steps to install LlamaIndex.TS and prepare an OpenAI key.
|
||||
@@ -26,7 +27,7 @@ Create the file `example.ts`. This code will
|
||||
- index it (which creates embeddings using OpenAI)
|
||||
- create a query engine to answer questions about the data
|
||||
|
||||
<include cwd>../../examples/vectorIndex.ts</include>
|
||||
<include cwd>../../examples/index/vectorIndex.ts</include>
|
||||
|
||||
Create a `tsconfig.json` file in the same folder:
|
||||
|
||||
@@ -34,7 +35,7 @@ Create a `tsconfig.json` file in the same folder:
|
||||
|
||||
Now you can run the code with
|
||||
|
||||
```bash
|
||||
```package-install
|
||||
npx tsx example.ts
|
||||
```
|
||||
|
||||
|
||||
@@ -10,9 +10,10 @@ You can use [other LLMs](/docs/llamaindex/modules/models/llms) via their APIs; i
|
||||
|
||||
In a new folder:
|
||||
|
||||
```bash npm2yarn
|
||||
```package-install
|
||||
npm init
|
||||
npm i -D typescript @types/node
|
||||
npm i @llamaindex/openai zod
|
||||
```
|
||||
|
||||
## Extract data
|
||||
@@ -23,11 +24,11 @@ Create the file `example.ts`. This code will:
|
||||
- Give an example of the data structure we wish to generate
|
||||
- Prompt the LLM with instructions and the example, plus a sample transcript
|
||||
|
||||
<include cwd>../../examples/jsonExtract.ts</include>
|
||||
<include cwd>../../examples/misc/jsonExtract.ts</include>
|
||||
|
||||
To run the code:
|
||||
|
||||
```bash
|
||||
```package-install
|
||||
npx tsx example.ts
|
||||
```
|
||||
|
||||
|
||||
@@ -1,530 +0,0 @@
|
||||
---
|
||||
title: Advanced Event Handling
|
||||
description: Master complex event patterns and middleware with Workflows
|
||||
---
|
||||
|
||||
This guide explores advanced event handling techniques and patterns you can use with Workflows to build more sophisticated patterns.
|
||||
|
||||
## Event Composition
|
||||
|
||||
Workflows allow you to work with different event types and compose them in powerful ways:
|
||||
|
||||
### Multiple Event Types
|
||||
|
||||
You can define multiple event types for different kinds of data flowing through your workflow:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent } from "llamaindex";
|
||||
|
||||
// Define different event types
|
||||
const textEvent = workflowEvent<string>();
|
||||
const numberEvent = workflowEvent<number>();
|
||||
const booleanEvent = workflowEvent<boolean>();
|
||||
const complexEvent = workflowEvent<{ id: string; value: number }>();
|
||||
|
||||
// Create a workflow that can process different event types
|
||||
const workflow = createWorkflow();
|
||||
|
||||
// Handle text events
|
||||
workflow.handle([textEvent], (event) => {
|
||||
console.log(`Processing text: ${event.data}`);
|
||||
return numberEvent.with(event.data.length);
|
||||
});
|
||||
|
||||
// Handle number events
|
||||
workflow.handle([numberEvent], (event) => {
|
||||
const isEven = event.data % 2 === 0;
|
||||
console.log(`Number ${event.data} is ${isEven ? 'even' : 'odd'}`);
|
||||
return booleanEvent.with(isEven);
|
||||
});
|
||||
|
||||
// Handle boolean events
|
||||
workflow.handle([booleanEvent], (event) => {
|
||||
return complexEvent.with({
|
||||
id: crypto.randomUUID(),
|
||||
value: event.data ? 100 : 0
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### Event Branching and Merging
|
||||
|
||||
You can create complex event flows with branching and merging patterns:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent, until, collect } from "llamaindex";
|
||||
|
||||
// Define events for a data processing pipeline
|
||||
const inputEvent = workflowEvent<string>();
|
||||
const validateEvent = workflowEvent<string>();
|
||||
const processEvent = workflowEvent<string>();
|
||||
const errorEvent = workflowEvent<Error>();
|
||||
const resultEvent = workflowEvent<string>();
|
||||
const completeEvent = workflowEvent<string[]>();
|
||||
|
||||
// Create workflow
|
||||
const workflow = createWorkflow();
|
||||
|
||||
// Branch based on input validation
|
||||
workflow.handle([inputEvent], (event) => {
|
||||
if (event.data && event.data.trim().length > 0) {
|
||||
return validateEvent.with(event.data.trim());
|
||||
} else {
|
||||
return errorEvent.with(new Error("Empty input"));
|
||||
}
|
||||
});
|
||||
|
||||
// Process valid inputs
|
||||
workflow.handle([validateEvent], (event) => {
|
||||
return processEvent.with(event.data.toUpperCase());
|
||||
});
|
||||
|
||||
// Handle processing
|
||||
workflow.handle([processEvent], (event) => {
|
||||
return resultEvent.with(`Processed: ${event.data}`);
|
||||
});
|
||||
|
||||
// Handle errors
|
||||
workflow.handle([errorEvent], (event) => {
|
||||
return resultEvent.with(`Error: ${event.data.message}`);
|
||||
});
|
||||
|
||||
// Merge results: collect multiple results into a single completion event
|
||||
workflow.handle([inputEvent], (start) => {
|
||||
const { sendEvent, stream } = getContext();
|
||||
|
||||
// Process all inputs
|
||||
const inputs = start.data.split(',').map(s => s.trim());
|
||||
inputs.forEach(input => sendEvent(inputEvent.with(input)));
|
||||
|
||||
// Collect all results
|
||||
const results = await collect(
|
||||
until(stream, result => resultEvent.include(result))
|
||||
.filter(ev => resultEvent.include(ev))
|
||||
.take(inputs.length)
|
||||
);
|
||||
|
||||
return completeEvent.with(results.map(r => r.data));
|
||||
});
|
||||
```
|
||||
|
||||
## Event Filtering and Transformation
|
||||
|
||||
You can filter and transform events to build sophisticated data processing pipelines:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent } from "llamaindex";
|
||||
|
||||
// Define events
|
||||
const dataEvent = workflowEvent<number>();
|
||||
const evenEvent = workflowEvent<number>();
|
||||
const oddEvent = workflowEvent<number>();
|
||||
const transformedEvent = workflowEvent<string>();
|
||||
const resultEvent = workflowEvent<string[]>();
|
||||
|
||||
// Create workflow
|
||||
const workflow = createWorkflow();
|
||||
|
||||
// Filter even numbers
|
||||
workflow.handle([dataEvent], (event) => {
|
||||
if (event.data % 2 === 0) {
|
||||
return evenEvent.with(event.data);
|
||||
} else {
|
||||
return oddEvent.with(event.data);
|
||||
}
|
||||
});
|
||||
|
||||
// Transform even numbers
|
||||
workflow.handle([evenEvent], (event) => {
|
||||
return transformedEvent.with(`Even: ${event.data}`);
|
||||
});
|
||||
|
||||
// Transform odd numbers
|
||||
workflow.handle([oddEvent], (event) => {
|
||||
return transformedEvent.with(`Odd: ${event.data}`);
|
||||
});
|
||||
|
||||
// Collect and organize results
|
||||
workflow.handle([dataEvent], (start) => {
|
||||
const { sendEvent, stream } = getContext();
|
||||
|
||||
// Generate a sequence of numbers
|
||||
for (let i = 1; i <= 10; i++) {
|
||||
sendEvent(dataEvent.with(i));
|
||||
}
|
||||
|
||||
// Collect transformed events
|
||||
const results = await collect(
|
||||
until(stream)
|
||||
.filter(ev => transformedEvent.include(ev))
|
||||
.take(10)
|
||||
);
|
||||
|
||||
return resultEvent.with(results.map(r => r.data));
|
||||
});
|
||||
```
|
||||
|
||||
## Working with `withTraceEvents` Middleware
|
||||
|
||||
The `withTraceEvents` middleware adds powerful tracing capabilities to your workflows:
|
||||
|
||||
```ts
|
||||
import {
|
||||
createWorkflow,
|
||||
workflowEvent,
|
||||
withTraceEvents,
|
||||
runOnce,
|
||||
createHandlerDecorator
|
||||
} from "llamaindex";
|
||||
|
||||
// Define events
|
||||
const startEvent = workflowEvent<string>();
|
||||
const processEvent = workflowEvent<string>();
|
||||
const resultEvent = workflowEvent<string>();
|
||||
|
||||
// Create workflow with tracing
|
||||
const workflow = withTraceEvents(createWorkflow());
|
||||
|
||||
// Create a custom handler decorator that logs execution time
|
||||
const measureTime = createHandlerDecorator({
|
||||
debugLabel: "measureTime",
|
||||
getInitialValue: () => performance.now(),
|
||||
onBeforeHandler: (handler, context, startTime) => {
|
||||
console.log(`Starting handler execution at ${new Date().toISOString()}`);
|
||||
return handler;
|
||||
},
|
||||
onAfterHandler: (result, context, startTime) => {
|
||||
const duration = performance.now() - startTime;
|
||||
console.log(`Handler executed in ${duration.toFixed(2)}ms`);
|
||||
return startTime; // Return the initial value for next execution
|
||||
}
|
||||
});
|
||||
|
||||
// Run a specific handler only once
|
||||
workflow.handle(
|
||||
[startEvent],
|
||||
runOnce((event) => {
|
||||
console.log("This handler will only run once per workflow context");
|
||||
return processEvent.with(event.data);
|
||||
})
|
||||
);
|
||||
|
||||
// Measure the execution time of this handler
|
||||
workflow.handle(
|
||||
[processEvent],
|
||||
measureTime((event) => {
|
||||
// Simulate processing time
|
||||
const start = Date.now();
|
||||
while (Date.now() - start < 100) {
|
||||
// Busy wait for 100ms
|
||||
}
|
||||
return resultEvent.with(`Processed: ${event.data}`);
|
||||
})
|
||||
);
|
||||
```
|
||||
|
||||
### Debugging with Substreams
|
||||
|
||||
You can use the `substream` feature to debug specific event flows:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent, withTraceEvents } from "llamaindex";
|
||||
|
||||
// Define events
|
||||
const queryEvent = workflowEvent<string>();
|
||||
const fetchEvent = workflowEvent<string>();
|
||||
const resultEvent = workflowEvent<string>();
|
||||
|
||||
// Create workflow with tracing
|
||||
const workflow = withTraceEvents(createWorkflow());
|
||||
|
||||
// Query handler
|
||||
workflow.handle([queryEvent], (event) => {
|
||||
const { sendEvent, stream } = getContext();
|
||||
|
||||
// Create a specific fetch event for this query
|
||||
const fetchInstance = fetchEvent.with(event.data);
|
||||
sendEvent(fetchInstance);
|
||||
|
||||
// Create a substream to only track events related to this fetch
|
||||
const substream = workflow.substream(fetchInstance, stream);
|
||||
|
||||
// Listen for results in the substream
|
||||
(async () => {
|
||||
for await (const event of substream) {
|
||||
console.log(`Event in substream: ${event.type}`);
|
||||
}
|
||||
})();
|
||||
|
||||
return resultEvent.with(`Querying: ${event.data}`);
|
||||
});
|
||||
|
||||
// Fetch handler
|
||||
workflow.handle([fetchEvent], (event) => {
|
||||
console.log(`Fetching data for: ${event.data}`);
|
||||
// Actual fetch logic would go here
|
||||
return resultEvent.with(`Results for: ${event.data}`);
|
||||
});
|
||||
```
|
||||
|
||||
## Advanced Validation and Type Safety
|
||||
|
||||
The `withValidation` middleware ensures your workflow connections are both type-safe and runtime-safe:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent, withValidation } from "llamaindex";
|
||||
|
||||
// Define events with explicit types
|
||||
const inputEvent = workflowEvent<string, "input">();
|
||||
const validateEvent = workflowEvent<string, "validate">();
|
||||
const processEvent = workflowEvent<string, "process">();
|
||||
const resultEvent = workflowEvent<string, "result">();
|
||||
const errorEvent = workflowEvent<Error, "error">({
|
||||
debugLabel: "errorEvent" // Add debug labels for better error messages
|
||||
});
|
||||
|
||||
// Define the allowed event flow paths
|
||||
const workflow = withValidation(
|
||||
createWorkflow(),
|
||||
[
|
||||
[[inputEvent], [validateEvent, errorEvent]], // inputEvent can lead to validateEvent or errorEvent
|
||||
[[validateEvent], [processEvent, errorEvent]], // validateEvent can lead to processEvent or errorEvent
|
||||
[[processEvent], [resultEvent, errorEvent]], // processEvent can lead to resultEvent or errorEvent
|
||||
[[errorEvent], [resultEvent]] // errorEvent can lead to resultEvent
|
||||
]
|
||||
);
|
||||
|
||||
// Now use strictHandle to get compile-time validation
|
||||
workflow.strictHandle([inputEvent], (sendEvent, event) => {
|
||||
try {
|
||||
if (!event.data || event.data.trim().length === 0) {
|
||||
throw new Error("Empty input");
|
||||
}
|
||||
// This is allowed by our validation rules
|
||||
sendEvent(validateEvent.with(event.data.trim()));
|
||||
|
||||
// This would cause a compile-time error:
|
||||
// sendEvent(resultEvent.with("Result")); // ❌ Not allowed by validation rules
|
||||
} catch (err) {
|
||||
// This is allowed by our validation rules
|
||||
sendEvent(errorEvent.with(err instanceof Error ? err : new Error(String(err))));
|
||||
}
|
||||
});
|
||||
|
||||
// The rest of the workflow with strict validation
|
||||
workflow.strictHandle([validateEvent], (sendEvent, event) => {
|
||||
// Validation logic here
|
||||
sendEvent(processEvent.with(event.data));
|
||||
});
|
||||
|
||||
workflow.strictHandle([processEvent], (sendEvent, event) => {
|
||||
// Processing logic here
|
||||
sendEvent(resultEvent.with(`Processed: ${event.data}`));
|
||||
});
|
||||
|
||||
workflow.strictHandle([errorEvent], (sendEvent, event) => {
|
||||
// Error handling logic here
|
||||
sendEvent(resultEvent.with(`Error handled: ${event.data.message}`));
|
||||
});
|
||||
```
|
||||
|
||||
## Creating Custom Middleware
|
||||
|
||||
You can create your own middleware to extend the workflow capabilities:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent } from "llamaindex";
|
||||
|
||||
// Create a logging middleware
|
||||
function withLogging(workflow) {
|
||||
const originalHandle = workflow.handle;
|
||||
|
||||
workflow.handle = function(eventTypes, handler) {
|
||||
return originalHandle.call(workflow, eventTypes, async function(...args) {
|
||||
const eventType = eventTypes.map(e => e.name || 'AnonymousEvent').join(',');
|
||||
console.log(`[${new Date().toISOString()}] Handling ${eventType}`);
|
||||
|
||||
try {
|
||||
const result = await handler(...args);
|
||||
console.log(`[${new Date().toISOString()}] Completed ${eventType}`);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error(`[${new Date().toISOString()}] Error in ${eventType}:`, error);
|
||||
throw error;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return workflow;
|
||||
}
|
||||
|
||||
// Create a retry middleware
|
||||
function withRetry(maxRetries = 3, workflow) {
|
||||
const originalHandle = workflow.handle;
|
||||
|
||||
workflow.handle = function(eventTypes, handler) {
|
||||
return originalHandle.call(workflow, eventTypes, async function(...args) {
|
||||
let lastError;
|
||||
|
||||
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
try {
|
||||
return await handler(...args);
|
||||
} catch (error) {
|
||||
lastError = error;
|
||||
console.warn(`Attempt ${attempt}/${maxRetries} failed:`, error);
|
||||
|
||||
if (attempt < maxRetries) {
|
||||
// Exponential backoff
|
||||
await new Promise(resolve =>
|
||||
setTimeout(resolve, Math.pow(2, attempt - 1) * 100)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw lastError;
|
||||
});
|
||||
};
|
||||
|
||||
return workflow;
|
||||
}
|
||||
|
||||
// Use the custom middleware
|
||||
const workflow = withRetry(3, withLogging(createWorkflow()));
|
||||
|
||||
// Define events
|
||||
const startEvent = workflowEvent<string>();
|
||||
const resultEvent = workflowEvent<string>();
|
||||
|
||||
// Add handlers
|
||||
workflow.handle([startEvent], (event) => {
|
||||
// This handler might fail but will be retried
|
||||
if (Math.random() < 0.7) {
|
||||
throw new Error("Random failure");
|
||||
}
|
||||
return resultEvent.with(`Processed: ${event.data}`);
|
||||
});
|
||||
```
|
||||
|
||||
## Integrating with External Systems
|
||||
|
||||
You can extend your workflows to integrate with external systems:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent } from "llamaindex";
|
||||
|
||||
// Define events
|
||||
const fetchEvent = workflowEvent<string>();
|
||||
const successEvent = workflowEvent<any>();
|
||||
const failureEvent = workflowEvent<Error>();
|
||||
|
||||
// Create workflow
|
||||
const workflow = createWorkflow();
|
||||
|
||||
// Handle external API calls with proper error handling
|
||||
workflow.handle([fetchEvent], async (event) => {
|
||||
const { signal } = getContext();
|
||||
|
||||
try {
|
||||
// Use AbortSignal for cancellation support
|
||||
const response = await fetch(event.data, { signal });
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return successEvent.with(data);
|
||||
} catch (error) {
|
||||
if (error.name === 'AbortError') {
|
||||
return failureEvent.with(new Error('Request was aborted'));
|
||||
}
|
||||
return failureEvent.with(error instanceof Error ? error : new Error(String(error)));
|
||||
}
|
||||
});
|
||||
|
||||
// Database integration example
|
||||
const dbQueryEvent = workflowEvent<{ collection: string; query: any }>();
|
||||
const dbResultEvent = workflowEvent<any[]>();
|
||||
|
||||
workflow.handle([dbQueryEvent], async (event) => {
|
||||
// Connect to database (pseudo-code)
|
||||
const db = await connectToDatabase();
|
||||
|
||||
try {
|
||||
const results = await db.collection(event.data.collection)
|
||||
.find(event.data.query)
|
||||
.toArray();
|
||||
|
||||
return dbResultEvent.with(results);
|
||||
} catch (error) {
|
||||
return failureEvent.with(error);
|
||||
} finally {
|
||||
await db.close();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Handling Complex Asynchronous Patterns
|
||||
|
||||
LlamaIndex workflows excel at managing complex asynchronous patterns:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent, until, collect } from "llamaindex";
|
||||
|
||||
// Events for an orchestration workflow
|
||||
const orchestrateEvent = workflowEvent<string[]>();
|
||||
const taskEvent = workflowEvent<string>();
|
||||
const progressEvent = workflowEvent<{ task: string; progress: number }>();
|
||||
const taskCompleteEvent = workflowEvent<string>();
|
||||
const aggregateEvent = workflowEvent<any>();
|
||||
|
||||
// Create workflow
|
||||
const workflow = createWorkflow();
|
||||
|
||||
// Orchestrator: distribute tasks and collect results
|
||||
workflow.handle([orchestrateEvent], async (event) => {
|
||||
const { sendEvent, stream } = getContext();
|
||||
const tasks = event.data;
|
||||
|
||||
// Start all tasks
|
||||
tasks.forEach(task => sendEvent(taskEvent.with(task)));
|
||||
|
||||
// Track progress
|
||||
let completed = 0;
|
||||
const results = {};
|
||||
|
||||
// Process task completion and progress events
|
||||
for await (const event of until(stream, () => completed === tasks.length)) {
|
||||
if (progressEvent.include(event)) {
|
||||
console.log(`Task ${event.data.task}: ${event.data.progress}%`);
|
||||
} else if (taskCompleteEvent.include(event)) {
|
||||
completed++;
|
||||
results[event.data] = `Completed ${event.data}`;
|
||||
console.log(`Completed ${completed}/${tasks.length} tasks`);
|
||||
}
|
||||
}
|
||||
|
||||
return aggregateEvent.with(results);
|
||||
});
|
||||
|
||||
// Task processor
|
||||
workflow.handle([taskEvent], async (event) => {
|
||||
const { sendEvent } = getContext();
|
||||
const task = event.data;
|
||||
|
||||
// Simulate task processing with progress updates
|
||||
for (let progress = 0; progress <= 100; progress += 20) {
|
||||
sendEvent(progressEvent.with({ task, progress }));
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
}
|
||||
|
||||
return taskCompleteEvent.with(task);
|
||||
});
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
Now that you've explored advanced event handling with workflows, you're ready to build sophisticated applications:
|
||||
|
||||
- [Integrating Workflows with other LlamaIndex Features](./llamaindex-integration.mdx)
|
||||
@@ -1,263 +0,0 @@
|
||||
---
|
||||
title: Basic Workflow Patterns
|
||||
description: Learn common patterns and techniques for building effective workflows
|
||||
---
|
||||
|
||||
This guide explores common patterns you can use to build more complex workflows with workflows.
|
||||
|
||||
## Fan-out (Parallelism)
|
||||
|
||||
One of the most powerful features of workflows is the ability to run tasks in parallel:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent, until, collect } from "llamaindex";
|
||||
|
||||
// Define events
|
||||
const startEvent = workflowEvent<string>();
|
||||
const processItemEvent = workflowEvent<number>();
|
||||
const resultEvent = workflowEvent<string>();
|
||||
const completeEvent = workflowEvent<string[]>();
|
||||
|
||||
// Create workflow
|
||||
const workflow = createWorkflow();
|
||||
|
||||
// Process start event: fan out to multiple processItemEvent events
|
||||
workflow.handle([startEvent], (start) => {
|
||||
const { sendEvent, stream } = getContext();
|
||||
|
||||
// Emit multiple events to be processed in parallel
|
||||
for (let i = 0; i < 10; i++) {
|
||||
sendEvent(processItemEvent.with(i));
|
||||
}
|
||||
|
||||
// Collect all resultEvents and emit a final completeEvent
|
||||
let condition = false;
|
||||
const results = collect(
|
||||
until(stream, () => condition)
|
||||
.filter((ev) => resultEvent.includes(ev))
|
||||
);
|
||||
|
||||
return completeEvent.with(results.map(event => event.data));
|
||||
});
|
||||
|
||||
// Process each item
|
||||
workflow.handle([processItemEvent], (event) => {
|
||||
// Process the item
|
||||
const processedValue = `Processed: ${event.data}`;
|
||||
|
||||
// If this is the last item, set the condition to stop collecting
|
||||
if (event.data === 9) {
|
||||
condition = true;
|
||||
}
|
||||
|
||||
return resultEvent.with(processedValue);
|
||||
});
|
||||
```
|
||||
|
||||
This pattern allows you to:
|
||||
1. Emit multiple events to be processed in parallel
|
||||
2. Collect results as they come in
|
||||
3. Complete once all parallel tasks are finished
|
||||
|
||||
## Conditional Branching
|
||||
|
||||
You can implement conditional logic in your workflows:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent } from "llamaindex";
|
||||
|
||||
const inputEvent = workflowEvent<number>();
|
||||
const evenNumberEvent = workflowEvent<string>();
|
||||
const oddNumberEvent = workflowEvent<string>();
|
||||
const resultEvent = workflowEvent<string>();
|
||||
|
||||
const workflow = createWorkflow();
|
||||
|
||||
// Branch based on whether the number is even or odd
|
||||
workflow.handle([inputEvent], (event) => {
|
||||
if (event.data % 2 === 0) {
|
||||
return evenNumberEvent.with(`${event.data} is even`);
|
||||
} else {
|
||||
return oddNumberEvent.with(`${event.data} is odd`);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle even numbers
|
||||
workflow.handle([evenNumberEvent], (event) => {
|
||||
return resultEvent.with(`Even result: ${event.data}`);
|
||||
});
|
||||
|
||||
// Handle odd numbers
|
||||
workflow.handle([oddNumberEvent], (event) => {
|
||||
return resultEvent.with(`Odd result: ${event.data}`);
|
||||
});
|
||||
```
|
||||
|
||||
## Using Middleware
|
||||
|
||||
LlamaIndex workflows provide middleware that can enhance your workflows:
|
||||
|
||||
### `withStore` Middleware
|
||||
|
||||
The `withStore` middleware adds a persistent store to your workflow context:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent, withStore } from "llamaindex";
|
||||
|
||||
const startEvent = workflowEvent<void>();
|
||||
const incrementEvent = workflowEvent<number>();
|
||||
const resultEvent = workflowEvent<number>();
|
||||
|
||||
// Create a workflow with store middleware
|
||||
const workflow = withStore(
|
||||
() => ({
|
||||
count: 0,
|
||||
history: [] as number[],
|
||||
}),
|
||||
createWorkflow()
|
||||
);
|
||||
|
||||
// Increment the counter
|
||||
workflow.handle([startEvent], () => {
|
||||
const store = workflow.getStore();
|
||||
store.count += 1;
|
||||
store.history.push(store.count);
|
||||
return incrementEvent.with(store.count);
|
||||
});
|
||||
|
||||
// Return the current count
|
||||
workflow.handle([incrementEvent], (event) => {
|
||||
const store = workflow.getStore();
|
||||
return resultEvent.with(store.count);
|
||||
});
|
||||
```
|
||||
|
||||
### `withValidation` Middleware
|
||||
|
||||
The `withValidation` middleware adds compile-time and runtime validation to your workflows:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent, withValidation } from "llamaindex";
|
||||
|
||||
const startEvent = workflowEvent<string, "start">();
|
||||
const processEvent = workflowEvent<number, "process">();
|
||||
const resultEvent = workflowEvent<string, "result">();
|
||||
const disallowedEvent = workflowEvent<void, "disallowed">();
|
||||
|
||||
// Create a workflow with validation middleware
|
||||
// Define allowed event paths
|
||||
const workflow = withValidation(
|
||||
createWorkflow(),
|
||||
[
|
||||
[[startEvent], [processEvent]], // startEvent can only lead to processEvent
|
||||
[[processEvent], [resultEvent]], // processEvent can only lead to resultEvent
|
||||
]
|
||||
);
|
||||
|
||||
// This will pass validation
|
||||
workflow.strictHandle([startEvent], (sendEvent, start) => {
|
||||
sendEvent(processEvent.with(123)); // ✅ This is allowed
|
||||
});
|
||||
|
||||
// This would fail at compile time and runtime
|
||||
workflow.strictHandle([startEvent], (sendEvent, start) => {
|
||||
// sendEvent(disallowedEvent.with()); // ❌ This would cause an error
|
||||
// sendEvent(resultEvent.with("result")); // ❌ This would also cause an error
|
||||
});
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
LlamaIndex workflows provide built-in mechanisms for handling errors:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent } from "llamaindex";
|
||||
|
||||
const startEvent = workflowEvent<string>();
|
||||
const processEvent = workflowEvent<number>();
|
||||
const errorEvent = workflowEvent<Error>();
|
||||
const resultEvent = workflowEvent<string>();
|
||||
|
||||
const workflow = createWorkflow();
|
||||
|
||||
workflow.handle([startEvent], (start) => {
|
||||
try {
|
||||
const num = Number.parseInt(start.data, 10);
|
||||
if (isNaN(num)) {
|
||||
throw new Error("Invalid number");
|
||||
}
|
||||
return processEvent.with(num);
|
||||
} catch (err) {
|
||||
return errorEvent.with(err instanceof Error ? err : new Error(String(err)));
|
||||
}
|
||||
});
|
||||
|
||||
workflow.handle([processEvent], (event) => {
|
||||
return resultEvent.with(`Result: ${event.data * 2}`);
|
||||
});
|
||||
|
||||
workflow.handle([errorEvent], (event) => {
|
||||
return resultEvent.with(`Error: ${event.data.message}`);
|
||||
});
|
||||
```
|
||||
|
||||
You can also use the signal in `getContext()` to handle errors:
|
||||
|
||||
```ts
|
||||
workflow.handle([processEvent], () => {
|
||||
const { signal } = getContext();
|
||||
|
||||
signal.onabort = () => {
|
||||
console.error("Process aborted:", signal.reason);
|
||||
// Clean up resources
|
||||
};
|
||||
|
||||
// Your processing logic here
|
||||
});
|
||||
```
|
||||
|
||||
## Connecting with Server Endpoints
|
||||
|
||||
Workflow can be used as middleware in server frameworks like Express, Hono, or Fastify:
|
||||
|
||||
```ts
|
||||
import { Hono } from "hono";
|
||||
import { serve } from "@hono/node-server";
|
||||
import { createWorkflow, workflowEvent, createHonoHandler } from "llamaindex";
|
||||
|
||||
// Define events
|
||||
const queryEvent = workflowEvent<string>();
|
||||
const responseEvent = workflowEvent<string>();
|
||||
|
||||
// Create workflow
|
||||
const workflow = createWorkflow();
|
||||
|
||||
workflow.handle([queryEvent], (event) => {
|
||||
const response = `Processed: ${event.data}`;
|
||||
return responseEvent.with(response);
|
||||
});
|
||||
|
||||
// Create Hono app
|
||||
const app = new Hono();
|
||||
|
||||
// Set up workflow endpoint
|
||||
app.post(
|
||||
"/workflow",
|
||||
createHonoHandler(
|
||||
workflow,
|
||||
async (ctx) => queryEvent.with(await ctx.req.text()),
|
||||
responseEvent
|
||||
)
|
||||
);
|
||||
|
||||
// Start server
|
||||
serve(app, ({ port }) => {
|
||||
console.log(`Server started at http://localhost:${port}`);
|
||||
});
|
||||
```
|
||||
|
||||
## Next Steps
|
||||
|
||||
Now that you've learned about basic workflow patterns, explore more advanced topics:
|
||||
- [Streaming with Workflows](./streaming.mdx)
|
||||
- [Advanced Event Handling](./advanced-events.mdx)
|
||||
-234
@@ -1,234 +0,0 @@
|
||||
---
|
||||
title: Inputs / Outputs (Outdated)
|
||||
description: This page has been replaced with newer documentation
|
||||
---
|
||||
|
||||
# ⚠️ Outdated Documentation
|
||||
|
||||
This documentation is for an older version of the workflow API. Please refer to the new llama-flow documentation:
|
||||
|
||||
- [Getting Started with llama-flow](./index.mdx)
|
||||
- [Basic Workflow Patterns](./basic-workflow.mdx)
|
||||
- [Advanced Event Handling](./advanced-events.mdx)
|
||||
|
||||
The new API provides a more lightweight and flexible approach to building workflows.
|
||||
|
||||
Inputs and outputs are the way to communicate between steps in a workflow. In the previous example,
|
||||
we used `StartEvent` and `StopEvent` to communicate between steps. However, you can use any type of event to communicate between steps.
|
||||
|
||||
## Multiple inputs
|
||||
|
||||
You can define multiple inputs for a step.
|
||||
|
||||
In the following example, we define a complex workflow with multiple inputs and outputs.
|
||||
|
||||
```ts twoslash
|
||||
import { Workflow, StartEvent, StopEvent, WorkflowEvent } from '@llamaindex/workflow';
|
||||
|
||||
class AEvent extends WorkflowEvent<string> {
|
||||
constructor(data: string) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
class BEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
class ResultEvent extends WorkflowEvent<string> {
|
||||
constructor(data: string) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
First, let's define the events that we will use in the workflow.
|
||||
|
||||
```ts twoslash
|
||||
import { Workflow, StartEvent, StopEvent, WorkflowEvent } from '@llamaindex/workflow';
|
||||
|
||||
class AEvent extends WorkflowEvent<string> {
|
||||
constructor(data: string) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
class BEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
class ResultEvent extends WorkflowEvent<string> {
|
||||
constructor(data: string) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
const workflow = new Workflow<never, string, string>();
|
||||
|
||||
workflow.addStep({
|
||||
inputs: [StartEvent<string>],
|
||||
outputs: [StopEvent<string>]
|
||||
}, async (
|
||||
context,
|
||||
startEvent
|
||||
) => {
|
||||
const input = startEvent.data;
|
||||
const aEvent = await context.requireEvent(AEvent);
|
||||
const bEvent = await context.requireEvent(BEvent);
|
||||
const a = aEvent.data;
|
||||
const b = bEvent.data;
|
||||
return new StopEvent(`Hello, ${input}! A: ${a}, B: ${b}`);
|
||||
});
|
||||
|
||||
// ---cut---
|
||||
workflow.addStep({
|
||||
inputs: [AEvent, BEvent],
|
||||
outputs: [ResultEvent]
|
||||
}, async (
|
||||
context,
|
||||
aEvent,
|
||||
bEvent
|
||||
) => {
|
||||
const a = aEvent.data;
|
||||
const b = bEvent.data;
|
||||
return new ResultEvent(`A: ${a}, B: ${b}`);
|
||||
});
|
||||
```
|
||||
|
||||
This step means that it requires two events: `AEvent` and `BEvent`. It will return a `ResultEvent` with the data `A: ${a}, B: ${b}`.
|
||||
|
||||
## A or B input
|
||||
|
||||
If we want to have a step that can accept either `AEvent` or `BEvent`, we can define the step like this:
|
||||
|
||||
```ts twoslash
|
||||
import { Workflow, StartEvent, StopEvent, WorkflowEvent } from '@llamaindex/workflow';
|
||||
|
||||
class AEvent extends WorkflowEvent<string> {
|
||||
constructor(data: string) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
class BEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
class ResultEvent extends WorkflowEvent<string> {
|
||||
constructor(data: string) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
const workflow = new Workflow<never, string, string>();
|
||||
|
||||
workflow.addStep({
|
||||
inputs: [StartEvent<string>],
|
||||
outputs: [StopEvent<string>]
|
||||
}, async (
|
||||
context,
|
||||
startEvent
|
||||
) => {
|
||||
const input = startEvent.data;
|
||||
const aEvent = await context.requireEvent(AEvent);
|
||||
const bEvent = await context.requireEvent(BEvent);
|
||||
const a = aEvent.data;
|
||||
const b = bEvent.data;
|
||||
return new StopEvent(`Hello, ${input}! A: ${a}, B: ${b}`);
|
||||
});
|
||||
|
||||
// ---cut---
|
||||
workflow.addStep({
|
||||
inputs: [WorkflowEvent.or(AEvent, BEvent)],
|
||||
outputs: [ResultEvent]
|
||||
}, async (
|
||||
context,
|
||||
aOrBEvent
|
||||
) => {
|
||||
if (aOrBEvent instanceof AEvent) {
|
||||
// ^?
|
||||
|
||||
|
||||
const a = aOrBEvent.data;
|
||||
// ^?
|
||||
|
||||
|
||||
return new ResultEvent(`A: ${a}`);
|
||||
} else {
|
||||
const b = aOrBEvent.data;
|
||||
// ^?
|
||||
|
||||
|
||||
return new ResultEvent(`B: ${b}`);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
This step means that it requires either `AEvent` or `BEvent`. It will return a `ResultEvent` with the data `A: ${a}` or `B: ${b}`.
|
||||
|
||||
You can still combine the logic with `context.requireEvent` to get the data from the event.
|
||||
|
||||
<Accordions>
|
||||
<Accordion title="Under the hood">
|
||||
We use JavaScript Inheritance and the prototype chain to implement the `or` logic.
|
||||
The `or` method creates a new class that extends the two classes that you pass to it.
|
||||
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain"
|
||||
>
|
||||
MDN - Inheritance and the prototype chain
|
||||
</a>
|
||||
</Accordion>
|
||||
</Accordions>
|
||||
|
||||
## Multiple outputs
|
||||
|
||||
You can define multiple outputs for a step.
|
||||
|
||||
```ts twoslash
|
||||
import { Workflow, StartEvent, StopEvent, WorkflowEvent } from '@llamaindex/workflow';
|
||||
|
||||
class AEvent extends WorkflowEvent<string> {
|
||||
constructor(data: string) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
class BEvent extends WorkflowEvent<number> {
|
||||
constructor(data: number) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
class ResultEvent extends WorkflowEvent<string> {
|
||||
constructor(data: string) {
|
||||
super(data);
|
||||
}
|
||||
}
|
||||
|
||||
const workflow = new Workflow<never, string, string>();
|
||||
// ---cut---
|
||||
workflow.addStep({
|
||||
inputs: [StartEvent<string>],
|
||||
outputs: [AEvent, BEvent]
|
||||
}, async (
|
||||
context,
|
||||
startEvent
|
||||
) => {
|
||||
const input = startEvent.data;
|
||||
if (Math.random() > 0.5) {
|
||||
return new AEvent(`Hello, ${input}!`);
|
||||
} else {
|
||||
return new BEvent(42);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
This step will return either an `AEvent` or a `BEvent` based on a random number.
|
||||
@@ -1,111 +0,0 @@
|
||||
---
|
||||
title: Getting Started with Workflows
|
||||
description: Learn how to use LlamaIndex's lightweight workflow engine for TypeScript
|
||||
---
|
||||
|
||||
Workflows are a simple and lightweight engine for TypeScript. Built with ❤️ by LlamaIndex.
|
||||
|
||||
- Minimal core API (\<\=2kb)
|
||||
- 100% Type safe
|
||||
- Event-driven, stream oriented programming
|
||||
- Support for multiple JS runtimes/frameworks
|
||||
|
||||
## Installation
|
||||
|
||||
It's directly included with the `llamaindex` package:
|
||||
|
||||
```shell
|
||||
npm i llamaindex
|
||||
```
|
||||
|
||||
But can also be installed separately:
|
||||
|
||||
```shell
|
||||
npm i @llama-flow/core
|
||||
|
||||
# or with yarn
|
||||
yarn add @llama-flow/core
|
||||
|
||||
# or with pnpm
|
||||
pnpm add @llama-flow/core
|
||||
```
|
||||
|
||||
## Key Concepts
|
||||
|
||||
- **Events**: Data carriers that flow through the workflow
|
||||
- **Handlers**: Functions that process events and emit new events
|
||||
- **Workflow**: Connects events and handlers together
|
||||
- **Context**: Runtime environment for a workflow execution
|
||||
|
||||
## Basic Usage
|
||||
|
||||
Let's build a simple workflow that processes a text input:
|
||||
|
||||
### 1. Define events
|
||||
|
||||
First, we need to define the events that will flow through our workflow:
|
||||
|
||||
```ts
|
||||
import { workflowEvent } from "llamaindex";
|
||||
|
||||
// Define input and output events
|
||||
const startEvent = workflowEvent<string>(); // Takes a string input
|
||||
const convertEvent = workflowEvent<Number>(); // Intermediate event
|
||||
const stopEvent = workflowEvent<1 | -1>(); // Final output event, returns 1 or -1
|
||||
```
|
||||
|
||||
### 2. Create a workflow and connect events
|
||||
|
||||
Next, we'll create our workflow and define how events are processed:
|
||||
|
||||
```ts
|
||||
import { createWorkflow } from "llamaindex";
|
||||
|
||||
const workflow = createWorkflow();
|
||||
|
||||
// Handle the start event: convert the string to a number
|
||||
workflow.handle([startEvent], (start) => {
|
||||
return convertEvent.with(Number.parseInt(start.data, 10));
|
||||
});
|
||||
|
||||
// Handle the convert event: determine if number is positive or negative
|
||||
workflow.handle([convertEvent], (convert) => {
|
||||
return stopEvent.with(convert.data > 0 ? 1 : -1);
|
||||
});
|
||||
```
|
||||
|
||||
### 3. Run the workflow
|
||||
|
||||
Finally, we can execute our workflow:
|
||||
|
||||
```ts
|
||||
// Create a workflow context and send the initial event
|
||||
const { stream, sendEvent } = workflow.createContext();
|
||||
sendEvent(startEvent.with("42"));
|
||||
|
||||
// Process the stream to get the result
|
||||
import { pipeline } from "node:stream/promises";
|
||||
|
||||
const result = await pipeline(stream, async function (source) {
|
||||
for await (const event of source) {
|
||||
if (stopEvent.include(event)) {
|
||||
return `Result: ${event.data === 1 ? 'positive' : 'negative'}`;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log(result); // "Result: positive"
|
||||
```
|
||||
|
||||
Or using the stream utilities:
|
||||
|
||||
```ts
|
||||
import { collect, until } from "llamaindex";
|
||||
|
||||
// Collect all events until we get a stopEvent
|
||||
const allEvents = await collect(until(stream, stopEvent));
|
||||
const finalEvent = allEvents[allEvents.length - 1];
|
||||
console.log(`Result: ${finalEvent.data === 1 ? 'positive' : 'negative'}`);
|
||||
```
|
||||
|
||||
Ready to learn more? Check out our [detailed examples](./basic-workflow.mdx) to see llama-flow in action!
|
||||
@@ -1,288 +0,0 @@
|
||||
---
|
||||
title: Integrating with LlamaIndex
|
||||
description: Build AI applications by combining Workflows with other LlamaIndex features
|
||||
---
|
||||
|
||||
This guide demonstrates how to combine the power of the workflow engine with LlamaIndex's retrieval and reasoning capabilities to build sophisticated AI applications.
|
||||
|
||||
## Basic RAG Workflow
|
||||
|
||||
Let's build a simple Retrieval-Augmented Generation (RAG) workflow:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent } from "llamaindex";
|
||||
import { Document, serviceContextFromDefaults, VectorStoreIndex } from "llamaindex";
|
||||
import { OpenAI, OpenAIEmbedding } from "@llamaindex/openai";
|
||||
import { Settings } from "@llamaindex/core/global"
|
||||
|
||||
// Define events
|
||||
const queryEvent = workflowEvent<string>();
|
||||
const retrieveEvent = workflowEvent<{ query: string; documents: Document[] }>();
|
||||
const generateEvent = workflowEvent<{ query: string; context: string }>();
|
||||
const responseEvent = workflowEvent<string>();
|
||||
|
||||
// Create workflow
|
||||
const workflow = createWorkflow();
|
||||
|
||||
// Set default global llm
|
||||
Settings.llm = new OpenAI({
|
||||
model: "gpt-4.1-mini",
|
||||
temperature: 0.2
|
||||
});
|
||||
|
||||
// Set the default global embedModel
|
||||
Settings.embedModel = new OpenAIEmbedding({
|
||||
model: "text-embedding-3-small",
|
||||
});
|
||||
|
||||
// Sample documents
|
||||
const documents = [
|
||||
new Document({
|
||||
text: "LlamaIndex is a data framework for LLM applications to ingest, structure, and access private or domain-specific data.",
|
||||
}),
|
||||
new Document({
|
||||
text: "LlamaIndex workflows are a lightweight workflow engine for TypeScript, designed to create event-driven processes.",
|
||||
}),
|
||||
];
|
||||
|
||||
// Create vector store index
|
||||
const index = await VectorStoreIndex.fromDocuments(documents);
|
||||
|
||||
// Handle query: Retrieve relevant documents
|
||||
workflow.handle([queryEvent], (event) => {
|
||||
const query = event.data;
|
||||
console.log(`Processing query: ${query}`);
|
||||
|
||||
// Retrieve relevant documents
|
||||
const retriever = index.asRetriever();
|
||||
const nodes = retriever.retrieve(query);
|
||||
|
||||
return retrieveEvent.with({
|
||||
query,
|
||||
documents: nodes.map(node => node.node),
|
||||
});
|
||||
});
|
||||
|
||||
// Handle retrieval results: Generate response
|
||||
workflow.handle([retrieveEvent], async (event) => {
|
||||
const { query, documents } = event.data;
|
||||
|
||||
// Combine document content as context
|
||||
const context = documents.map(doc => doc.text).join('\n\n');
|
||||
|
||||
return generateEvent.with({ query, context });
|
||||
});
|
||||
|
||||
// Handle generation: Produce final response
|
||||
workflow.handle([generateEvent], async (event) => {
|
||||
const { query, context } = event.data;
|
||||
|
||||
// Create a prompt with the context and query
|
||||
const prompt = `
|
||||
Context information:
|
||||
${context}
|
||||
|
||||
Based on the context information and no other knowledge, answer the following query:
|
||||
${query}
|
||||
`;
|
||||
|
||||
// Generate response with LLM
|
||||
const response = await Settings.llm.complete({ prompt });
|
||||
|
||||
return responseEvent.with(response.text);
|
||||
});
|
||||
|
||||
// Execute the workflow
|
||||
const { stream, sendEvent } = workflow.createContext();
|
||||
sendEvent(queryEvent.with("What is LlamaIndex?"));
|
||||
|
||||
// Process the stream
|
||||
for await (const event of stream) {
|
||||
if (responseEvent.include(event)) {
|
||||
console.log("Final response:", event.data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Building a Chat Application
|
||||
|
||||
Let's create a more complex chat application that maintains conversation history:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent, withStore } from "llamaindex";
|
||||
import { OpenAI, OpenAIEmbedding } from "@llamaindex/openai";
|
||||
import { Document, serviceContextFromDefaults, VectorStoreIndex } from "llamaindex";
|
||||
import { Settings } from "@llamaindex/core/global"
|
||||
|
||||
// Set default global llm
|
||||
Settings.llm = new OpenAI({
|
||||
model: "gpt-4.1-mini",
|
||||
temperature: 0.2
|
||||
});
|
||||
|
||||
// Set the default global embedModel
|
||||
Settings.embedModel = new OpenAIEmbedding({
|
||||
model: "text-embedding-3-small",
|
||||
});
|
||||
|
||||
// Define store type
|
||||
type ChatStore = {
|
||||
history: Array<{ role: string; content: string }>;
|
||||
documents: Document[];
|
||||
index: VectorStoreIndex | null;
|
||||
};
|
||||
|
||||
// Define events
|
||||
const initEvent = workflowEvent<Document[]>();
|
||||
const indexCreatedEvent = workflowEvent<VectorStoreIndex>();
|
||||
const userMessageEvent = workflowEvent<string>();
|
||||
const retrievalEvent = workflowEvent<{ query: string; nodes: any[] }>();
|
||||
const responseEvent = workflowEvent<{ message: { content: string } }>();
|
||||
|
||||
// Create workflow with store
|
||||
const workflow = withStore<ChatStore>(
|
||||
() => ({
|
||||
history: [],
|
||||
documents: [],
|
||||
index: null,
|
||||
}),
|
||||
createWorkflow()
|
||||
);
|
||||
|
||||
// Initialize the chat context
|
||||
workflow.handle([initEvent], async (event) => {
|
||||
const store = workflow.getStore();
|
||||
store.documents = event.data;
|
||||
|
||||
// Create index from documents
|
||||
const index = await VectorStoreIndex.fromDocuments(store.documents);
|
||||
|
||||
store.index = index;
|
||||
return indexCreatedEvent.with(index);
|
||||
});
|
||||
|
||||
// Process user message
|
||||
workflow.handle([userMessageEvent], (event) => {
|
||||
const userMessage = event.data;
|
||||
const store = workflow.getStore();
|
||||
|
||||
// Add user message to history
|
||||
store.history.push({
|
||||
role: "user",
|
||||
content: userMessage,
|
||||
});
|
||||
|
||||
if (!store.index) {
|
||||
throw new Error("Index not initialized yet");
|
||||
}
|
||||
|
||||
// Retrieve relevant context
|
||||
const retriever = store.index.asRetriever();
|
||||
const nodes = retriever.retrieve(userMessage);
|
||||
|
||||
return retrievalEvent.with({
|
||||
query: userMessage,
|
||||
nodes,
|
||||
});
|
||||
});
|
||||
|
||||
// Generate response from retrieval results
|
||||
workflow.handle([retrievalEvent], async (event) => {
|
||||
const { query, nodes } = event.data;
|
||||
const store = workflow.getStore();
|
||||
|
||||
// Context from retrieved nodes
|
||||
const context = nodes.map(node => node.node.text).join('\n\n');
|
||||
|
||||
// Create the system message with context
|
||||
const systemMessage = {
|
||||
role: "system",
|
||||
content: `You are a helpful assistant. Use the following information to answer the user's question:
|
||||
|
||||
${context}
|
||||
|
||||
Only use the information provided above to answer. If you don't know, say so.`,
|
||||
};
|
||||
|
||||
// Create full conversation history for the chat
|
||||
const messages = [
|
||||
systemMessage,
|
||||
...store.history,
|
||||
];
|
||||
|
||||
// Generate response
|
||||
const response = await Settings.llm.chat({
|
||||
messages,
|
||||
});
|
||||
|
||||
// Add assistant response to history
|
||||
store.history.push({
|
||||
role: "assistant",
|
||||
content: response.message.content,
|
||||
});
|
||||
|
||||
return responseEvent.with(response);
|
||||
});
|
||||
|
||||
// Example usage
|
||||
async function runChat() {
|
||||
// Sample documents
|
||||
const documents = [
|
||||
new Document({
|
||||
text: "LlamaIndex is a data framework for LLM applications to ingest, structure, and access private or domain-specific data.",
|
||||
}),
|
||||
new Document({
|
||||
text: "LlamaIndex Workflows are a lightweight workflow engine for TypeScript, designed to create event-driven processes.",
|
||||
}),
|
||||
];
|
||||
|
||||
// Initialize the chat
|
||||
const { stream, sendEvent } = workflow.createContext();
|
||||
sendEvent(initEvent.with(documents));
|
||||
|
||||
// Wait for index creation
|
||||
for await (const event of stream) {
|
||||
if (indexCreatedEvent.include(event)) {
|
||||
console.log("Index created successfully");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Start conversation
|
||||
async function sendUserMessage(message: string) {
|
||||
sendEvent(userMessageEvent.with(message));
|
||||
|
||||
for await (const event of stream) {
|
||||
if (responseEvent.include(event)) {
|
||||
console.log("Assistant:", event.data.message.content);
|
||||
return event.data.message.content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await sendUserMessage("What is LlamaIndex?");
|
||||
await sendUserMessage("Can you tell me about LlamaIndex workflows?");
|
||||
await sendUserMessage("How might these two technologies work together?");
|
||||
}
|
||||
|
||||
runChat();
|
||||
```
|
||||
|
||||
## Building an Tool Calling Agent
|
||||
|
||||
[TODO]
|
||||
|
||||
## Conclusion
|
||||
|
||||
By combining the lightweight, event-driven workflow engine with LlamaIndex's powerful document indexing and querying capabilities, you can build sophisticated AI applications with clean, maintainable code.
|
||||
|
||||
The event-driven architecture allows you to:
|
||||
|
||||
1. Break complex processes into manageable steps
|
||||
2. Create reusable components for common AI workflows
|
||||
3. Easily debug and monitor each phase of execution
|
||||
4. Scale your applications by isolating resource-intensive steps
|
||||
5. Build more resilient systems with better error handling
|
||||
|
||||
As you build your own applications, consider how the patterns shown here can be adapted to your specific use cases.
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"title": "Workflows",
|
||||
"description": "Event-driven workflow engine for TypeScript",
|
||||
"defaultOpen": false,
|
||||
"pages": [
|
||||
"index",
|
||||
"basic-workflow",
|
||||
"streaming",
|
||||
"advanced-events",
|
||||
"llamaindex-integration"
|
||||
]
|
||||
}
|
||||
@@ -1,371 +0,0 @@
|
||||
---
|
||||
title: Streaming with Workflows
|
||||
description: Learn how to build streaming workflows
|
||||
---
|
||||
|
||||
LlamaIndex workflows are designed from the ground up to work with streaming data. The streaming capabilities make it perfect for:
|
||||
|
||||
- Building real-time applications
|
||||
- Handling large datasets incrementally
|
||||
- Creating responsive UIs that update as data becomes available
|
||||
- Implementing long-running tasks with partial results
|
||||
|
||||
## Basic Streaming
|
||||
|
||||
Every workflow context provides a stream of events:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent } from "llamaindex";
|
||||
|
||||
// Define events
|
||||
const startEvent = workflowEvent<string>();
|
||||
const intermediateEvent = workflowEvent<string>();
|
||||
const resultEvent = workflowEvent<string>();
|
||||
|
||||
// Create workflow
|
||||
const workflow = createWorkflow();
|
||||
|
||||
workflow.handle([startEvent], (event) => {
|
||||
const { sendEvent } = getContext();
|
||||
|
||||
// Emit multiple intermediate events
|
||||
for (let i = 0; i < 5; i++) {
|
||||
sendEvent(intermediateEvent.with(`Progress: ${i * 20}%`));
|
||||
}
|
||||
|
||||
return resultEvent.with("Completed");
|
||||
});
|
||||
|
||||
// Run the workflow
|
||||
const { stream, sendEvent } = workflow.createContext();
|
||||
sendEvent(startEvent.with("Start processing"));
|
||||
|
||||
// Process events as they arrive
|
||||
for await (const event of stream) {
|
||||
if (intermediateEvent.include(event)) {
|
||||
console.log(event.data); // Show progress updates
|
||||
} else if (resultEvent.include(event)) {
|
||||
console.log("Final result:", event.data);
|
||||
break; // Exit the loop when done
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Using the Stream Utilities
|
||||
|
||||
Workflows provide utility functions to make working with streams easier:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent, until, collect } from "llamaindex";
|
||||
|
||||
const startEvent = workflowEvent<void>();
|
||||
const progressEvent = workflowEvent<number>();
|
||||
const resultEvent = workflowEvent<string>();
|
||||
|
||||
const workflow = createWorkflow();
|
||||
|
||||
workflow.handle([startEvent], () => {
|
||||
const { sendEvent } = getContext();
|
||||
|
||||
// Emit progress events
|
||||
for (let i = 0; i < 100; i += 10) {
|
||||
sendEvent(progressEvent.with(i));
|
||||
}
|
||||
|
||||
return resultEvent.with("Complete");
|
||||
});
|
||||
|
||||
// Run the workflow and collect events until a condition is met
|
||||
const { stream, sendEvent } = workflow.createContext();
|
||||
sendEvent(startEvent.with());
|
||||
|
||||
// Collect all events until resultEvent is encountered
|
||||
const events = await collect(until(stream, (event) => resultEvent.include(event)));
|
||||
|
||||
// Filter only progress events
|
||||
const progressEvents = events.filter(event => progressEvent.include(event));
|
||||
console.log(`Received ${progressEvents.length} progress updates`);
|
||||
```
|
||||
|
||||
## Conditional Stream Processing
|
||||
|
||||
You can conditionally process events and even stop the stream early:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent } from "llamaindex";
|
||||
|
||||
const startEvent = workflowEvent<number>();
|
||||
const dataEvent = workflowEvent<number>();
|
||||
const thresholdEvent = workflowEvent<void>();
|
||||
const resultEvent = workflowEvent<number[]>();
|
||||
|
||||
const workflow = createWorkflow();
|
||||
|
||||
workflow.handle([startEvent], (event) => {
|
||||
const { sendEvent } = getContext();
|
||||
const max = event.data;
|
||||
|
||||
for (let i = 0; i < max; i++) {
|
||||
sendEvent(dataEvent.with(i));
|
||||
if (i >= 10) {
|
||||
// Signal that we've hit a threshold
|
||||
sendEvent(thresholdEvent.with());
|
||||
}
|
||||
}
|
||||
|
||||
return resultEvent.with(Array.from({ length: max }, (_, i) => i));
|
||||
});
|
||||
|
||||
// Run the workflow
|
||||
const { stream, sendEvent } = workflow.createContext();
|
||||
sendEvent(startEvent.with(100)); // Generate 100 numbers
|
||||
|
||||
const results = [];
|
||||
let hitThreshold = false;
|
||||
|
||||
// Process the stream
|
||||
for await (const event of stream) {
|
||||
if (dataEvent.include(event)) {
|
||||
results.push(event.data);
|
||||
} else if (thresholdEvent.include(event)) {
|
||||
hitThreshold = true;
|
||||
break; // Stop processing early
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`Collected ${results.length} items before ${hitThreshold ? 'hitting threshold' : 'completion'}`);
|
||||
```
|
||||
|
||||
## Integration with UI Frameworks
|
||||
|
||||
Workflow streams can be easily integrated with UI frameworks like React to create responsive interfaces:
|
||||
|
||||
```tsx
|
||||
// In a React component
|
||||
import { useEffect, useState } from 'react';
|
||||
import { createWorkflow, workflowEvent } from "llamaindex";
|
||||
|
||||
function StreamingComponent() {
|
||||
const [updates, setUpdates] = useState([]);
|
||||
const [isComplete, setIsComplete] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
// Set up workflow
|
||||
const startEvent = workflowEvent<void>();
|
||||
const updateEvent = workflowEvent<string>();
|
||||
const completeEvent = workflowEvent<void>();
|
||||
|
||||
const workflow = createWorkflow();
|
||||
|
||||
workflow.handle([startEvent], () => {
|
||||
const { sendEvent } = getContext();
|
||||
|
||||
// Simulate async updates
|
||||
const intervals = [
|
||||
setTimeout(() => sendEvent(updateEvent.with("First update")), 500),
|
||||
setTimeout(() => sendEvent(updateEvent.with("Second update")), 1000),
|
||||
setTimeout(() => sendEvent(updateEvent.with("Final update")), 1500),
|
||||
setTimeout(() => sendEvent(completeEvent.with()), 2000)
|
||||
];
|
||||
|
||||
// Cleanup function
|
||||
getContext().signal.onabort = () => {
|
||||
intervals.forEach(clearTimeout);
|
||||
};
|
||||
});
|
||||
|
||||
// Run the workflow
|
||||
const { stream, sendEvent } = workflow.createContext();
|
||||
sendEvent(startEvent.with());
|
||||
|
||||
// Process events
|
||||
const processEvents = async () => {
|
||||
for await (const event of stream) {
|
||||
if (updateEvent.include(event)) {
|
||||
setUpdates(prev => [...prev, event.data]);
|
||||
} else if (completeEvent.include(event)) {
|
||||
setIsComplete(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
processEvents();
|
||||
|
||||
// Cleanup
|
||||
return () => {
|
||||
// The workflow will be aborted when the component unmounts
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>Streaming Updates</h2>
|
||||
<ul>
|
||||
{updates.map((update, i) => (
|
||||
<li key={i}>{update}</li>
|
||||
))}
|
||||
</ul>
|
||||
{isComplete && <div>Process complete!</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## Server-Sent Events (SSE)
|
||||
|
||||
Workflows are also suitable for implementing Server-Sent Events:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent } from "llamaindex";
|
||||
import express from 'express';
|
||||
|
||||
// Define events
|
||||
const startEvent = workflowEvent<void>();
|
||||
const dataEvent = workflowEvent<string>();
|
||||
|
||||
// Create workflow
|
||||
const workflow = createWorkflow();
|
||||
|
||||
workflow.handle([startEvent], () => {
|
||||
const { sendEvent } = getContext();
|
||||
|
||||
// Send periodic updates
|
||||
const intervals = [
|
||||
setInterval(() => {
|
||||
sendEvent(dataEvent.with(`Update: ${new Date().toISOString()}`));
|
||||
}, 1000)
|
||||
];
|
||||
|
||||
// Cleanup
|
||||
getContext().signal.onabort = () => {
|
||||
intervals.forEach(clearInterval);
|
||||
};
|
||||
});
|
||||
|
||||
// Set up Express server
|
||||
const app = express();
|
||||
|
||||
app.get('/events', (req, res) => {
|
||||
// Set headers for SSE
|
||||
res.setHeader('Content-Type', 'text/event-stream');
|
||||
res.setHeader('Cache-Control', 'no-cache');
|
||||
res.setHeader('Connection', 'keep-alive');
|
||||
|
||||
// Run workflow
|
||||
const { stream, sendEvent } = workflow.createContext();
|
||||
sendEvent(startEvent.with());
|
||||
|
||||
// Handle client disconnect
|
||||
req.on('close', () => {
|
||||
// This will trigger the abort signal in the workflow
|
||||
});
|
||||
|
||||
// Process and send events
|
||||
(async () => {
|
||||
for await (const event of stream) {
|
||||
if (dataEvent.include(event)) {
|
||||
res.write(`data: ${JSON.stringify(event.data)}\n\n`);
|
||||
}
|
||||
}
|
||||
})();
|
||||
});
|
||||
|
||||
app.listen(3000, () => {
|
||||
console.log('SSE server running on port 3000');
|
||||
});
|
||||
```
|
||||
|
||||
## Advanced Techniques
|
||||
|
||||
### Flow Control
|
||||
|
||||
You can implement flow control with backpressure in your streaming workflows:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent } from "llamaindex";
|
||||
|
||||
// This example shows how to process items with controlled concurrency
|
||||
const processItems = async (items, maxConcurrency = 3) => {
|
||||
const startEvent = workflowEvent<string[]>();
|
||||
const processItemEvent = workflowEvent<string>();
|
||||
const itemProcessedEvent = workflowEvent<string>();
|
||||
const resultEvent = workflowEvent<string[]>();
|
||||
|
||||
const workflow = createWorkflow();
|
||||
|
||||
// Handler to process individual items
|
||||
workflow.handle([processItemEvent], async (event) => {
|
||||
// Simulate processing time
|
||||
await new Promise(resolve => setTimeout(resolve, 100));
|
||||
return itemProcessedEvent.with(`Processed: ${event.data}`);
|
||||
});
|
||||
|
||||
// Main workflow handler
|
||||
workflow.handle([startEvent], async (event) => {
|
||||
const { sendEvent, stream } = getContext();
|
||||
const results = [];
|
||||
|
||||
// Process with controlled concurrency
|
||||
const items = event.data;
|
||||
let inProgress = 0;
|
||||
let itemIndex = 0;
|
||||
|
||||
// Start initial batch of items
|
||||
while (inProgress < maxConcurrency && itemIndex < items.length) {
|
||||
sendEvent(processItemEvent.with(items[itemIndex++]));
|
||||
inProgress++;
|
||||
}
|
||||
|
||||
// Process items and collect results
|
||||
for await (const event of stream) {
|
||||
if (itemProcessedEvent.include(event)) {
|
||||
results.push(event.data);
|
||||
inProgress--;
|
||||
|
||||
// Add next item if available
|
||||
if (itemIndex < items.length) {
|
||||
sendEvent(processItemEvent.with(items[itemIndex++]));
|
||||
inProgress++;
|
||||
} else if (inProgress === 0) {
|
||||
// All done
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resultEvent.with(results);
|
||||
});
|
||||
|
||||
// Run the workflow
|
||||
const { stream, sendEvent } = workflow.createContext();
|
||||
sendEvent(startEvent.with(items));
|
||||
|
||||
// Wait for final result
|
||||
for await (const event of stream) {
|
||||
if (resultEvent.include(event)) {
|
||||
return event.data;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
};
|
||||
|
||||
// Usage
|
||||
const results = await processItems(
|
||||
Array.from({ length: 20 }, (_, i) => `Item ${i}`)
|
||||
);
|
||||
console.log(results);
|
||||
```
|
||||
|
||||
This pattern allows you to:
|
||||
1. Process large datasets without overwhelming system resources
|
||||
2. Control the level of concurrency
|
||||
3. Process data as it becomes available
|
||||
4. Create efficient data pipelines
|
||||
|
||||
## Next Steps
|
||||
|
||||
Now that you've learned about streaming with workflows, explore more advanced topics:
|
||||
- [Advanced Event Handling](./advanced-events.mdx)
|
||||
- [Integration Workflows with other LlamaIndex features](./llamaindex-integration.mdx)
|
||||
@@ -0,0 +1,176 @@
|
||||
---
|
||||
title: Workflows
|
||||
---
|
||||
|
||||
A `Workflow` in LlamaIndex is a lightweight, event-driven abstraction used to chain together several events. Workflows are made up of `handlers`, with each one responsible for processing specific event types and emitting new events.
|
||||
|
||||
Workflows are designed to be flexible and can be used to build agents, RAG flows, extraction flows, or anything else you want to implement.
|
||||
|
||||
```package-install
|
||||
npm i @llamaindex/workflow @llamaindex/openai
|
||||
```
|
||||
|
||||
## Getting Started
|
||||
|
||||
Let's explore a simple workflow example where a joke is generated and then critiqued and iterated on:
|
||||
|
||||
<include cwd>../../examples/agents/workflow/joke.ts</include>
|
||||
|
||||
There are a few moving pieces here, so let's go through this step by step.
|
||||
|
||||
### Defining Workflow Events
|
||||
|
||||
```typescript
|
||||
const startEvent = workflowEvent<string>(); // Input topic for joke
|
||||
const jokeEvent = workflowEvent<{ joke: string }>(); // Intermediate joke
|
||||
const critiqueEvent = workflowEvent<{ joke: string; critique: string }>(); // Intermediate critique
|
||||
const resultEvent = workflowEvent<{ joke: string; critique: string }>(); // Final joke + critique
|
||||
```
|
||||
|
||||
Events are defined using the `workflowEvent` function and contain arbitrary data provided as a generic type. In this example, we have four events:
|
||||
- `startEvent`: Takes a string input (the joke topic)
|
||||
- `jokeEvent`: Contains an object with a joke property
|
||||
- `critiqueEvent`: Contains both the joke and its critique, used for the feedback loop
|
||||
- `resultEvent`: Contains the final joke and critique after any iterations
|
||||
|
||||
### Setting up the Workflow with Stateful Middleware
|
||||
|
||||
```typescript
|
||||
const { withState, getContext } = createStatefulMiddleware(() => ({
|
||||
numIterations: 0,
|
||||
maxIterations: 3,
|
||||
}));
|
||||
const jokeFlow = withState(createWorkflow());
|
||||
```
|
||||
|
||||
Our workflow is implemented using the `createWorkflow()` function, enhanced with the `withState` middleware. This middleware provides shared state across all handlers, which in this case tracks:
|
||||
- `numIterations`: Counts how many iterations of joke improvement we've done
|
||||
- `maxIterations`: Sets a limit to prevent infinite loops
|
||||
|
||||
This state will be accessible within workflows by using the `getContext().state` function.
|
||||
|
||||
### Adding Handlers with Loops
|
||||
|
||||
We have three key handlers in our workflow:
|
||||
|
||||
1. The first handler processes the `startEvent`, generates an initial joke, and emits a `jokeEvent`:
|
||||
|
||||
```typescript
|
||||
jokeFlow.handle([startEvent], async (event) => {
|
||||
// Prompt the LLM to write a joke
|
||||
const prompt = `Write your best joke about ${event.data}. Write the joke between <joke> and </joke> tags.`;
|
||||
const response = await llm.complete({ prompt });
|
||||
|
||||
// Parse the joke from the response
|
||||
const joke =
|
||||
response.text.match(/<joke>([\s\S]*?)<\/joke>/)?.[1]?.trim() ??
|
||||
response.text;
|
||||
return jokeEvent.with({ joke: joke });
|
||||
});
|
||||
```
|
||||
|
||||
2. The second handler handles the `jokeEvent`, critiques the joke, and either:
|
||||
- Emits a `critiqueEvent` if the joke needs improvement
|
||||
- Emits a `resultEvent` if the joke is good enough
|
||||
|
||||
```typescript
|
||||
jokeFlow.handle([jokeEvent], async (event) => {
|
||||
// Prompt the LLM to critique the joke
|
||||
const prompt = `Give a thorough critique of the following joke. If the joke needs improvement, put "IMPROVE" somewhere in the critique: ${event.data.joke}`;
|
||||
const response = await llm.complete({ prompt });
|
||||
|
||||
// If the critique includes "IMPROVE", keep iterating, else, return the result
|
||||
if (response.text.includes("IMPROVE")) {
|
||||
return critiqueEvent.with({
|
||||
joke: event.data.joke,
|
||||
critique: response.text,
|
||||
});
|
||||
}
|
||||
|
||||
return resultEvent.with({ joke: event.data.joke, critique: response.text });
|
||||
});
|
||||
```
|
||||
|
||||
3. The third handler processes the `critiqueEvent`, generates an improved joke based on the critique, and either:
|
||||
- Loops back to the joke evaluation (if under the iteration limit)
|
||||
- Emits the final `resultEvent` (if iteration limit reached)
|
||||
|
||||
```typescript
|
||||
jokeFlow.handle([critiqueEvent], async (event) => {
|
||||
// Keep track of the number of iterations
|
||||
const state = getContext().state;
|
||||
state.numIterations++;
|
||||
|
||||
// Write a new joke based on the previous joke and critique
|
||||
const prompt = `Write a new joke based on the following critique and the original joke. Write the joke between <joke> and </joke> tags.\n\nJoke: ${event.data.joke}\n\nCritique: ${event.data.critique}`;
|
||||
const response = await llm.complete({ prompt });
|
||||
|
||||
// Parse the joke from the response
|
||||
const joke =
|
||||
response.text.match(/<joke>([\s\S]*?)<\/joke>/)?.[1]?.trim() ??
|
||||
response.text;
|
||||
|
||||
// If we've done less than the max number of iterations, keep iterating
|
||||
// else, return the result
|
||||
if (state.numIterations < state.maxIterations) {
|
||||
return jokeEvent.with({ joke: joke });
|
||||
}
|
||||
|
||||
return resultEvent.with({ joke: joke, critique: event.data.critique });
|
||||
});
|
||||
```
|
||||
|
||||
### Running the Workflow
|
||||
|
||||
```typescript
|
||||
async function main() {
|
||||
const { stream, sendEvent } = jokeFlow.createContext();
|
||||
sendEvent(startEvent.with("pirates"));
|
||||
|
||||
let result: { joke: string, critique: string } | undefined;
|
||||
|
||||
for await (const event of stream) {
|
||||
// console.log(event.data); optionally log the event data
|
||||
if (resultEvent.include(event)) {
|
||||
result = event.data;
|
||||
break; // Stop when we get the final result
|
||||
}
|
||||
}
|
||||
|
||||
console.log(result);
|
||||
}
|
||||
```
|
||||
|
||||
To run the workflow, we:
|
||||
1. Create a workflow context with `createContext()`
|
||||
2. Trigger the initial event with `sendEvent()`
|
||||
3. Listen to the event stream and process events as they arrive
|
||||
4. Use `include()` to check if an event is of a specific type
|
||||
5. Break the loop when we receive our final result
|
||||
|
||||
### Using Stream Utilities
|
||||
|
||||
The `stream` returned by `createContext` contains utility functions to make working with event streams easier:
|
||||
|
||||
```typescript
|
||||
// Create a workflow context and send the initial event
|
||||
const { stream, sendEvent } = jokeFlow.createContext();
|
||||
sendEvent(startEvent.with("pirates"));
|
||||
|
||||
// Collect all events until we get a resultEvent
|
||||
const allEvents = await stream.until(resultEvent).toArray();
|
||||
|
||||
// The last event will be the resultEvent
|
||||
const finalEvent = allEvents.at(-1);
|
||||
console.log(finalEvent.data); // Output the joke and critique
|
||||
```
|
||||
|
||||
The stream utilities make it easier to work with the asynchronous event flow. In this example, we use:
|
||||
- `toArray`: Aggregates all events into an array
|
||||
- `until`: Creates a stream that emits events until a condition is met (in this case, until a resultEvent is received)
|
||||
|
||||
You can combine these utilities with other stream operators like `filter` and `map` to create powerful processing pipelines.
|
||||
|
||||
## Next Steps
|
||||
|
||||
To learn more about workflows, check out [the Workflows documentation](/docs/llamaindex/modules/agents/workflows).
|
||||
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"pages": ["llamaindex", "llamaflow", "cloud", "api"]
|
||||
"pages": ["llamaindex", "api", "llamaflow"]
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
export type {
|
||||
HandlerContext,
|
||||
Workflow,
|
||||
WorkflowContext,
|
||||
} from "@llamaindex/workflow";
|
||||
@@ -3,12 +3,19 @@
|
||||
"extends": ["//"],
|
||||
"tasks": {
|
||||
"build": {
|
||||
"inputs": [
|
||||
"node_modules/@llama-flow/docs/**",
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.mdx",
|
||||
"src/**/*.md"
|
||||
],
|
||||
"outputs": [
|
||||
".next",
|
||||
".source",
|
||||
"next-env.d.ts",
|
||||
"src/content/docs/cloud/api/**",
|
||||
"src/content/docs/api/**"
|
||||
"src/content/docs/api/**",
|
||||
"tsconfig.json"
|
||||
],
|
||||
"env": [
|
||||
"LLAMA_CLOUD_API_KEY",
|
||||
|
||||
@@ -2,12 +2,10 @@
|
||||
"plugin": ["typedoc-plugin-markdown", "typedoc-plugin-merge-modules"],
|
||||
"entryPoints": [
|
||||
"../../packages/{,**/}index.ts",
|
||||
"../../packages/readers/src/*.ts",
|
||||
"../../packages/cloud/src/{reader,utils}.ts"
|
||||
"../../packages/readers/src/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"../../packages/autotool/**/src/index.ts",
|
||||
"../../packages/cloud/src/client/index.ts",
|
||||
"**/node_modules/**",
|
||||
"**/dist/**",
|
||||
"**/test/**",
|
||||
@@ -22,7 +20,7 @@
|
||||
"categoryOrder": ["Classes", "Enums", "Functions", "Interfaces", "Types"],
|
||||
"sort": ["source-order"],
|
||||
"entryFileName": "index.md",
|
||||
"fileExtension": ".mdx",
|
||||
"fileExtension": ".md",
|
||||
"hidePageTitle": true,
|
||||
"hidePageHeader": true,
|
||||
"hideGroupHeadings": true,
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# @llamaindex/core-e2e
|
||||
|
||||
## 0.1.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- b0cd530: # Breaking Change
|
||||
|
||||
## What Changed
|
||||
|
||||
Remove default setting of llm and embedModel in Settings
|
||||
|
||||
## Migration Guide
|
||||
|
||||
Set the llm provider and embed Model in the top of your code using Settings.llm = and Settings.embedModel
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
# @llamaindex/cloudflare-worker-agent-test
|
||||
|
||||
## 0.0.161
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b0cd530]
|
||||
- Updated dependencies [361a685]
|
||||
- llamaindex@0.11.0
|
||||
|
||||
## 0.0.160
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.10.6
|
||||
|
||||
## 0.0.159
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.10.5
|
||||
|
||||
## 0.0.158
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2225ffd]
|
||||
- Updated dependencies [6ddf1c1]
|
||||
- Updated dependencies [41953a3]
|
||||
- llamaindex@0.10.4
|
||||
|
||||
## 0.0.157
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3ee8c83]
|
||||
- llamaindex@0.10.3
|
||||
|
||||
## 0.0.156
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.10.2
|
||||
|
||||
## 0.0.155
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@llamaindex/cloudflare-worker-agent-test",
|
||||
"version": "0.0.155",
|
||||
"version": "0.0.161",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -1,5 +1,37 @@
|
||||
# @llamaindex/llama-parse-browser-test
|
||||
|
||||
## 0.0.63
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @llamaindex/cloud@4.0.8
|
||||
|
||||
## 0.0.62
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [40f5f41]
|
||||
- @llamaindex/cloud@4.0.7
|
||||
|
||||
## 0.0.61
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @llamaindex/cloud@4.0.6
|
||||
|
||||
## 0.0.60
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2225ffd]
|
||||
- @llamaindex/cloud@4.0.5
|
||||
|
||||
## 0.0.59
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @llamaindex/cloud@4.0.4
|
||||
|
||||
## 0.0.58
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@llamaindex/llama-parse-browser-test",
|
||||
"private": true,
|
||||
"version": "0.0.58",
|
||||
"version": "0.0.63",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@@ -10,8 +10,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.7.3",
|
||||
"vite": "^5.4.16",
|
||||
"vite-plugin-wasm": "^3.3.0"
|
||||
"vite": "^6.3.3",
|
||||
"vite-plugin-wasm": "^3.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@llamaindex/cloud": "workspace:*"
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
# @llamaindex/next-agent-test
|
||||
|
||||
## 0.1.161
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b0cd530]
|
||||
- Updated dependencies [361a685]
|
||||
- llamaindex@0.11.0
|
||||
|
||||
## 0.1.160
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.10.6
|
||||
|
||||
## 0.1.159
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.10.5
|
||||
|
||||
## 0.1.158
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2225ffd]
|
||||
- Updated dependencies [6ddf1c1]
|
||||
- Updated dependencies [41953a3]
|
||||
- llamaindex@0.10.4
|
||||
|
||||
## 0.1.157
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3ee8c83]
|
||||
- llamaindex@0.10.3
|
||||
|
||||
## 0.1.156
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.10.2
|
||||
|
||||
## 0.1.155
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@llamaindex/next-agent-test",
|
||||
"version": "0.1.155",
|
||||
"version": "0.1.161",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"use server";
|
||||
import { OpenAIAgent } from "@llamaindex/openai";
|
||||
import { createStreamableUI } from "ai/rsc";
|
||||
import type { ChatMessage } from "llamaindex";
|
||||
import { OpenAIAgent } from "llamaindex";
|
||||
|
||||
export async function chatWithAgent(
|
||||
question: string,
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
# test-edge-runtime
|
||||
|
||||
## 0.1.160
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b0cd530]
|
||||
- Updated dependencies [361a685]
|
||||
- llamaindex@0.11.0
|
||||
|
||||
## 0.1.159
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.10.6
|
||||
|
||||
## 0.1.158
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.10.5
|
||||
|
||||
## 0.1.157
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2225ffd]
|
||||
- Updated dependencies [6ddf1c1]
|
||||
- Updated dependencies [41953a3]
|
||||
- llamaindex@0.10.4
|
||||
|
||||
## 0.1.156
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3ee8c83]
|
||||
- llamaindex@0.10.3
|
||||
|
||||
## 0.1.155
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.10.2
|
||||
|
||||
## 0.1.154
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@llamaindex/nextjs-edge-runtime-test",
|
||||
"version": "0.1.154",
|
||||
"version": "0.1.160",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
||||
@@ -1,5 +1,64 @@
|
||||
# @llamaindex/next-node-runtime
|
||||
|
||||
## 0.1.28
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b0cd530]
|
||||
- Updated dependencies [361a685]
|
||||
- llamaindex@0.11.0
|
||||
- @llamaindex/huggingface@0.1.10
|
||||
- @llamaindex/readers@3.1.4
|
||||
|
||||
## 0.1.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [76c9a80]
|
||||
- @llamaindex/huggingface@0.1.9
|
||||
- llamaindex@0.10.6
|
||||
- @llamaindex/readers@3.1.3
|
||||
|
||||
## 0.1.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.10.5
|
||||
- @llamaindex/huggingface@0.1.8
|
||||
- @llamaindex/readers@3.1.2
|
||||
|
||||
## 0.1.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2225ffd]
|
||||
- Updated dependencies [6ddf1c1]
|
||||
- Updated dependencies [41953a3]
|
||||
- llamaindex@0.10.4
|
||||
|
||||
## 0.1.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3ee8c83]
|
||||
- llamaindex@0.10.3
|
||||
- @llamaindex/huggingface@0.1.7
|
||||
- @llamaindex/readers@3.1.1
|
||||
|
||||
## 0.1.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1e59695]
|
||||
- @llamaindex/readers@3.1.0
|
||||
|
||||
## 0.1.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.10.2
|
||||
- @llamaindex/huggingface@0.1.6
|
||||
|
||||
## 0.1.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@llamaindex/next-node-runtime-test",
|
||||
"version": "0.1.21",
|
||||
"version": "0.1.28",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
"use server";
|
||||
import { HuggingFaceEmbedding } from "@llamaindex/huggingface";
|
||||
import { OpenAI, OpenAIAgent } from "@llamaindex/openai";
|
||||
import { SimpleDirectoryReader } from "@llamaindex/readers/directory";
|
||||
import { OpenAI, OpenAIAgent, Settings, VectorStoreIndex } from "llamaindex";
|
||||
import { Settings, VectorStoreIndex } from "llamaindex";
|
||||
|
||||
Settings.llm = new OpenAI({
|
||||
apiKey: process.env.NEXT_PUBLIC_OPENAI_KEY ?? "FAKE_KEY_TO_PASS_TESTS",
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
# vite-import-llamaindex
|
||||
|
||||
## 0.0.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b0cd530]
|
||||
- Updated dependencies [361a685]
|
||||
- llamaindex@0.11.0
|
||||
|
||||
## 0.0.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.10.6
|
||||
|
||||
## 0.0.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.10.5
|
||||
|
||||
## 0.0.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2225ffd]
|
||||
- Updated dependencies [6ddf1c1]
|
||||
- Updated dependencies [41953a3]
|
||||
- llamaindex@0.10.4
|
||||
|
||||
## 0.0.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3ee8c83]
|
||||
- llamaindex@0.10.3
|
||||
|
||||
## 0.0.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.10.2
|
||||
|
||||
## 0.0.21
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "vite-import-llamaindex",
|
||||
"private": true,
|
||||
"version": "0.0.21",
|
||||
"version": "0.0.27",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "vite build",
|
||||
@@ -16,7 +16,7 @@
|
||||
"@size-limit/preset-big-lib": "^11.1.6",
|
||||
"size-limit": "^11.1.6",
|
||||
"typescript": "^5.7.3",
|
||||
"vite": "^5.4.16"
|
||||
"vite": "^6.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"llamaindex": "workspace:*"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"root":["./src/main.ts","./vite.config.ts"],"version":"5.7.3"}
|
||||
@@ -1,5 +1,49 @@
|
||||
# @llamaindex/waku-query-engine-test
|
||||
|
||||
## 0.0.161
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [b0cd530]
|
||||
- Updated dependencies [361a685]
|
||||
- llamaindex@0.11.0
|
||||
|
||||
## 0.0.160
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.10.6
|
||||
|
||||
## 0.0.159
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [9b2e25a]
|
||||
- @llamaindex/env@0.1.30
|
||||
- llamaindex@0.10.5
|
||||
|
||||
## 0.0.158
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [2225ffd]
|
||||
- Updated dependencies [6ddf1c1]
|
||||
- Updated dependencies [41953a3]
|
||||
- llamaindex@0.10.4
|
||||
|
||||
## 0.0.157
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3ee8c83]
|
||||
- llamaindex@0.10.3
|
||||
|
||||
## 0.0.156
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- llamaindex@0.10.2
|
||||
|
||||
## 0.0.155
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@llamaindex/waku-query-engine-test",
|
||||
"version": "0.0.155",
|
||||
"version": "0.0.161",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ClipEmbedding } from "@llamaindex/clip";
|
||||
import type { LoadTransformerEvent } from "@llamaindex/env/multi-model";
|
||||
import { setTransformers } from "@llamaindex/env/multi-model";
|
||||
import { OpenAIEmbedding } from "@llamaindex/openai";
|
||||
import { ImageNode, Settings } from "llamaindex";
|
||||
import assert from "node:assert";
|
||||
import { type Mock, test } from "node:test";
|
||||
@@ -19,6 +20,7 @@ test.before(() => {
|
||||
|
||||
test.beforeEach(() => {
|
||||
callback.mock.resetCalls();
|
||||
Settings.embedModel = new OpenAIEmbedding();
|
||||
});
|
||||
|
||||
await test.skip("clip embedding", async (t) => {
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import type { TaskStep } from "@llamaindex/core/agent";
|
||||
import {
|
||||
LLMSingleSelector,
|
||||
OpenAIAgent,
|
||||
Settings,
|
||||
type ChatMessage,
|
||||
} from "llamaindex";
|
||||
import { OpenAIAgent } from "@llamaindex/openai";
|
||||
import { LLMSingleSelector, Settings, type ChatMessage } from "llamaindex";
|
||||
import assert from "node:assert";
|
||||
import { test } from "node:test";
|
||||
import { divideNumbersTool, sumNumbersTool } from "./fixtures/tools.js";
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { extractText } from "@llamaindex/core/utils";
|
||||
import { OpenAI, OpenAIAgent } from "@llamaindex/openai";
|
||||
import { consola } from "consola";
|
||||
import {
|
||||
Document,
|
||||
FunctionTool,
|
||||
ObjectIndex,
|
||||
OpenAI,
|
||||
OpenAIAgent,
|
||||
QueryEngineTool,
|
||||
SentenceSplitter,
|
||||
Settings,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { extractText } from "@llamaindex/core/utils";
|
||||
import { OpenAI, ReActAgent, Settings, type LLM } from "llamaindex";
|
||||
import { OpenAI } from "@llamaindex/openai";
|
||||
import { ReActAgent, Settings, type LLM } from "llamaindex";
|
||||
import { ok } from "node:assert";
|
||||
import { beforeEach, test } from "node:test";
|
||||
import { getWeatherTool } from "./fixtures/tools.js";
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { OpenAIEmbedding } from "@llamaindex/openai";
|
||||
import { PGVectorStore } from "@llamaindex/postgres";
|
||||
import { config } from "dotenv";
|
||||
import { Document, VectorStoreQueryMode } from "llamaindex";
|
||||
import { Document, Settings, VectorStoreQueryMode } from "llamaindex";
|
||||
import assert from "node:assert";
|
||||
import { test } from "node:test";
|
||||
import { beforeEach, test } from "node:test";
|
||||
import pg from "pg";
|
||||
import { registerTypes } from "pgvector/pg";
|
||||
|
||||
@@ -14,6 +15,10 @@ const pgConfig = {
|
||||
database: "llamaindex_node_test",
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
Settings.embedModel = new OpenAIEmbedding();
|
||||
});
|
||||
|
||||
await test("init with client", async (t) => {
|
||||
const pgClient = new pg.Client(pgConfig);
|
||||
await pgClient.connect();
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
package-lock.json
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "e2e-npm",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "node --import tsx --test test/*.e2e.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@llamaindex/workflow": "1.1.1",
|
||||
"llamaindex": "0.10.5",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tsx": "^4.19.1",
|
||||
"@types/node": "^22.9.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import { OpenAI } from "@llamaindex/openai";
|
||||
import { agent } from "@llamaindex/workflow";
|
||||
import { Settings, tool } from "llamaindex";
|
||||
import { ok } from "node:assert";
|
||||
import { test } from "node:test";
|
||||
import { z } from "zod";
|
||||
|
||||
Settings.llm = new OpenAI({ model: "gpt-4-0613" });
|
||||
|
||||
test("creating agent from workflow package", async () => {
|
||||
const calculatorAgent = agent({
|
||||
tools: [
|
||||
tool({
|
||||
name: "add",
|
||||
description: "Adds two numbers",
|
||||
parameters: z.object({ x: z.number(), y: z.number() }),
|
||||
execute: ({ x, y }) => x + y,
|
||||
}),
|
||||
],
|
||||
});
|
||||
ok(calculatorAgent !== undefined, "calculatorAgent should be defined");
|
||||
|
||||
const agents = calculatorAgent.getAgents();
|
||||
const currentLLM = agents?.[0].llm;
|
||||
ok(
|
||||
(currentLLM as OpenAI)?.model === (Settings.llm as OpenAI)?.model,
|
||||
"Agent should use the same LLM model as setup in Settings instance",
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "node16",
|
||||
"moduleResolution": "node16",
|
||||
"target": "ESNext",
|
||||
"types": ["node"],
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"include": ["test/**/*.ts"]
|
||||
}
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@llamaindex/e2e",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"version": "0.1.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"e2e": "node --import tsx --import ./mock-register.js --test ./node/**/*.e2e.ts",
|
||||
|
||||
+1
-2
@@ -1,3 +1,2 @@
|
||||
package-lock.json
|
||||
storage
|
||||
tmp_data
|
||||
tmp_data
|
||||
|
||||
@@ -1,5 +1,273 @@
|
||||
# examples
|
||||
|
||||
## 0.3.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [680b529]
|
||||
- Updated dependencies [b0cd530]
|
||||
- Updated dependencies [c73c659]
|
||||
- Updated dependencies [361a685]
|
||||
- Updated dependencies [3e66ddc]
|
||||
- @llamaindex/workflow@1.1.3
|
||||
- @llamaindex/core@0.6.6
|
||||
- llamaindex@0.11.0
|
||||
- @llamaindex/qdrant@0.1.15
|
||||
- @llamaindex/azure@0.1.16
|
||||
- @llamaindex/openai@0.4.0
|
||||
- @llamaindex/cloud@4.0.8
|
||||
- @llamaindex/node-parser@2.0.6
|
||||
- @llamaindex/anthropic@0.3.7
|
||||
- @llamaindex/assemblyai@0.1.5
|
||||
- @llamaindex/clip@0.0.56
|
||||
- @llamaindex/cohere@0.0.20
|
||||
- @llamaindex/deepinfra@0.0.56
|
||||
- @llamaindex/discord@0.1.5
|
||||
- @llamaindex/google@0.3.2
|
||||
- @llamaindex/huggingface@0.1.10
|
||||
- @llamaindex/jinaai@0.0.16
|
||||
- @llamaindex/mistral@0.1.6
|
||||
- @llamaindex/mixedbread@0.0.20
|
||||
- @llamaindex/notion@0.1.5
|
||||
- @llamaindex/ollama@0.1.6
|
||||
- @llamaindex/perplexity@0.0.13
|
||||
- @llamaindex/portkey-ai@0.0.48
|
||||
- @llamaindex/replicate@0.0.48
|
||||
- @llamaindex/astra@0.0.20
|
||||
- @llamaindex/chroma@0.0.20
|
||||
- @llamaindex/elastic-search@0.1.6
|
||||
- @llamaindex/firestore@1.0.13
|
||||
- @llamaindex/milvus@0.1.15
|
||||
- @llamaindex/mongodb@0.0.21
|
||||
- @llamaindex/pinecone@0.1.6
|
||||
- @llamaindex/postgres@0.0.49
|
||||
- @llamaindex/supabase@0.1.5
|
||||
- @llamaindex/upstash@0.0.20
|
||||
- @llamaindex/weaviate@0.0.20
|
||||
- @llamaindex/vercel@0.1.6
|
||||
- @llamaindex/voyage-ai@1.0.12
|
||||
- @llamaindex/readers@3.1.4
|
||||
- @llamaindex/tools@0.0.11
|
||||
- @llamaindex/deepseek@0.0.16
|
||||
- @llamaindex/fireworks@0.0.16
|
||||
- @llamaindex/groq@0.0.71
|
||||
- @llamaindex/together@0.0.16
|
||||
- @llamaindex/vllm@0.0.42
|
||||
- @llamaindex/xai@0.0.3
|
||||
|
||||
## 0.3.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- d671ed6: Add functionality for search params when querying Qdrant vector store.
|
||||
- Updated dependencies [7a7ca60]
|
||||
- Updated dependencies [7a7ca60]
|
||||
- Updated dependencies [76c9a80]
|
||||
- Updated dependencies [168d11f]
|
||||
- Updated dependencies [d671ed6]
|
||||
- Updated dependencies [40f5f41]
|
||||
- @llamaindex/xai@0.0.2
|
||||
- @llamaindex/fireworks@0.0.15
|
||||
- @llamaindex/elastic-search@0.1.5
|
||||
- @llamaindex/firestore@1.0.12
|
||||
- @llamaindex/pinecone@0.1.5
|
||||
- @llamaindex/postgres@0.0.48
|
||||
- @llamaindex/supabase@0.1.4
|
||||
- @llamaindex/weaviate@0.0.19
|
||||
- @llamaindex/mongodb@0.0.20
|
||||
- @llamaindex/upstash@0.0.19
|
||||
- @llamaindex/chroma@0.0.19
|
||||
- @llamaindex/milvus@0.1.14
|
||||
- @llamaindex/qdrant@0.1.14
|
||||
- @llamaindex/astra@0.0.19
|
||||
- @llamaindex/azure@0.1.15
|
||||
- @llamaindex/huggingface@0.1.9
|
||||
- @llamaindex/assemblyai@0.1.4
|
||||
- @llamaindex/mixedbread@0.0.19
|
||||
- @llamaindex/perplexity@0.0.12
|
||||
- @llamaindex/portkey-ai@0.0.47
|
||||
- @llamaindex/anthropic@0.3.6
|
||||
- @llamaindex/deepinfra@0.0.55
|
||||
- @llamaindex/replicate@0.0.47
|
||||
- @llamaindex/voyage-ai@1.0.11
|
||||
- @llamaindex/discord@0.1.4
|
||||
- @llamaindex/mistral@0.1.5
|
||||
- @llamaindex/cohere@0.0.19
|
||||
- @llamaindex/google@0.3.1
|
||||
- @llamaindex/jinaai@0.0.15
|
||||
- @llamaindex/notion@0.1.4
|
||||
- @llamaindex/ollama@0.1.5
|
||||
- @llamaindex/openai@0.3.7
|
||||
- @llamaindex/vercel@0.1.5
|
||||
- @llamaindex/clip@0.0.55
|
||||
- @llamaindex/tools@0.0.10
|
||||
- @llamaindex/workflow@1.1.2
|
||||
- @llamaindex/core@0.6.5
|
||||
- @llamaindex/cloud@4.0.7
|
||||
- llamaindex@0.10.6
|
||||
- @llamaindex/deepseek@0.0.15
|
||||
- @llamaindex/groq@0.0.70
|
||||
- @llamaindex/together@0.0.15
|
||||
- @llamaindex/vllm@0.0.41
|
||||
- @llamaindex/node-parser@2.0.5
|
||||
- @llamaindex/readers@3.1.3
|
||||
|
||||
## 0.3.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 9b2e25a: Use Uint8Array instead of Buffer for file type messages (works with non-NodeJS)
|
||||
- 206b491: Add support for google live api
|
||||
- Updated dependencies [9b2e25a]
|
||||
- Updated dependencies [206b491]
|
||||
- @llamaindex/anthropic@0.3.5
|
||||
- @llamaindex/google@0.3.0
|
||||
- @llamaindex/openai@0.3.6
|
||||
- @llamaindex/core@0.6.4
|
||||
- @llamaindex/env@0.1.30
|
||||
- llamaindex@0.10.5
|
||||
- @llamaindex/clip@0.0.54
|
||||
- @llamaindex/deepinfra@0.0.54
|
||||
- @llamaindex/deepseek@0.0.14
|
||||
- @llamaindex/fireworks@0.0.14
|
||||
- @llamaindex/groq@0.0.69
|
||||
- @llamaindex/huggingface@0.1.8
|
||||
- @llamaindex/jinaai@0.0.14
|
||||
- @llamaindex/perplexity@0.0.11
|
||||
- @llamaindex/azure@0.1.14
|
||||
- @llamaindex/elastic-search@0.1.4
|
||||
- @llamaindex/milvus@0.1.13
|
||||
- @llamaindex/qdrant@0.1.13
|
||||
- @llamaindex/supabase@0.1.3
|
||||
- @llamaindex/together@0.0.14
|
||||
- @llamaindex/vllm@0.0.40
|
||||
- @llamaindex/cloud@4.0.6
|
||||
- @llamaindex/node-parser@2.0.4
|
||||
- @llamaindex/assemblyai@0.1.3
|
||||
- @llamaindex/cohere@0.0.18
|
||||
- @llamaindex/discord@0.1.3
|
||||
- @llamaindex/mistral@0.1.4
|
||||
- @llamaindex/mixedbread@0.0.18
|
||||
- @llamaindex/notion@0.1.3
|
||||
- @llamaindex/ollama@0.1.4
|
||||
- @llamaindex/portkey-ai@0.0.46
|
||||
- @llamaindex/replicate@0.0.46
|
||||
- @llamaindex/astra@0.0.18
|
||||
- @llamaindex/chroma@0.0.18
|
||||
- @llamaindex/firestore@1.0.11
|
||||
- @llamaindex/mongodb@0.0.19
|
||||
- @llamaindex/pinecone@0.1.4
|
||||
- @llamaindex/postgres@0.0.47
|
||||
- @llamaindex/upstash@0.0.18
|
||||
- @llamaindex/weaviate@0.0.18
|
||||
- @llamaindex/vercel@0.1.4
|
||||
- @llamaindex/voyage-ai@1.0.10
|
||||
- @llamaindex/readers@3.1.2
|
||||
- @llamaindex/tools@0.0.9
|
||||
- @llamaindex/workflow@1.1.1
|
||||
|
||||
## 0.3.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [3ee8c83]
|
||||
- @llamaindex/core@0.6.3
|
||||
- llamaindex@0.10.3
|
||||
- @llamaindex/anthropic@0.3.4
|
||||
- @llamaindex/google@0.2.5
|
||||
- @llamaindex/openai@0.3.5
|
||||
- @llamaindex/vercel@0.1.3
|
||||
- @llamaindex/cloud@4.0.4
|
||||
- @llamaindex/node-parser@2.0.3
|
||||
- @llamaindex/assemblyai@0.1.2
|
||||
- @llamaindex/clip@0.0.53
|
||||
- @llamaindex/cohere@0.0.17
|
||||
- @llamaindex/deepinfra@0.0.53
|
||||
- @llamaindex/discord@0.1.2
|
||||
- @llamaindex/huggingface@0.1.7
|
||||
- @llamaindex/jinaai@0.0.13
|
||||
- @llamaindex/mistral@0.1.3
|
||||
- @llamaindex/mixedbread@0.0.17
|
||||
- @llamaindex/notion@0.1.2
|
||||
- @llamaindex/ollama@0.1.3
|
||||
- @llamaindex/perplexity@0.0.10
|
||||
- @llamaindex/portkey-ai@0.0.45
|
||||
- @llamaindex/replicate@0.0.45
|
||||
- @llamaindex/astra@0.0.17
|
||||
- @llamaindex/azure@0.1.13
|
||||
- @llamaindex/chroma@0.0.17
|
||||
- @llamaindex/elastic-search@0.1.3
|
||||
- @llamaindex/firestore@1.0.10
|
||||
- @llamaindex/milvus@0.1.12
|
||||
- @llamaindex/mongodb@0.0.18
|
||||
- @llamaindex/pinecone@0.1.3
|
||||
- @llamaindex/postgres@0.0.46
|
||||
- @llamaindex/qdrant@0.1.12
|
||||
- @llamaindex/supabase@0.1.2
|
||||
- @llamaindex/upstash@0.0.17
|
||||
- @llamaindex/weaviate@0.0.17
|
||||
- @llamaindex/voyage-ai@1.0.9
|
||||
- @llamaindex/readers@3.1.1
|
||||
- @llamaindex/tools@0.0.8
|
||||
- @llamaindex/workflow@1.0.4
|
||||
- @llamaindex/deepseek@0.0.13
|
||||
- @llamaindex/fireworks@0.0.13
|
||||
- @llamaindex/groq@0.0.68
|
||||
- @llamaindex/together@0.0.13
|
||||
- @llamaindex/vllm@0.0.39
|
||||
|
||||
## 0.3.12
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [82d4b46]
|
||||
- @llamaindex/server@0.1.6
|
||||
- @llamaindex/tools@0.0.7
|
||||
|
||||
## 0.3.11
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [294f502]
|
||||
- @llamaindex/tools@0.0.6
|
||||
|
||||
## 0.3.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [1e59695]
|
||||
- Updated dependencies [1e59695]
|
||||
- Updated dependencies [1e59695]
|
||||
- Updated dependencies [1e59695]
|
||||
- Updated dependencies [1e59695]
|
||||
- Updated dependencies [1e59695]
|
||||
- @llamaindex/assemblyai@0.1.1
|
||||
- @llamaindex/mongodb@0.0.17
|
||||
- @llamaindex/azure@0.1.12
|
||||
- @llamaindex/readers@3.1.0
|
||||
- @llamaindex/notion@0.1.1
|
||||
- @llamaindex/discord@0.1.1
|
||||
|
||||
## 0.3.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [96dac4d]
|
||||
- Updated dependencies [e5c3f95]
|
||||
- @llamaindex/google@0.2.4
|
||||
- @llamaindex/openai@0.3.4
|
||||
- llamaindex@0.10.2
|
||||
- @llamaindex/clip@0.0.52
|
||||
- @llamaindex/deepinfra@0.0.52
|
||||
- @llamaindex/deepseek@0.0.12
|
||||
- @llamaindex/fireworks@0.0.12
|
||||
- @llamaindex/groq@0.0.67
|
||||
- @llamaindex/huggingface@0.1.6
|
||||
- @llamaindex/jinaai@0.0.12
|
||||
- @llamaindex/perplexity@0.0.9
|
||||
- @llamaindex/together@0.0.12
|
||||
- @llamaindex/vllm@0.0.38
|
||||
|
||||
## 0.3.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@ make sure you have basic knowledge of the [LlamaIndexTS](https://ts.llamaindex.a
|
||||
# export your API key
|
||||
export OPENAI_API_KEY="sk-..."
|
||||
|
||||
npx tsx ./chatEngine.ts
|
||||
npx tsx ./rag/chatEngine.ts
|
||||
```
|
||||
|
||||
## Build your own RAG app
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { tool } from "@llamaindex/core/tools";
|
||||
import { openai } from "@llamaindex/openai";
|
||||
import fs from "fs";
|
||||
import {
|
||||
agent,
|
||||
AgentToolCall,
|
||||
AgentToolCallResult,
|
||||
agentToolCallEvent,
|
||||
agentToolCallResultEvent,
|
||||
multiAgent,
|
||||
tool,
|
||||
} from "llamaindex";
|
||||
} from "@llamaindex/workflow";
|
||||
import fs from "fs";
|
||||
import os from "os";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -56,19 +56,19 @@ async function main() {
|
||||
rootAgent: researchAgent,
|
||||
});
|
||||
|
||||
const context = workflow.run("Write a blog post about history of LLM");
|
||||
const events = workflow.runStream("Write a blog post about history of LLM");
|
||||
|
||||
let finalResult;
|
||||
for await (const event of context) {
|
||||
if (event instanceof AgentToolCall) {
|
||||
for await (const event of events) {
|
||||
if (agentToolCallEvent.include(event)) {
|
||||
console.log(
|
||||
`[Agent ${event.displayName}] executing tool ${event.data.toolName} with parameters ${JSON.stringify(
|
||||
`[Agent ${event.data.agentName}] executing tool ${event.data.toolName} with parameters ${JSON.stringify(
|
||||
event.data.toolKwargs,
|
||||
)}`,
|
||||
);
|
||||
} else if (event instanceof AgentToolCallResult) {
|
||||
} else if (agentToolCallResultEvent.include(event)) {
|
||||
console.log(
|
||||
`[Agent ${event.displayName}] executed tool ${event.data.toolName} with result ${event.data.toolOutput.result}`,
|
||||
`[Tool ${event.data.toolName}] executed with result ${event.data.toolOutput.result}`,
|
||||
);
|
||||
}
|
||||
finalResult = event;
|
||||
@@ -1,5 +1,6 @@
|
||||
import { OpenAI } from "@llamaindex/openai";
|
||||
import { FunctionTool, agent } from "llamaindex";
|
||||
import { agent } from "@llamaindex/workflow";
|
||||
import { tool } from "llamaindex";
|
||||
import { z } from "zod";
|
||||
|
||||
const csvData =
|
||||
@@ -11,24 +12,22 @@ const userQuestion = "which are the best comedies after 2010?";
|
||||
// The agent will succeed if we increase `maxTokens` to 1024
|
||||
const llm = new OpenAI({ model: "gpt-4-turbo", maxTokens: 1024 });
|
||||
|
||||
const interpreterTool = FunctionTool.from(
|
||||
({ code }) => {
|
||||
const interpreterTool = tool({
|
||||
name: "interpreter",
|
||||
description:
|
||||
"Execute python code in a Jupyter notebook cell and return any result, stdout, stderr, display_data, and error.",
|
||||
parameters: z.object({
|
||||
code: z.string({
|
||||
description: "The python code to execute in a single cell.",
|
||||
}),
|
||||
}),
|
||||
execute: ({ code }) => {
|
||||
console.log(
|
||||
`To answer the user's question, call the following code:\n${code}`,
|
||||
);
|
||||
return code;
|
||||
},
|
||||
{
|
||||
name: "interpreter",
|
||||
description:
|
||||
"Execute python code in a Jupyter notebook cell and return any result, stdout, stderr, display_data, and error.",
|
||||
parameters: z.object({
|
||||
code: z.string({
|
||||
description: "The python code to execute in a single cell.",
|
||||
}),
|
||||
}),
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
const systemPrompt =
|
||||
"You are a Python interpreter.\n - You are given tasks to complete and you run python code to solve them.\n - The python code runs in a Jupyter notebook. Every time you call $(interpreter) tool, the python code is executed in a separate cell. It's okay to make multiple calls to $(interpreter).\n - Display visualizations using matplotlib or any other visualization library directly in the notebook. Shouldn't save the visualizations to a file, just return the base64 encoded data.\n - You can install any pip package (if it exists) if you need to but the usual packages for data analysis are already preinstalled.\n - You can run any python code you want in a secure environment.";
|
||||
@@ -1,6 +1,6 @@
|
||||
import { openai } from "@llamaindex/openai";
|
||||
import { mcp } from "@llamaindex/tools";
|
||||
import { agent } from "llamaindex";
|
||||
import { agent } from "@llamaindex/workflow";
|
||||
|
||||
async function main() {
|
||||
// Create an MCP server for filesystem tools
|
||||
@@ -9,6 +9,12 @@ async function main() {
|
||||
args: ["-y", "@modelcontextprotocol/server-filesystem", "."],
|
||||
verbose: true,
|
||||
});
|
||||
// You can also connect to the MCP server using SSE
|
||||
// See: https://modelcontextprotocol.io/docs/concepts/transports#server-sent-events-sse
|
||||
// const server = mcp({
|
||||
// url: "http://localhost:8000/mcp",
|
||||
// verbose: true,
|
||||
// });
|
||||
|
||||
try {
|
||||
// Create an agent that uses the MCP tools
|
||||
@@ -21,9 +27,7 @@ async function main() {
|
||||
});
|
||||
|
||||
// Run a task
|
||||
const response = await myAgent.run(
|
||||
"what are the files in the current directory?",
|
||||
);
|
||||
const response = await myAgent.run("What are the available tools?");
|
||||
|
||||
console.log("Agent response:", response.data);
|
||||
} finally {
|
||||
+18
-18
@@ -6,15 +6,15 @@
|
||||
import { openai } from "@llamaindex/openai";
|
||||
import {
|
||||
agent,
|
||||
AgentInput,
|
||||
AgentOutput,
|
||||
AgentStream,
|
||||
AgentToolCall,
|
||||
AgentToolCallResult,
|
||||
agentInputEvent,
|
||||
agentOutputEvent,
|
||||
agentStreamEvent,
|
||||
agentToolCallEvent,
|
||||
agentToolCallResultEvent,
|
||||
multiAgent,
|
||||
StopEvent,
|
||||
tool,
|
||||
} from "llamaindex";
|
||||
stopAgentEvent,
|
||||
} from "@llamaindex/workflow";
|
||||
import { tool } from "llamaindex";
|
||||
import { z } from "zod";
|
||||
|
||||
const llm = openai({
|
||||
@@ -79,21 +79,21 @@ async function multiWeatherAgent() {
|
||||
});
|
||||
|
||||
// Ask the agent to get the weather in a city
|
||||
const context = workflow.run(
|
||||
const events = workflow.runStream(
|
||||
"What is the weather in San Francisco in Celsius?",
|
||||
);
|
||||
// Stream the events
|
||||
for await (const event of context) {
|
||||
// These events might be useful for UI
|
||||
for await (const event of events) {
|
||||
// These events are useful for reporting the current state to the user in the UI
|
||||
if (
|
||||
event instanceof AgentToolCall ||
|
||||
event instanceof AgentToolCallResult ||
|
||||
event instanceof AgentOutput ||
|
||||
event instanceof AgentInput ||
|
||||
event instanceof StopEvent
|
||||
agentToolCallEvent.include(event) ||
|
||||
agentToolCallResultEvent.include(event) ||
|
||||
agentOutputEvent.include(event) ||
|
||||
agentInputEvent.include(event) ||
|
||||
stopAgentEvent.include(event)
|
||||
) {
|
||||
console.log(event);
|
||||
} else if (event instanceof AgentStream) {
|
||||
console.log(event.data);
|
||||
} else if (agentStreamEvent.include(event)) {
|
||||
for (const chunk of event.data.delta) {
|
||||
process.stdout.write(chunk);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { openai } from "@llamaindex/openai";
|
||||
import { agent, tool } from "llamaindex";
|
||||
import { agent } from "@llamaindex/workflow";
|
||||
import { tool } from "llamaindex";
|
||||
import { z } from "zod";
|
||||
|
||||
const sumNumbers = tool({
|
||||
@@ -25,7 +26,7 @@ const divideNumbers = tool({
|
||||
async function main() {
|
||||
const mathAgent = agent({
|
||||
tools: [sumNumbers, divideNumbers],
|
||||
llm: openai({ model: "gpt-4o-mini" }),
|
||||
llm: openai({ model: "gpt-4.1-mini" }),
|
||||
verbose: false,
|
||||
});
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { openai } from "@llamaindex/openai";
|
||||
import {
|
||||
AgentStream,
|
||||
AgentToolCallResult,
|
||||
Document,
|
||||
VectorStoreIndex,
|
||||
agent,
|
||||
openai,
|
||||
} from "llamaindex";
|
||||
agentStreamEvent,
|
||||
agentToolCallResultEvent,
|
||||
} from "@llamaindex/workflow";
|
||||
import { Document, VectorStoreIndex } from "llamaindex";
|
||||
|
||||
async function main() {
|
||||
const index = await VectorStoreIndex.fromDocuments([
|
||||
@@ -30,15 +29,15 @@ async function main() {
|
||||
],
|
||||
});
|
||||
|
||||
const context = myAgent.run("The fact about cats");
|
||||
const events = myAgent.runStream("The fact about cats");
|
||||
|
||||
for await (const event of context) {
|
||||
if (event instanceof AgentToolCallResult) {
|
||||
for await (const event of events) {
|
||||
if (agentToolCallResultEvent.include(event)) {
|
||||
console.log(
|
||||
"Using these retrieved information to answer the question:\n",
|
||||
event.data.toolOutput.result,
|
||||
);
|
||||
} else if (event instanceof AgentStream) {
|
||||
} else if (agentStreamEvent.include(event)) {
|
||||
for (const chunk of event.data.delta) {
|
||||
process.stdout.write(chunk);
|
||||
}
|
||||
@@ -2,8 +2,8 @@
|
||||
* This example shows how to use a single agent with a tool
|
||||
*/
|
||||
import { openai } from "@llamaindex/openai";
|
||||
import { agent } from "llamaindex";
|
||||
import { getWeatherTool } from "../agent/utils/tools";
|
||||
import { agent } from "@llamaindex/workflow";
|
||||
import { getWeatherTool } from "../../deprecated/agents/utils/tools";
|
||||
|
||||
async function main() {
|
||||
const weatherAgent = agent({
|
||||
@@ -14,14 +14,14 @@ async function main() {
|
||||
verbose: false,
|
||||
});
|
||||
|
||||
// Run the agent and keep the context
|
||||
const context = weatherAgent.run("What's the weather like in San Francisco?");
|
||||
const result = await context;
|
||||
const result = await weatherAgent.run(
|
||||
"What's the weather like in San Francisco?",
|
||||
);
|
||||
console.log(`${JSON.stringify(result, null, 2)}`);
|
||||
|
||||
// Reuse the context from the previous run
|
||||
// Reuse the state from the previous run
|
||||
const caResult = await weatherAgent.run("Compare it with California?", {
|
||||
context: context.data,
|
||||
state: result.data.state,
|
||||
});
|
||||
console.log(`${JSON.stringify(caResult, null, 2)}`);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { OpenAI } from "@llamaindex/openai";
|
||||
import { wiki } from "@llamaindex/tools";
|
||||
import { AgentStream, agent } from "llamaindex";
|
||||
import { agent, agentStreamEvent } from "@llamaindex/workflow";
|
||||
|
||||
async function main() {
|
||||
const llm = new OpenAI({ model: "gpt-4-turbo" });
|
||||
@@ -12,10 +12,10 @@ async function main() {
|
||||
});
|
||||
|
||||
// Chat with the agent
|
||||
const context = workflow.run("Who was Goethe?");
|
||||
const events = workflow.runStream("Who was Goethe?");
|
||||
|
||||
for await (const event of context) {
|
||||
if (event instanceof AgentStream) {
|
||||
for await (const event of events) {
|
||||
if (agentStreamEvent.include(event)) {
|
||||
for (const chunk of event.data.delta) {
|
||||
process.stdout.write(chunk);
|
||||
}
|
||||
+11
-11
@@ -1,11 +1,11 @@
|
||||
import fs from "fs";
|
||||
import {
|
||||
agent,
|
||||
AgentToolCall,
|
||||
AgentToolCallResult,
|
||||
agentToolCallEvent,
|
||||
agentToolCallResultEvent,
|
||||
multiAgent,
|
||||
tool,
|
||||
} from "llamaindex";
|
||||
} from "@llamaindex/workflow";
|
||||
import fs from "fs";
|
||||
import { tool } from "llamaindex";
|
||||
import { z } from "zod";
|
||||
|
||||
import { anthropic } from "@llamaindex/anthropic";
|
||||
@@ -81,21 +81,21 @@ async function main() {
|
||||
rootAgent: researchAgent,
|
||||
});
|
||||
|
||||
const context = workflow.run(
|
||||
const events = workflow.runStream(
|
||||
"Write a report about New York weather and inflation",
|
||||
);
|
||||
|
||||
let finalResult;
|
||||
for await (const event of context) {
|
||||
if (event instanceof AgentToolCall) {
|
||||
for await (const event of events) {
|
||||
if (agentToolCallEvent.include(event)) {
|
||||
console.log(
|
||||
`[Agent ${event.displayName}] executing tool ${event.data.toolName} with parameters ${JSON.stringify(
|
||||
`[Agent ${event.data.agentName}] executing tool ${event.data.toolName} with parameters ${JSON.stringify(
|
||||
event.data.toolKwargs,
|
||||
)}`,
|
||||
);
|
||||
} else if (event instanceof AgentToolCallResult) {
|
||||
} else if (agentToolCallResultEvent.include(event)) {
|
||||
console.log(
|
||||
`[Agent ${event.displayName}] executed tool ${event.data.toolName} with result ${event.data.toolOutput.result}`,
|
||||
`[Agent executed tool ${event.data.toolName} with result ${event.data.toolOutput.result}`,
|
||||
);
|
||||
}
|
||||
finalResult = event;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user