mirror of
https://github.com/run-llama/workflows-ts.git
synced 2026-07-21 06:05:23 -04:00
some docs fixes (#128)
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@llamaindex/workflow-docs": patch
|
||||
---
|
||||
|
||||
Ensure examples can run
|
||||
@@ -46,17 +46,21 @@ workflow.handle([booleanEvent], (event) => {
|
||||
});
|
||||
});
|
||||
|
||||
// Run the workflow
|
||||
const { stream, sendEvent } = workflow.createContext();
|
||||
const main = async () => {
|
||||
// Run the workflow
|
||||
const { stream, sendEvent } = workflow.createContext();
|
||||
|
||||
sendEvent(textEvent.with("Hello, world!"));
|
||||
sendEvent(textEvent.with("Hello, world!"));
|
||||
|
||||
for await (const event of stream) {
|
||||
if (complexEvent.include(event)) {
|
||||
console.log(event.data);
|
||||
break;
|
||||
for await (const event of stream) {
|
||||
if (complexEvent.include(event)) {
|
||||
console.log(event.data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void main().catch(console.error);
|
||||
```
|
||||
|
||||
### Event Branching and Merging
|
||||
@@ -240,13 +244,11 @@ workflow.handle([initEvent], async (event) => {
|
||||
}
|
||||
|
||||
// Collect transformed events
|
||||
const limit = event.data;
|
||||
let numResults = 0;
|
||||
const results = await stream
|
||||
.filter(transformedEvent)
|
||||
.until((event) => {
|
||||
numResults++;
|
||||
return numResults >= event.data;
|
||||
})
|
||||
.until(() => ++numResults >= limit)
|
||||
.toArray();
|
||||
|
||||
return resultEvent.with(results.map((r) => r.data));
|
||||
|
||||
@@ -157,6 +157,7 @@ LlamaIndex workflows provide middleware that can enhance your workflows:
|
||||
The `withState` middleware adds a persistent state to your workflow context:
|
||||
|
||||
```ts
|
||||
import { createWorkflow, workflowEvent } from "@llamaindex/workflow-core";
|
||||
import { createStatefulMiddleware } from "@llamaindex/workflow-core/middleware/state";
|
||||
|
||||
// Define your state type
|
||||
@@ -165,11 +166,17 @@ type CounterState = {
|
||||
history: number[];
|
||||
};
|
||||
|
||||
// Create a workflow with state middleware
|
||||
const { withState } = createStatefulMiddleware<CounterState>(() => ({
|
||||
count: 0,
|
||||
history: [],
|
||||
}));
|
||||
// Define events
|
||||
const startEvent = workflowEvent<void>();
|
||||
const incrementEvent = workflowEvent<number>();
|
||||
const resultEvent = workflowEvent<number>();
|
||||
|
||||
const { withState, getContext } = createStatefulMiddleware<CounterState>(
|
||||
() => ({
|
||||
count: 0,
|
||||
history: [],
|
||||
}),
|
||||
);
|
||||
|
||||
const workflow = withState(createWorkflow());
|
||||
|
||||
|
||||
+28
-21
@@ -37,30 +37,34 @@ With [workflowEvent](#) and [createWorkflow](#), you can create a simple workflo
|
||||
import { OpenAI } from "openai";
|
||||
import { createWorkflow, workflowEvent } from "@llamaindex/workflow-core";
|
||||
|
||||
const openai = new OpenAI({
|
||||
apiKey: process.env.OPENAI_API_KEY,
|
||||
});
|
||||
|
||||
const startEvent = workflowEvent<string>();
|
||||
const stopEvent = workflowEvent<string>();
|
||||
|
||||
const workflow = createWorkflow();
|
||||
|
||||
workflow.handle([startEvent], async (event) => {
|
||||
const response = await openai.chat.completions.create({
|
||||
// ...
|
||||
messages: [{ role: "user", content: event.data }],
|
||||
const main = async () => {
|
||||
const openai = new OpenAI({
|
||||
apiKey: process.env.OPENAI_API_KEY,
|
||||
});
|
||||
|
||||
return stopEvent(response.choices[0].message.content);
|
||||
});
|
||||
const startEvent = workflowEvent<string>();
|
||||
const stopEvent = workflowEvent<string>();
|
||||
|
||||
workflow.handle([stopEvent], (event) => {
|
||||
console.log("Response:", event.data);
|
||||
});
|
||||
const workflow = createWorkflow();
|
||||
|
||||
const { sendEvent } = workflow.createContext();
|
||||
sendEvent(startEvent.with("Hello, Workflows!"));
|
||||
workflow.handle([startEvent], async (event) => {
|
||||
const response = await openai.chat.completions.create({
|
||||
model: "gpt-4.1-mini",
|
||||
messages: [{ role: "user", content: event.data }],
|
||||
});
|
||||
|
||||
return stopEvent.with(response.choices[0].message.content ?? "");
|
||||
});
|
||||
|
||||
workflow.handle([stopEvent], (event) => {
|
||||
console.log("Response:", event.data);
|
||||
});
|
||||
|
||||
const { sendEvent } = workflow.createContext();
|
||||
sendEvent(startEvent.with("Hello, Workflows!"));
|
||||
};
|
||||
|
||||
void main().catch(console.error);
|
||||
```
|
||||
|
||||
## Parallel processing with async handlers
|
||||
@@ -71,7 +75,11 @@ Tool calls are a common pattern in LLM applications, where the model generates a
|
||||
|
||||
Workflows provide [abort signals](#) and [parallel processing](#) out of the box.
|
||||
|
||||
For example, imagine you have a workflow handler for calling tools that an agent has selection:
|
||||
|
||||
```ts
|
||||
import { getContext } from "@llamaindex/workflow-core";
|
||||
|
||||
workflow.handle([toolCallEvent], ({ data: { id, name, args } }) => {
|
||||
const { signal, sendEvent } = getContext();
|
||||
signal.onabort = () =>
|
||||
@@ -82,7 +90,6 @@ workflow.handle([toolCallEvent], ({ data: { id, name, args } }) => {
|
||||
content: "ERROR WHILE CALLING FUNCTION" + signal.reason.message,
|
||||
}),
|
||||
);
|
||||
|
||||
const result = callFunction(name, args);
|
||||
return toolCallResultEvent.with({
|
||||
role: "tool",
|
||||
|
||||
@@ -24,15 +24,6 @@ import {
|
||||
} from "llamaindex";
|
||||
import { OpenAI, OpenAIEmbedding } from "@llamaindex/openai";
|
||||
|
||||
// Define events
|
||||
const queryEvent = workflowEvent<string>();
|
||||
const retrieveEvent = workflowEvent<{ query: string; nodes: BaseNode[] }>();
|
||||
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",
|
||||
@@ -44,76 +35,89 @@ 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.",
|
||||
}),
|
||||
];
|
||||
const main = async () => {
|
||||
// Define events
|
||||
const queryEvent = workflowEvent<string>();
|
||||
const retrieveEvent = workflowEvent<{ query: string; nodes: BaseNode[] }>();
|
||||
const generateEvent = workflowEvent<{ query: string; context: string }>();
|
||||
const responseEvent = workflowEvent<string>();
|
||||
|
||||
// Create vector store index
|
||||
const index = await VectorStoreIndex.fromDocuments(documents);
|
||||
// Create workflow
|
||||
const workflow = createWorkflow();
|
||||
|
||||
// Handle query: Retrieve relevant documents
|
||||
workflow.handle([queryEvent], async (event) => {
|
||||
const query = event.data;
|
||||
console.log(`Processing query: ${query}`);
|
||||
// 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.",
|
||||
}),
|
||||
];
|
||||
|
||||
// Retrieve relevant documents
|
||||
const retriever = index.asRetriever();
|
||||
const nodes = await retriever.retrieve(query);
|
||||
// Create vector store index
|
||||
const index = await VectorStoreIndex.fromDocuments(documents);
|
||||
|
||||
return retrieveEvent.with({
|
||||
query,
|
||||
nodes: nodes.map((node) => node.node),
|
||||
// Handle query: Retrieve relevant documents
|
||||
workflow.handle([queryEvent], async (event) => {
|
||||
const query = event.data;
|
||||
console.log(`Processing query: ${query}`);
|
||||
|
||||
// Retrieve relevant documents
|
||||
const retriever = index.asRetriever();
|
||||
const nodes = await retriever.retrieve(query);
|
||||
|
||||
return retrieveEvent.with({
|
||||
query,
|
||||
nodes: nodes.map((node) => node.node),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Handle retrieval results: Generate response
|
||||
workflow.handle([retrieveEvent], async (event) => {
|
||||
const { query, nodes } = event.data;
|
||||
// Handle retrieval results: Generate response
|
||||
workflow.handle([retrieveEvent], async (event) => {
|
||||
const { query, nodes } = event.data;
|
||||
|
||||
// Combine document content as context
|
||||
const context = nodes
|
||||
.map((node) => node.getContent(MetadataMode.NONE))
|
||||
.join("\n\n");
|
||||
// Combine document content as context
|
||||
const context = nodes
|
||||
.map((node) => node.getContent(MetadataMode.NONE))
|
||||
.join("\n\n");
|
||||
|
||||
return generateEvent.with({ query, context });
|
||||
});
|
||||
return generateEvent.with({ query, context });
|
||||
});
|
||||
|
||||
// Handle generation: Produce final response
|
||||
workflow.handle([generateEvent], async (event) => {
|
||||
const { query, context } = event.data;
|
||||
// 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}
|
||||
// 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}
|
||||
`;
|
||||
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 });
|
||||
// Generate response with LLM
|
||||
const response = await Settings.llm.complete({ prompt });
|
||||
|
||||
return responseEvent.with(response.text);
|
||||
});
|
||||
return responseEvent.with(response.text);
|
||||
});
|
||||
|
||||
// Execute the workflow
|
||||
const { stream, sendEvent } = workflow.createContext();
|
||||
sendEvent(queryEvent.with("What is LlamaIndex?"));
|
||||
// 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;
|
||||
// Process the stream
|
||||
for await (const event of stream) {
|
||||
if (responseEvent.include(event)) {
|
||||
console.log("Final response:", event.data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void main().catch(console.error);
|
||||
```
|
||||
|
||||
## Building an Tool Calling Agent
|
||||
@@ -126,10 +130,10 @@ import {
|
||||
Settings,
|
||||
Document,
|
||||
VectorStoreIndex,
|
||||
agent, // Import the agent factory
|
||||
tool, // Import the tool factory
|
||||
QueryEngineTool, // Specific tool type for query engines
|
||||
} from "llamaindex";
|
||||
import { agent } from "@llamaindex/workflow"; // Import the agent factory
|
||||
import { OpenAI, OpenAIEmbedding } from "@llamaindex/openai";
|
||||
// import { SimpleDirectoryReader } from "@llamaindex/readers/directory"; // If loading from files
|
||||
import { z } from "zod"; // For defining tool parameters
|
||||
|
||||
@@ -83,16 +83,20 @@ workflow.handle([startEvent], () => {
|
||||
return resultEvent.with("Complete");
|
||||
});
|
||||
|
||||
// Run the workflow and collect events until a condition is met
|
||||
const { stream, sendEvent } = workflow.createContext();
|
||||
sendEvent(startEvent.with());
|
||||
const main = async () => {
|
||||
// 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 progressEvents = await stream
|
||||
.until(resultEvent)
|
||||
.filter(progressEvent)
|
||||
.toArray();
|
||||
console.log(`Received ${progressEvents.length} progress updates`);
|
||||
// Collect all events until resultEvent is encountered
|
||||
const progressEvents = await stream
|
||||
.until(resultEvent)
|
||||
.filter(progressEvent)
|
||||
.toArray();
|
||||
console.log(`Received ${progressEvents.length} progress updates`);
|
||||
};
|
||||
|
||||
void main().catch(console.error);
|
||||
```
|
||||
|
||||
## Conditional Stream Processing
|
||||
@@ -128,26 +132,30 @@ workflow.handle([startEvent], (event) => {
|
||||
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 main = async () => {
|
||||
// Run the workflow
|
||||
const { stream, sendEvent } = workflow.createContext();
|
||||
sendEvent(startEvent.with(100)); // Generate 100 numbers
|
||||
|
||||
const results = [];
|
||||
let hitThreshold = false;
|
||||
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
|
||||
// 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"}`,
|
||||
);
|
||||
console.log(
|
||||
`Collected ${results.length} items before ${hitThreshold ? "hitting threshold" : "completion"}`,
|
||||
);
|
||||
};
|
||||
|
||||
void main().catch(console.error);
|
||||
```
|
||||
|
||||
## Integration with UI Frameworks
|
||||
|
||||
Reference in New Issue
Block a user