Compare commits

..

6 Commits

Author SHA1 Message Date
Logan Markewich 32d74a5cff remove old workflow examples, we need to redo these anyways 2025-04-23 15:43:29 -07:00
Logan Markewich 1aeb2cb8a9 modernize module guide example 2025-04-23 15:43:29 -07:00
github-actions[bot] 6d7bc4ccbb Release (#1883)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: marcusschiesser <17126+marcusschiesser@users.noreply.github.com>
2025-04-23 17:24:54 +07:00
Huu Le 294f502441 feat: support SSE for MCP tools adapter (#1882) 2025-04-23 15:54:37 +07:00
github-actions[bot] 056594452c Release @llamaindex/readers@3.1.0 (#1880)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: marcusschiesser <17126+marcusschiesser@users.noreply.github.com>
2025-04-22 19:14:09 +07:00
Huu Le 1e59695cef Restructure reader packages (#1877)
Co-authored-by: Marcus Schiesser <mail@marcusschiesser.de>
2025-04-22 17:20:08 +07:00
64 changed files with 658 additions and 800 deletions
+7
View File
@@ -1,5 +1,12 @@
# @llamaindex/doc
## 0.2.14
### Patch Changes
- Updated dependencies [1e59695]
- @llamaindex/readers@3.1.0
## 0.2.13
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@llamaindex/doc",
"version": "0.2.13",
"version": "0.2.14",
"private": true,
"scripts": {
"postinstall": "fumadocs-mdx",
@@ -57,6 +57,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";
// 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.
@@ -2,149 +2,260 @@
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.
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.
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
npm i @llama-flow/core @llamaindex/openai
```
## Getting Started
As an illustrative example, let's consider a naive workflow where a joke is generated and then critiqued.
Let's explore a simple workflow example where a joke is generated and then critiqued and iterated on:
<include cwd>../../examples/workflow/joke.ts</include>
```typescript
import { OpenAI } from "@llamaindex/openai";
import { createWorkflow, workflowEvent } from "@llama-flow/core";
import { withStore } from "@llama-flow/core/middleware/store";
There's a few moving pieces here, so let's go through this piece by piece.
// Create LLM instance
const llm = new OpenAI({ model: "gpt-4.1-mini", apiKey: "..."});
// Define our workflow events
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
// Create our workflow
const jokeFlow = withStore(
() => ({
numIterations: 0,
maxIterations: 3,
}),
createWorkflow()
);
// Define handlers for each step
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 });
});
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 });
});
jokeFlow.handle([critiqueEvent], async (event) => {
// Keep track of the number of iterations
const store = jokeFlow.getStore();
store.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 (store.numIterations < store.maxIterations) {
return jokeEvent.with({ joke: joke });
}
return resultEvent.with({ joke: joke, critique: event.data.critique });
});
// Usage
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);
}
main().catch(console.error);
```
There are a few moving pieces here, so let's go through this step by step.
### Defining Workflow Events
```typescript
export class JokeEvent extends WorkflowEvent<{ joke: string }> {}
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 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`.
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 Class
### Setting up the Workflow with Store Middleware
```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
const jokeFlow = withStore(
() => ({
numIterations: 0,
maxIterations: 3,
}),
createWorkflow()
);
```
### Workflow Exit Points
Our workflow is implemented using the `createWorkflow()` function, enhanced with the `withStore` middleware. The store 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 store will be accesible within workflows by using the `jokeFlow.getStore()` 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
const critiqueJoke = async (_: unknown, ev: JokeEvent) => {
const prompt = `Give a thorough critique of the following joke: ${ev.data.joke}`;
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 });
return new StopEvent(response.text);
};
// Parse the joke from the response
const joke = response.text.match(/<joke>([\s\S]*?)<\/joke>/)?.[1]?.trim() ?? response.text;
return jokeEvent.with({ joke: joke });
});
```
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:
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.addStep(
{
inputs: [JokeEvent],
outputs: [StopEvent<string>],
},
critiqueJoke
);
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 store = jokeFlow.getStore();
store.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 (store.numIterations < store.maxIterations) {
return jokeEvent.with({ joke: joke });
}
return resultEvent.with({ joke: joke, critique: event.data.critique });
});
```
### Running the Workflow
```typescript
const result = await jokeFlow.run("pirates");
console.log(result.data.result);
```
async function main() {
const { stream, sendEvent } = jokeFlow.createContext();
sendEvent(startEvent.with("pirates"));
Lastly, we run the workflow. The `.run()` method is async, so we use await here to wait for the result.
let result: { joke: string, critique: string } | undefined;
## 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[];
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);
}
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
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
The context does more than just hold data, it also provides utilities to buffer and wait for multiple events.
### Using Stream Utilities
For example, you might have a step that waits for a query and retrieved nodes before synthesizing a response:
Workflows provide utility functions to make working with event streams easier:
```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 });
};
import { collect } from "@llama-flow/core/stream/consumer";
import { until } from "@llama-flow/core/stream/until";
// 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 collect(until(stream, resultEvent));
// The last event will be the resultEvent
const finalEvent = allEvents[allEvents.length - 1];
console.log(finalEvent.data); // Output the joke and critique
```
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.
The stream utilities make it easier to work with the asynchronous event flow. In this example, we use:
- `collect`: 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)
## Manually Triggering Events
You can combine these utilities with other stream operators like `filter` and `map` to create powerful processing pipelines.
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.
## Next Steps
## Examples
You can find many useful examples of using workflows in the [examples folder](https://github.com/run-llama/LlamaIndexTS/blob/main/examples/workflow).
To learn more about workflows, check out [the documentation in the tutorial section](../../../llamaflow).
@@ -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/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)
@@ -1,5 +1,12 @@
# @llamaindex/next-node-runtime
## 0.1.23
### Patch Changes
- Updated dependencies [1e59695]
- @llamaindex/readers@3.1.0
## 0.1.22
### Patch Changes
@@ -1,6 +1,6 @@
{
"name": "@llamaindex/next-node-runtime-test",
"version": "0.1.22",
"version": "0.1.23",
"private": true,
"scripts": {
"dev": "next dev",
+24
View File
@@ -1,5 +1,29 @@
# examples
## 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
+7 -3
View File
@@ -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 {
@@ -1,7 +1,7 @@
import {
AudioTranscriptReader,
TranscribeParams,
} from "@llamaindex/readers/assembly-ai";
} from "@llamaindex/assemblyai";
import { program } from "commander";
import { VectorStoreIndex } from "llamaindex";
import { stdin as input, stdout as output } from "node:process";
+3 -3
View File
@@ -1,11 +1,11 @@
import { CosmosClient } from "@azure/cosmos";
import { DefaultAzureCredential } from "@azure/identity";
import { AzureCosmosDBNoSQLConfig } from "@llamaindex/azure";
import { OpenAI, OpenAIEmbedding } from "@llamaindex/openai";
import {
AzureCosmosDBNoSQLConfig,
SimpleCosmosDBReader,
SimpleCosmosDBReaderLoaderConfig,
} from "@llamaindex/readers/cosmosdb";
} from "@llamaindex/azure";
import { OpenAI, OpenAIEmbedding } from "@llamaindex/openai";
import * as dotenv from "dotenv";
import {
Settings,
@@ -1,4 +1,4 @@
import { DiscordReader } from "@llamaindex/readers/discord";
import { DiscordReader } from "@llamaindex/discord";
async function main() {
// Create an instance of the DiscordReader. Set token here or DISCORD_TOKEN environment variable
+1 -1
View File
@@ -1,4 +1,4 @@
import { SimpleMongoReader } from "@llamaindex/readers/mongo";
import { SimpleMongoReader } from "@llamaindex/mongodb";
import { Document, VectorStoreIndex } from "llamaindex";
import { MongoClient } from "mongodb";
+4 -2
View File
@@ -1,5 +1,7 @@
import { MongoDBAtlasVectorSearch } from "@llamaindex/mongodb";
import { SimpleMongoReader } from "@llamaindex/readers/mongo";
import {
MongoDBAtlasVectorSearch,
SimpleMongoReader,
} from "@llamaindex/mongodb";
import * as dotenv from "dotenv";
import { storageContextFromDefaults, VectorStoreIndex } from "llamaindex";
import { MongoClient } from "mongodb";
@@ -1,4 +1,4 @@
import { NotionReader } from "@llamaindex/readers/notion";
import { NotionReader } from "@llamaindex/notion";
import { Client } from "@notionhq/client";
import { program } from "commander";
import { VectorStoreIndex } from "llamaindex";
@@ -8,8 +8,6 @@ import { createInterface } from "node:readline/promises";
program
.argument("[page]", "Notion page id (must be provided)")
.action(async (page, _options) => {
// Initializing a client
if (!process.env.NOTION_TOKEN) {
console.log(
"No NOTION_TOKEN found in environment variables. You will need to register an integration https://www.notion.com/my-integrations and put it in your NOTION_TOKEN environment variable.",
@@ -64,10 +62,8 @@ program
const documents = await reader.loadData(page);
console.log(documents);
// Split text and create embeddings. Store them in a VectorStoreIndex
const index = await VectorStoreIndex.fromDocuments(documents);
// Create query engine
const queryEngine = index.asQueryEngine();
const rl = createInterface({ input, output });
@@ -80,7 +76,6 @@ program
const response = await queryEngine.query({ query });
// Output response
console.log(response.toString());
}
});
+8 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@llamaindex/examples",
"version": "0.3.9",
"version": "0.3.11",
"private": true,
"scripts": {
"lint": "eslint .",
@@ -13,7 +13,7 @@
"@azure/search-documents": "^12.1.0",
"@llamaindex/anthropic": "^0.3.3",
"@llamaindex/astra": "^0.0.16",
"@llamaindex/azure": "^0.1.11",
"@llamaindex/azure": "^0.1.12",
"@llamaindex/chroma": "^0.0.16",
"@llamaindex/clip": "^0.0.52",
"@llamaindex/cloud": "^4.0.3",
@@ -28,7 +28,7 @@
"@llamaindex/milvus": "^0.1.11",
"@llamaindex/mistral": "^0.1.2",
"@llamaindex/mixedbread": "^0.0.16",
"@llamaindex/mongodb": "^0.0.16",
"@llamaindex/mongodb": "^0.0.17",
"@llamaindex/elastic-search": "^0.1.2",
"@llamaindex/node-parser": "^2.0.2",
"@llamaindex/ollama": "^0.1.2",
@@ -37,7 +37,7 @@
"@llamaindex/portkey-ai": "^0.0.44",
"@llamaindex/postgres": "^0.0.45",
"@llamaindex/qdrant": "^0.1.11",
"@llamaindex/readers": "^3.0.2",
"@llamaindex/readers": "^3.1.0",
"@llamaindex/replicate": "^0.0.44",
"@llamaindex/upstash": "^0.0.16",
"@llamaindex/vercel": "^0.1.2",
@@ -51,9 +51,12 @@
"@llamaindex/jinaai": "^0.0.12",
"@llamaindex/perplexity": "^0.0.9",
"@llamaindex/supabase": "^0.1.1",
"@llamaindex/tools": "^0.0.5",
"@llamaindex/tools": "^0.0.6",
"@notionhq/client": "^2.2.15",
"@pinecone-database/pinecone": "^4.0.0",
"@llamaindex/assemblyai": "^0.1.1",
"@llamaindex/discord": "^0.1.1",
"@llamaindex/notion": "^0.1.1",
"@vercel/postgres": "^0.10.0",
"ai": "^4.0.0",
"ajv": "^8.17.1",
-1
View File
@@ -11,7 +11,6 @@
"start:pdf": "node --import tsx ./src/pdf.ts",
"start:llamaparse": "node --import tsx ./src/llamaparse.ts",
"start:notion": "node --import tsx ./src/notion.ts",
"start:assemblyai": "node --import tsx ./src/assemblyai.ts",
"start:llamaparse-dir": "node --import tsx ./src/simple-directory-reader-with-llamaparse.ts",
"start:llamaparse-json": "node --import tsx ./src/llamaparse-json.ts",
"start:discord": "node --import tsx ./src/discord.ts",
-7
View File
@@ -1,7 +0,0 @@
# Workflow Examples
These examples demonstrate LlamaIndexTS's workflow system. Check out [its documentation](https://ts.llamaindex.ai/modules/workflows) for more information.
## Running the Examples
To run the examples, make sure to run them from the parent folder called `examples`). For example, to run the joke workflow, run `npx tsx workflow/joke.ts`.
-157
View File
@@ -1,157 +0,0 @@
import { OpenAI } from "@llamaindex/openai";
import {
HandlerContext,
StartEvent,
StopEvent,
Workflow,
WorkflowEvent,
} from "llamaindex";
const MAX_REVIEWS = 3;
type Context = {
specification: string;
numberReviews: number;
};
// Using the o1-preview model (see https://platform.openai.com/docs/guides/reasoning?reasoning-prompt-examples=coding-planning)
const llm = new OpenAI({ model: "o1-preview", temperature: 1 });
// example specification from https://platform.openai.com/docs/guides/reasoning?reasoning-prompt-examples=coding-planning
const specification = `Python app that takes user questions and looks them up in a
database where they are mapped to answers. If there is a close match, it retrieves
the matched answer. If there isn't, it asks the user to provide an answer and
stores the question/answer pair in the database.`;
// Create custom event types
export class MessageEvent extends WorkflowEvent<{ msg: string }> {}
export class CodeEvent extends WorkflowEvent<{ code: string }> {}
export class ReviewEvent extends WorkflowEvent<{
review: string;
code: string;
}> {}
// Helper function to truncate long strings
const truncate = (str: string) => {
const MAX_LENGTH = 60;
if (str.length <= MAX_LENGTH) return str;
return str.slice(0, MAX_LENGTH) + "...";
};
// the architect is responsible for writing the structure and the initial code based on the specification
const architect = async (
context: HandlerContext<Context>,
_: StartEvent<string>,
) => {
const spec = context.data.specification;
// write a message to send an update to the user
context.sendEvent(
new MessageEvent({
msg: `Writing app using this specification: ${truncate(spec)}`,
}),
);
const prompt = `Build an app for this specification: <spec>${spec}</spec>. Make a plan for the directory structure you'll need, then return each file in full. Don't supply any reasoning, just code.`;
const code = await llm.complete({ prompt });
return new CodeEvent({ code: code.text });
};
// the coder is responsible for updating the code based on the review
const coder = async (context: HandlerContext<Context>, ev: ReviewEvent) => {
// get the specification from the context
const spec = context.data.specification;
// get the latest review and code
const { review, code } = ev.data;
// write a message to send an update to the user
context.sendEvent(
new MessageEvent({
msg: `Update code based on review: ${truncate(review)}`,
}),
);
const prompt = `We need to improve code that should implement this specification: <spec>${spec}</spec>. Here is the current code: <code>${code}</code>. And here is a review of the code: <review>${review}</review>. Improve the code based on the review, keep the specification in mind, and return the full updated code. Don't supply any reasoning, just code.`;
const updatedCode = await llm.complete({ prompt });
return new CodeEvent({ code: updatedCode.text });
};
// the reviewer is responsible for reviewing the code and providing feedback
const reviewer = async (context: HandlerContext<Context>, ev: CodeEvent) => {
// get the specification from the context
const spec = context.data.specification;
// get latest code from the event
const { code } = ev.data;
// update and check the number of reviews
context.data.numberReviews++;
if (context.data.numberReviews > MAX_REVIEWS) {
// the we've done this too many times - return the code
context.sendEvent(
new MessageEvent({
msg: `Already reviewed ${
context.data.numberReviews - 1
} times, stopping!`,
}),
);
return new StopEvent({ result: code });
}
// write a message to send an update to the user
context.sendEvent(
new MessageEvent({
msg: `Review #${context.data.numberReviews}: ${truncate(code)}`,
}),
);
const prompt = `Review this code: <code>${code}</code>. Check if the code quality and whether it correctly implements this specification: <spec>${spec}</spec>. If you're satisfied, just return 'Looks great', nothing else. If not, return a review with a list of changes you'd like to see.`;
const review = (await llm.complete({ prompt })).text;
if (review.includes("Looks great")) {
// the reviewer is satisfied with the code, let's return the review
context.sendEvent(
new MessageEvent({
msg: `Reviewer says: ${review}`,
}),
);
return new StopEvent({ result: code });
}
return new ReviewEvent({ review, code });
};
const codeAgent = new Workflow<Context, string, string>();
codeAgent.addStep(
{
inputs: [StartEvent<string>],
outputs: [CodeEvent],
},
architect,
);
codeAgent.addStep(
{
inputs: [ReviewEvent],
outputs: [CodeEvent],
},
coder,
);
codeAgent.addStep(
{
inputs: [CodeEvent],
outputs: [ReviewEvent, StopEvent],
},
reviewer,
);
// Usage
async function main() {
const run = codeAgent.run(specification).with({
specification,
numberReviews: 0,
});
for await (const event of run) {
if (event instanceof MessageEvent) {
const msg = (event as MessageEvent).data.msg;
console.log(`${msg}\n`);
} else if (event instanceof StopEvent) {
const result = (event as StopEvent<string>).data;
console.log("Final code:\n", result);
}
}
}
main().catch(console.error);
-88
View File
@@ -1,88 +0,0 @@
import { OpenAI } from "@llamaindex/openai";
import {
HandlerContext,
StartEvent,
StopEvent,
Workflow,
WorkflowEvent,
} from "llamaindex";
// Create LLM instance
const llm = new OpenAI();
// Create custom event types
export class JokeEvent extends WorkflowEvent<{ joke: string }> {}
export class CritiqueEvent extends WorkflowEvent<{ critique: string }> {}
export class AnalysisEvent extends WorkflowEvent<{ analysis: string }> {}
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 });
};
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 CritiqueEvent({ critique: response.text });
};
const analyzeJoke = async (_: unknown, ev: JokeEvent) => {
const prompt = `Give a thorough analysis of the following joke: ${ev.data.joke}`;
const response = await llm.complete({ prompt });
return new AnalysisEvent({ analysis: response.text });
};
const reportJoke = async (
context: HandlerContext,
ev1: AnalysisEvent,
ev2: CritiqueEvent,
) => {
const subPrompts = [ev1.data.analysis, ev2.data.critique];
const prompt = `Based on the following information about a joke:\n${subPrompts.join(
"\n",
)}\nProvide a comprehensive report on the joke's quality and impact.`;
const response = await llm.complete({ prompt });
return new StopEvent(response.text);
};
const jokeFlow = new Workflow<unknown, string, string>();
jokeFlow.addStep(
{
inputs: [StartEvent<string>],
outputs: [JokeEvent],
},
generateJoke,
);
jokeFlow.addStep(
{
inputs: [JokeEvent],
outputs: [CritiqueEvent],
},
critiqueJoke,
);
jokeFlow.addStep(
{
inputs: [JokeEvent],
outputs: [AnalysisEvent],
},
analyzeJoke,
);
jokeFlow.addStep(
{
inputs: [AnalysisEvent, CritiqueEvent],
outputs: [StopEvent<string>],
},
reportJoke,
);
// Usage
async function main() {
const result = await jokeFlow.run("pirates");
console.log(result.data);
}
main().catch(console.error);
-44
View File
@@ -1,44 +0,0 @@
import { OpenAI } from "@llamaindex/openai";
import { StartEvent, StopEvent, Workflow, WorkflowEvent } from "llamaindex";
// Create LLM instance
const llm = new OpenAI();
// Create a custom event type
export class JokeEvent extends WorkflowEvent<{ joke: string }> {}
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 });
};
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);
};
const jokeFlow = new Workflow<unknown, string, string>();
jokeFlow.addStep(
{
inputs: [StartEvent<string>],
outputs: [JokeEvent],
},
generateJoke,
);
jokeFlow.addStep(
{
inputs: [JokeEvent],
outputs: [StopEvent<string>],
},
critiqueJoke,
);
// Usage
async function main() {
const result = await jokeFlow.run("pirates");
console.log(result.data);
}
main().catch(console.error);
-66
View File
@@ -1,66 +0,0 @@
import { OpenAI } from "@llamaindex/openai";
import {
HandlerContext,
StartEvent,
StopEvent,
Workflow,
WorkflowEvent,
} from "llamaindex";
// Create LLM instance
const llm = new OpenAI();
// Create custom event types
export class JokeEvent extends WorkflowEvent<{ joke: string }> {}
export class MessageEvent extends WorkflowEvent<{ msg: string }> {}
const generateJoke = async (context: HandlerContext, ev: StartEvent) => {
context.sendEvent(
new MessageEvent({ msg: `Generating a joke about: ${ev.data}` }),
);
const prompt = `Write your best joke about ${ev.data}.`;
const response = await llm.complete({ prompt });
return new JokeEvent({ joke: response.text });
};
const critiqueJoke = async (context: HandlerContext, ev: JokeEvent) => {
context.sendEvent(
new MessageEvent({ msg: `Write a critique of this joke: ${ev.data.joke}` }),
);
const prompt = `Give a thorough critique of the following joke: ${ev.data.joke}`;
const response = await llm.complete({ prompt });
return new StopEvent(response.text);
};
const jokeFlow = new Workflow();
jokeFlow.addStep(
{
inputs: [StartEvent<string>],
outputs: [JokeEvent],
},
generateJoke,
);
jokeFlow.addStep(
{
inputs: [JokeEvent],
outputs: [StopEvent<string>],
},
critiqueJoke,
);
// Usage
async function main() {
const run = jokeFlow.run("pirates");
for await (const event of run) {
if (event instanceof MessageEvent) {
console.log("Message:");
console.log((event as MessageEvent).data.msg);
} else if (event instanceof StopEvent) {
console.log("Result:");
console.log((event as StopEvent<string>).data);
}
}
}
main().catch(console.error);
-48
View File
@@ -1,48 +0,0 @@
import { StartEvent, StopEvent, Workflow } from "llamaindex";
const longRunning = async (_: unknown, ev: StartEvent<string>) => {
await new Promise((resolve) => setTimeout(resolve, 2000)); // Wait for 2 seconds
return new StopEvent("We waited 2 seconds");
};
async function timeout() {
const workflow = new Workflow<unknown, string, string>({
timeout: 1,
});
workflow.addStep(
{
inputs: [StartEvent<string>],
outputs: [StopEvent<string>],
},
longRunning,
);
try {
await workflow.run("Let's start");
} catch (error) {
console.error(error);
}
}
async function notimeout() {
// Increase timeout to 3 seconds - no timeout
const workflow = new Workflow<unknown, string, string>({
timeout: 3,
});
workflow.addStep(
{
inputs: [StartEvent<string>],
outputs: [StopEvent<string>],
},
longRunning,
);
const result = await workflow.run("Let's start");
console.log(result.data);
}
async function main() {
await timeout();
console.log("---");
await notimeout();
}
main().catch(console.error);
-73
View File
@@ -1,73 +0,0 @@
import { OpenAI } from "@llamaindex/openai";
import { StartEvent, StopEvent, Workflow, WorkflowEvent } from "llamaindex";
// Create LLM instance
const llm = new OpenAI();
// Create a custom event type
export class JokeEvent extends WorkflowEvent<{ joke: string }> {}
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 });
};
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);
};
async function validateFails() {
try {
const jokeFlow = new Workflow();
jokeFlow.addStep(
{
inputs: [StartEvent<string>],
outputs: [StopEvent<string>],
},
// @ts-expect-error outputs should be JokeEvent
generateJoke,
);
jokeFlow.addStep(
{
inputs: [JokeEvent],
outputs: [StopEvent],
},
critiqueJoke,
);
await jokeFlow.run("pirates").strict();
} catch (e) {
console.error("Validation failed:", e);
}
}
async function validate() {
const jokeFlow = new Workflow();
jokeFlow.addStep(
{
inputs: [StartEvent<string>],
outputs: [JokeEvent],
},
generateJoke,
);
jokeFlow.addStep(
{
inputs: [JokeEvent],
outputs: [StopEvent<string>],
},
critiqueJoke,
);
const result = await jokeFlow.run("pirates").strict();
console.log(result.data);
}
// Usage
async function main() {
await validateFails();
console.log("---");
await validate();
}
main().catch(console.error);
@@ -0,0 +1,7 @@
# @llamaindex/assemblyai
## 0.1.1
### Patch Changes
- 1e59695: Introduce an independent package for assemblyai
@@ -0,0 +1,32 @@
{
"name": "@llamaindex/assemblyai",
"description": "AssemblyAI Reader for LlamaIndex",
"version": "0.1.1",
"type": "module",
"types": "dist/index.d.ts",
"main": "dist/index.cjs",
"module": "dist/index.js",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"files": [
"dist"
],
"repository": {
"type": "git",
"url": "git+https://github.com/run-llama/LlamaIndexTS.git",
"directory": "packages/providers/assemblyai"
},
"scripts": {
"build": "bunchee",
"dev": "bunchee --watch"
},
"dependencies": {
"assemblyai": "^4.8.0",
"@llamaindex/core": "workspace:*",
"@llamaindex/env": "workspace:*"
}
}
@@ -0,0 +1 @@
export * from "./reader";
@@ -0,0 +1,19 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"outDir": "./lib",
"tsBuildInfoFile": "./lib/.tsbuildinfo"
},
"include": ["./src"],
"references": [
{
"path": "../../core/tsconfig.json"
},
{
"path": "../../env/tsconfig.json"
}
]
}
+7
View File
@@ -0,0 +1,7 @@
# @llamaindex/discord
## 0.1.1
### Patch Changes
- 1e59695: Introduce an independent package for discord
+33
View File
@@ -0,0 +1,33 @@
{
"name": "@llamaindex/discord",
"description": "Discord Reader for LlamaIndex",
"version": "0.1.1",
"type": "module",
"types": "dist/index.d.ts",
"main": "dist/index.cjs",
"module": "dist/index.js",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"files": [
"dist"
],
"repository": {
"type": "git",
"url": "git+https://github.com/run-llama/LlamaIndexTS.git",
"directory": "packages/providers/discord"
},
"scripts": {
"build": "bunchee",
"dev": "bunchee --watch"
},
"dependencies": {
"@discordjs/rest": "^2.3.0",
"discord-api-types": "^0.37.105",
"@llamaindex/core": "workspace:*",
"@llamaindex/env": "workspace:*"
}
}
+1
View File
@@ -0,0 +1 @@
export * from "./reader";
@@ -1,4 +1,3 @@
// todo: move to `providers`
import { REST, type RESTOptions } from "@discordjs/rest";
import { Document, type BaseReader } from "@llamaindex/core/schema";
import { getEnv } from "@llamaindex/env";
+19
View File
@@ -0,0 +1,19 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"outDir": "./lib",
"tsBuildInfoFile": "./lib/.tsbuildinfo"
},
"include": ["./src"],
"references": [
{
"path": "../../core/tsconfig.json"
},
{
"path": "../../env/tsconfig.json"
}
]
}
+7
View File
@@ -0,0 +1,7 @@
# @llamaindex/notion
## 0.1.1
### Patch Changes
- 1e59695: Introduce an independent package for notion
+32
View File
@@ -0,0 +1,32 @@
{
"name": "@llamaindex/notion",
"description": "Notion Reader for LlamaIndex",
"version": "0.1.1",
"type": "module",
"types": "dist/index.d.ts",
"main": "dist/index.cjs",
"module": "dist/index.js",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"files": [
"dist"
],
"repository": {
"type": "git",
"url": "git+https://github.com/run-llama/LlamaIndexTS.git",
"directory": "packages/providers/notion"
},
"scripts": {
"build": "bunchee",
"dev": "bunchee --watch"
},
"dependencies": {
"notion-md-crawler": "^1.0.0",
"@llamaindex/core": "workspace:*",
"@llamaindex/env": "workspace:*"
}
}
+1
View File
@@ -0,0 +1 @@
export * from "./reader";
+19
View File
@@ -0,0 +1,19 @@
{
"extends": "../../../tsconfig.json",
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"outDir": "./lib",
"tsBuildInfoFile": "./lib/.tsbuildinfo"
},
"include": ["./src"],
"references": [
{
"path": "../../core/tsconfig.json"
},
{
"path": "../../env/tsconfig.json"
}
]
}
@@ -1,5 +1,11 @@
# @llamaindex/azure
## 0.1.12
### Patch Changes
- 1e59695: Add CosmosDB reader
## 0.1.11
### Patch Changes
@@ -1,7 +1,7 @@
{
"name": "@llamaindex/azure",
"description": "Azure Storage for LlamaIndex",
"version": "0.1.11",
"version": "0.1.12",
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
@@ -7,3 +7,5 @@ export * from "./vectorStore/AzureCosmosDBNoSqlVectorStore.js";
export * from "./vectorStore/AzureQueryResultSearch.js";
export * from "./tools/AzureDynamicSessionTool.node.js";
export * from "./readers/index.js";
@@ -0,0 +1 @@
export * from "./cosmosdb";
@@ -1,10 +1,10 @@
import { CosmosClient } from "@azure/cosmos";
import { Document } from "@llamaindex/core/schema";
import { describe, expect, it, vi } from "vitest";
import {
SimpleCosmosDBReader,
type SimpleCosmosDBReaderLoaderConfig,
} from "@llamaindex/readers/cosmosdb";
import { describe, expect, it, vi } from "vitest";
} from "../src/readers/cosmosdb";
const createMockClient = (mockData?: unknown[]) => {
const client = {
@@ -1,5 +1,11 @@
# @llamaindex/mongodb
## 0.0.17
### Patch Changes
- 1e59695: Add MongoDB reader
## 0.0.16
### Patch Changes
@@ -1,7 +1,7 @@
{
"name": "@llamaindex/mongodb",
"description": "MongoDB Storage for LlamaIndex",
"version": "0.0.16",
"version": "0.0.17",
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
@@ -1,3 +1,4 @@
export * from "./docStore/MongoDBDocumentStore";
export * from "./kvStore/MongoKVStore";
export * from "./MongoDBAtlasVectorStore";
export * from "./readers/index.js";
@@ -0,0 +1 @@
export * from "./mongo";
@@ -1,4 +1,3 @@
// todo: should move to providers
import type { Metadata } from "@llamaindex/core/schema";
import { type BaseReader, Document } from "@llamaindex/core/schema";
import type { Filter, MongoClient, Document as MongoDocument } from "mongodb";
+6
View File
@@ -1,5 +1,11 @@
# @llamaindex/readers
## 3.1.0
### Minor Changes
- 1e59695: Move MongoDB, CosmosDB, AssemblyAI, Notion, and Discord to their own packages
## 3.0.2
### Patch Changes
-14
View File
@@ -1,14 +0,0 @@
{
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"edge-light": "./dist/index.edge-light.js",
"workerd": "./dist/index.workerd.js",
"default": "./dist/index.js"
}
},
"private": true
}
-14
View File
@@ -1,14 +0,0 @@
{
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"edge-light": "./dist/index.edge-light.js",
"workerd": "./dist/index.workerd.js",
"default": "./dist/index.js"
}
},
"private": true
}
-14
View File
@@ -1,14 +0,0 @@
{
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"edge-light": "./dist/index.edge-light.js",
"workerd": "./dist/index.workerd.js",
"default": "./dist/index.js"
}
},
"private": true
}
-14
View File
@@ -1,14 +0,0 @@
{
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"edge-light": "./dist/index.edge-light.js",
"workerd": "./dist/index.workerd.js",
"default": "./dist/index.js"
}
},
"private": true
}
-14
View File
@@ -1,14 +0,0 @@
{
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"edge-light": "./dist/index.edge-light.js",
"workerd": "./dist/index.workerd.js",
"default": "./dist/index.js"
}
},
"private": true
}
+1 -62
View File
@@ -1,31 +1,11 @@
{
"name": "@llamaindex/readers",
"description": "LlamaIndex Readers",
"version": "3.0.2",
"version": "3.1.0",
"type": "module",
"exports": {
"./node/hook": "./node/dist/hook.js",
"./node": "./node/dist/index.js",
"./assembly-ai": {
"require": {
"types": "./assembly-ai/dist/index.d.cts",
"default": "./assembly-ai/dist/index.cjs"
},
"import": {
"types": "./assembly-ai/dist/index.d.ts",
"default": "./assembly-ai/dist/index.js"
}
},
"./cosmosdb": {
"require": {
"types": "./cosmosdb/dist/index.d.cts",
"default": "./cosmosdb/dist/index.cjs"
},
"import": {
"types": "./cosmosdb/dist/index.d.ts",
"default": "./cosmosdb/dist/index.js"
}
},
"./csv": {
"edge-light": {
"types": "./csv/dist/index.edge-light.d.ts",
@@ -62,16 +42,6 @@
"default": "./directory/dist/index.js"
}
},
"./discord": {
"require": {
"types": "./discord/dist/index.d.cts",
"default": "./discord/dist/index.cjs"
},
"import": {
"types": "./discord/dist/index.d.ts",
"default": "./discord/dist/index.js"
}
},
"./docx": {
"require": {
"types": "./docx/dist/index.d.cts",
@@ -122,26 +92,6 @@
"default": "./markdown/dist/index.js"
}
},
"./mongo": {
"require": {
"types": "./mongo/dist/index.d.cts",
"default": "./mongo/dist/index.cjs"
},
"import": {
"types": "./mongo/dist/index.d.ts",
"default": "./mongo/dist/index.js"
}
},
"./notion": {
"require": {
"types": "./notion/dist/index.d.cts",
"default": "./notion/dist/index.cjs"
},
"import": {
"types": "./notion/dist/index.d.ts",
"default": "./notion/dist/index.js"
}
},
"./obsidian": {
"edge-light": {
"types": "./obsidian/dist/index.edge-light.d.ts",
@@ -182,18 +132,13 @@
}
},
"files": [
"assembly-ai",
"cosmosdb",
"csv",
"directory",
"discord",
"docx",
"html",
"image",
"json",
"markdown",
"mongo",
"notion",
"obsidian",
"pdf",
"text",
@@ -220,15 +165,9 @@
"@llamaindex/env": "workspace:*"
},
"dependencies": {
"@azure/cosmos": "^4.1.1",
"@discordjs/rest": "^2.3.0",
"@discoveryjs/json-ext": "^0.6.1",
"assemblyai": "^4.8.0",
"csv-parse": "^5.5.6",
"discord-api-types": "^0.37.105",
"mammoth": "^1.7.2",
"mongodb": "^6.7.0",
"notion-md-crawler": "^1.0.0",
"unpdf": "^0.12.1"
}
}
+6
View File
@@ -1,5 +1,11 @@
# @llamaindex/tools
## 0.0.6
### Patch Changes
- 294f502: Support SSE for MCP tools adapter
## 0.0.5
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@llamaindex/tools",
"description": "LlamaIndex Tools",
"version": "0.0.5",
"version": "0.0.6",
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
+35 -6
View File
@@ -2,6 +2,10 @@ import type { JSONValue } from "@llamaindex/core/global";
import type { BaseToolWithCall } from "@llamaindex/core/llms";
import { FunctionTool } from "@llamaindex/core/tools";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import {
SSEClientTransport,
type SSEClientTransportOptions,
} from "@modelcontextprotocol/sdk/client/sse.js";
import {
StdioClientTransport,
type StdioServerParameters,
@@ -13,7 +17,7 @@ interface ToolInput {
[key: string]: unknown;
}
type MCPClientOptions = StdioServerParameters & {
type MCPCommonOptions = {
/**
* The prefix to add to the tool name
*/
@@ -32,11 +36,20 @@ type MCPClientOptions = StdioServerParameters & {
verbose?: boolean;
};
type StdioMCPClientOptions = StdioServerParameters & MCPCommonOptions;
type SSEMCPClientOptions = SSEClientTransportOptions &
MCPCommonOptions & {
url: string;
};
type MCPClientOptions = StdioMCPClientOptions | SSEMCPClientOptions;
class MCPClient {
private mcp: Client;
private transport: StdioClientTransport | null = null;
private transport: StdioClientTransport | SSEClientTransport | null = null;
private verbose: boolean;
private toolNamePrefix?: string | undefined;
private connected: boolean = false;
constructor(options: MCPClientOptions) {
this.mcp = new Client({
@@ -46,18 +59,34 @@ class MCPClient {
this.verbose = options.verbose ?? false;
this.toolNamePrefix = options.toolNamePrefix;
this.connectToSever(options);
if ("url" in options) {
this.transport = new SSEClientTransport(
new URL(options.url),
options as SSEClientTransportOptions,
);
} else {
this.transport = new StdioClientTransport(
options as StdioServerParameters,
);
}
this.connected = false;
}
async connectToSever(options: StdioServerParameters) {
async connectToSever() {
if (this.verbose) {
console.log("Connecting to MCP server...");
}
this.transport = new StdioClientTransport(options);
if (!this.transport) {
throw new Error("Initialized with invalid options");
}
await this.mcp.connect(this.transport);
this.connected = true;
}
async listTools(): Promise<Tool[]> {
private async listTools(): Promise<Tool[]> {
if (!this.connected) {
await this.connectToSever();
}
const tools = await this.mcp.listTools();
return tools.tools;
}
+74 -27
View File
@@ -611,11 +611,14 @@ importers:
'@llamaindex/anthropic':
specifier: ^0.3.3
version: link:../packages/providers/anthropic
'@llamaindex/assemblyai':
specifier: ^0.1.1
version: link:../packages/providers/assemblyai
'@llamaindex/astra':
specifier: ^0.0.16
version: link:../packages/providers/storage/astra
'@llamaindex/azure':
specifier: ^0.1.11
specifier: ^0.1.12
version: link:../packages/providers/storage/azure
'@llamaindex/chroma':
specifier: ^0.0.16
@@ -638,6 +641,9 @@ importers:
'@llamaindex/deepseek':
specifier: ^0.0.12
version: link:../packages/providers/deepseek
'@llamaindex/discord':
specifier: ^0.1.1
version: link:../packages/providers/discord
'@llamaindex/elastic-search':
specifier: ^0.1.2
version: link:../packages/providers/storage/elastic-search
@@ -672,11 +678,14 @@ importers:
specifier: ^0.0.16
version: link:../packages/providers/mixedbread
'@llamaindex/mongodb':
specifier: ^0.0.16
specifier: ^0.0.17
version: link:../packages/providers/storage/mongodb
'@llamaindex/node-parser':
specifier: ^2.0.2
version: link:../packages/node-parser
'@llamaindex/notion':
specifier: ^0.1.1
version: link:../packages/providers/notion
'@llamaindex/ollama':
specifier: ^0.1.2
version: link:../packages/providers/ollama
@@ -699,7 +708,7 @@ importers:
specifier: ^0.1.11
version: link:../packages/providers/storage/qdrant
'@llamaindex/readers':
specifier: ^3.0.2
specifier: ^3.1.0
version: link:../packages/readers
'@llamaindex/replicate':
specifier: ^0.0.44
@@ -711,7 +720,7 @@ importers:
specifier: ^0.0.12
version: link:../packages/providers/together
'@llamaindex/tools':
specifier: ^0.0.5
specifier: ^0.0.6
version: link:../packages/tools
'@llamaindex/upstash':
specifier: ^0.0.16
@@ -1102,6 +1111,18 @@ importers:
specifier: ^2.1.5
version: 2.1.5(@edge-runtime/vm@5.0.0)(@types/node@22.14.1)(happy-dom@17.4.4)(lightningcss@1.29.3)(msw@2.7.4(@types/node@22.14.1)(typescript@5.8.3))(terser@5.39.0)
packages/providers/assemblyai:
dependencies:
'@llamaindex/core':
specifier: workspace:*
version: link:../../core
'@llamaindex/env':
specifier: workspace:*
version: link:../../env
assemblyai:
specifier: ^4.8.0
version: 4.9.0(bufferutil@4.0.9)
packages/providers/clip:
dependencies:
'@huggingface/transformers':
@@ -1150,6 +1171,21 @@ importers:
specifier: workspace:*
version: link:../openai
packages/providers/discord:
dependencies:
'@discordjs/rest':
specifier: ^2.3.0
version: 2.4.3
'@llamaindex/core':
specifier: workspace:*
version: link:../../core
'@llamaindex/env':
specifier: workspace:*
version: link:../../env
discord-api-types:
specifier: ^0.37.105
version: 0.37.120
packages/providers/fireworks:
dependencies:
'@llamaindex/env':
@@ -1247,6 +1283,18 @@ importers:
specifier: ^2.2.11
version: 2.2.11
packages/providers/notion:
dependencies:
'@llamaindex/core':
specifier: workspace:*
version: link:../../core
'@llamaindex/env':
specifier: workspace:*
version: link:../../env
notion-md-crawler:
specifier: ^1.0.0
version: 1.0.1
packages/providers/ollama:
dependencies:
'@llamaindex/core':
@@ -1603,33 +1651,15 @@ importers:
packages/readers:
dependencies:
'@azure/cosmos':
specifier: ^4.1.1
version: 4.3.0
'@discordjs/rest':
specifier: ^2.3.0
version: 2.4.3
'@discoveryjs/json-ext':
specifier: ^0.6.1
version: 0.6.3
assemblyai:
specifier: ^4.8.0
version: 4.9.0(bufferutil@4.0.9)
csv-parse:
specifier: ^5.5.6
version: 5.6.0
discord-api-types:
specifier: ^0.37.105
version: 0.37.120
mammoth:
specifier: ^1.7.2
version: 1.9.0
mongodb:
specifier: ^6.7.0
version: 6.7.0(@aws-sdk/credential-providers@3.787.0)(socks@2.8.4)
notion-md-crawler:
specifier: ^1.0.0
version: 1.0.1
unpdf:
specifier: ^0.12.1
version: 0.12.1
@@ -10441,6 +10471,7 @@ packages:
node-domexception@1.0.0:
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
engines: {node: '>=10.5.0'}
deprecated: Use your platform's native DOMException instead
node-fetch-native@1.6.6:
resolution: {integrity: sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==}
@@ -20773,7 +20804,7 @@ snapshots:
'@typescript-eslint/parser': 8.30.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)
eslint: 9.22.0(jiti@2.4.2)
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@9.22.0(jiti@2.4.2))
eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.30.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2))
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.30.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-typescript@3.7.0)(eslint@9.22.0(jiti@2.4.2))
eslint-plugin-jsx-a11y: 6.10.2(eslint@9.22.0(jiti@2.4.2))
eslint-plugin-react: 7.37.2(eslint@9.22.0(jiti@2.4.2))
@@ -20803,6 +20834,22 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.30.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)):
dependencies:
'@nolyfill/is-core-module': 1.0.39
debug: 4.4.0
enhanced-resolve: 5.18.1
eslint: 9.22.0(jiti@2.4.2)
fast-glob: 3.3.3
get-tsconfig: 4.10.0
is-bun-module: 1.3.0
is-glob: 4.0.3
stable-hash: 0.0.4
optionalDependencies:
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.30.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-typescript@3.7.0)(eslint@9.22.0(jiti@2.4.2))
transitivePeerDependencies:
- supports-color
eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0)(eslint@9.16.0(jiti@2.4.2)):
dependencies:
'@nolyfill/is-core-module': 1.0.39
@@ -20831,7 +20878,7 @@ snapshots:
is-glob: 4.0.3
stable-hash: 0.0.4
optionalDependencies:
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.30.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-typescript@3.7.0)(eslint@9.22.0(jiti@2.4.2))
eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.30.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.7.3))(eslint-import-resolver-typescript@3.7.0)(eslint@9.22.0(jiti@2.4.2))
transitivePeerDependencies:
- supports-color
@@ -20857,14 +20904,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-module-utils@2.12.0(@typescript-eslint/parser@8.30.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@9.22.0(jiti@2.4.2)):
eslint-module-utils@2.12.0(@typescript-eslint/parser@8.30.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.30.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)):
dependencies:
debug: 3.2.7
optionalDependencies:
'@typescript-eslint/parser': 8.30.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3)
eslint: 9.22.0(jiti@2.4.2)
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0)(eslint@9.22.0(jiti@2.4.2))
eslint-import-resolver-typescript: 3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.30.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2))
transitivePeerDependencies:
- supports-color
@@ -20937,7 +20984,7 @@ snapshots:
doctrine: 2.1.0
eslint: 9.22.0(jiti@2.4.2)
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.30.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0)(eslint@9.22.0(jiti@2.4.2))
eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.30.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.7.0(eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.30.1(eslint@9.22.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2)))(eslint@9.22.0(jiti@2.4.2))
hasown: 2.0.2
is-core-module: 2.16.1
is-glob: 4.0.3
+7
View File
@@ -1,5 +1,12 @@
# @llamaindex/unit-test
## 0.1.23
### Patch Changes
- Updated dependencies [1e59695]
- @llamaindex/readers@3.1.0
## 0.1.22
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@llamaindex/unit-test",
"private": true,
"version": "0.1.22",
"version": "0.1.23",
"type": "module",
"scripts": {
"test": "vitest run"