feat: use agent to handle a workflow step (#2014)

Co-authored-by: Marcus Schiesser <mail@marcusschiesser.de>
This commit is contained in:
Huu Le
2025-06-12 16:06:13 +07:00
committed by GitHub
parent 1b5af1402d
commit 8a51c167f8
13 changed files with 721 additions and 30 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"@llamaindex/doc": patch
---
Add natural language agent page
+5
View File
@@ -0,0 +1,5 @@
---
"@llamaindex/workflow": patch
---
add agentHandler to handle a workflow steps using natural language.
@@ -1,4 +1,4 @@
{
"title": "Agents",
"pages": ["tool", "agent_workflow", "workflows"]
"pages": ["tool", "agent_workflow", "workflows", "natural_language_workflow"]
}
@@ -0,0 +1,103 @@
---
title: Define workflows using natural language
---
When working with Workflows, you have to write code to handle an event in the workflow.
Often, the logic of the handler is not too complex so that it can be expressed using natural language and executed by an LLM.
Besides the instructions, we just need the expected result event of the step, possible tool calls and optionally other events that can be emitted.
## Usage
Let's take an example of a workflow that generates a joke, gets a critique for it, and then improves it.
### Define the events
First, we define the events for our workflow. We need one for writing the joke, one for critiquing it, and one for the final result:
```typescript
import { z } from "zod";
import { zodEvent } from "@llamaindex/workflow";
const writeJokeSchema = z.object({
description: z
.string()
.describe("The topic to write a joke or describe the joke to improve."),
writtenJoke: z.optional(z.string()).describe("The written joke."),
retriedTimes: z
.number()
.default(0)
.describe(
"The retried times for writing the joke. Always increase this from the input retriedTimes.",
),
});
const critiqueSchema = z.object({
joke: z.string().describe("The joke to critique"),
retriedTimes: z.number().describe("The retried times for writing the joke."),
});
const finalResultSchema = z.object({
joke: z.string().describe("The joke to critique"),
critique: z.string().describe("The critique of the joke"),
});
const writeJokeEvent = zodEvent(writeJokeSchema, {
debugLabel: "writeJokeEvent",
});
const critiqueEvent = zodEvent(critiqueSchema, {
debugLabel: "critiqueEvent",
});
const finalResultEvent = zodEvent(finalResultSchema, {
debugLabel: "finalResultEvent",
});
```
Note that your natural language workflows the events need to be created by the `zodEvent` function passing the zod schema as an argument. The agent needs the schema of the event data to correctly generate events.
Also, we need a `debugLabel` so the LLM can identify the event to emit in the workflow.
### Define the workflow
As usual you first create the workflow:
```typescript
import { agentHandler, createWorkflow } from "@llamaindex/workflow";
const jokeFlow = createWorkflow();
```
Then you need to handle the events. For the handlers, instead of code, you're now going to use natural language by calling the `agentHandler` function.
It only requires two parameters:
- `instructions`: A prompt to guide the agent how to handle the steps.
- `results`: The output events that the agent should return after handling the step.
Then you will have a simple code to handle the step:
```typescript
jokeFlow.handle(
[writeJokeEvent],
agentHandler({
instructions: `You are a joke writer. You are given a topic and you need to write a joke about it.`,
results: [critiqueEvent],
}),
);
jokeFlow.handle(
[critiqueEvent],
agentHandler({
instructions: `
You are given a joke and you need to critique it. Follow the following guidelines:
1. You have maximum 3 times to improve the joke.
2. If the joke is not good, increase the retriedTimes, describe how to improve the joke and send a writeJokeEvent.
3. If the joke is good, trigger the finalResultEvent event.
`,
results: [writeJokeEvent, finalResultEvent],
}),
);
```
For advanced usage, you can add more functionality to `agentHandler` by using these parameters:
- `events`: A list of additional events that the agent can emit to the workflow. E.g., your agent can emit a `uiEvent` to update the UI during the execution.
- `tools`: A list of tools that the agent can use to handle the step. E.g., your agent can use a `search` tool to search the web.
You can find more code examples in the [examples](https://github.com/run-llama/LlamaIndexTS/tree/main/examples/agents/natural) folder.
+130
View File
@@ -0,0 +1,130 @@
import { ToolCallLLM } from "llamaindex";
import {
agentHandler,
createWorkflow,
workflowEvent,
zodEvent,
} from "@llamaindex/workflow";
import { openai } from "@llamaindex/openai";
import { z } from "zod";
// ===== 1. Define events =====
// An event to trigger the workflow
const planEvent = workflowEvent<{ topic: string }>();
// Generate artifact event
const ArtifactRequirementSchema = z.object({
type: z.literal("markdown"),
title: z.string().describe("The title of the artifact."),
requirement: z
.string()
.describe("The requirement for the artifact generation."),
});
const generateArtifactEvent = zodEvent(ArtifactRequirementSchema, {
debugLabel: "generateArtifactEvent",
});
// Artifact output event
const ArtifactSchema = z.object({
type: z.literal("artifact"),
data: z.object({
type: z.literal("document"),
data: z.object({
title: z.string().describe("The title of the data."),
content: z.string().describe("The content of the data."),
type: z.enum(["markdown", "html"]).describe("The type of the data."),
}),
}),
});
const outputArtifactEvent = zodEvent(ArtifactSchema, {
debugLabel: "outputArtifactEvent",
});
// Events for updating UI
// assume that we have a UI that can render different states of the workflow
// and update the UI based on the state and the requirement
export const UIEventSchema = z.object({
type: z.literal("ui_event"),
data: z.object({
state: z
.enum(["plan", "generate", "completed"])
.describe("The current state of the workflow."),
requirement: z
.string()
.optional()
.describe(
"An optional requirement creating or updating a document, if applicable.",
),
}),
});
const uiEvent = zodEvent(UIEventSchema, { debugLabel: "uiEvent" });
// ===== 2. Define workflow with agents using natural language =====
// We have a document artifact workflow that made up of 2 steps:
// 1. Generate requirement for the document
// 2. Generate document content based on the requirement
export function createDocumentArtifactWorkflow(llm: ToolCallLLM) {
const workflow = createWorkflow();
// Generate requirement for the document
workflow.handle(
[planEvent],
agentHandler({
instructions: `
Your task is to analyze the request and provide requirements for document generation or update.
1. Send an uiEvent with the \`plan\` to show UI what you are going to do.
2. Analyze the conversation history and the user's request carefully to determine the completed tasks and the next steps.
3. Return the generateArtifactEvent with the requirement for the next step of the document generation or update.
`,
results: [generateArtifactEvent],
events: [uiEvent],
llm,
}),
);
// Generate document content based on the requirement
workflow.handle(
[generateArtifactEvent],
agentHandler({
instructions: `
You are a skilled technical writer who can assist users with documentation.
Your task is to generate document content based on the requirement and update the UI state.
Here are the steps to handle this task:
1. First, send an uiEvent with the \`generate\` state and the requirement you received from the input.
2. Next, start generating the content based on the requirement then send an uiEvent with the \`completed\` state to update the state.
3. Finally, return the outputArtifactEvent with the document values.
`,
results: [outputArtifactEvent],
events: [uiEvent],
llm,
}),
);
return workflow;
}
async function main() {
const llm = openai({ model: "gpt-4.1-mini" });
const workflow = createDocumentArtifactWorkflow(llm);
const { stream, sendEvent } = workflow.createContext();
// Ask the workflow to generate a document about `llama`
sendEvent(planEvent.with({ topic: "llama" }));
await stream.until(outputArtifactEvent).forEach((event) => {
if (planEvent.include(event)) {
console.log("Starting workflow: ", event.data);
}
if (uiEvent.include(event)) {
console.log("UI event: ", event.data);
} else if (outputArtifactEvent.include(event)) {
console.log("Output artifact event: ", event.data);
}
});
}
main();
+93
View File
@@ -0,0 +1,93 @@
import { Settings } from "@llamaindex/core/global";
import { openai } from "@llamaindex/openai";
import { agentHandler, createWorkflow, zodEvent } from "@llamaindex/workflow";
import { z } from "zod";
// Create LLM instance
const llm = openai({ model: "gpt-4.1-mini" });
Settings.llm = llm;
// Define our workflow events
const writeJokeSchema = z.object({
description: z
.string()
.describe("The topic to write a joke or describe the joke to improve."),
writtenJoke: z.optional(z.string()).describe("The written joke."),
retriedTimes: z
.number()
.default(0)
.describe(
"The retried times for writing the joke. Always increase this from the input retriedTimes.",
),
});
const critiqueSchema = z.object({
joke: z.string().describe("The joke to critique"),
retriedTimes: z.number().describe("The retried times for writing the joke."),
});
const finalResultSchema = z.object({
joke: z.string().describe("The joke to critique"),
critique: z.string().describe("The critique of the joke"),
});
const writeJokeEvent = zodEvent(writeJokeSchema, {
debugLabel: "writeJokeEvent",
}); // Input topic for writing a joke
const critiqueEvent = zodEvent(critiqueSchema, {
debugLabel: "critiqueEvent",
}); // Ask for critique of the joke
const finalResultEvent = zodEvent(finalResultSchema, {
debugLabel: "finalResultEvent",
}); // Final result
// Create our workflow
const jokeFlow = createWorkflow();
// Define handlers for each step
// This step always write a joke based on the description
jokeFlow.handle(
[writeJokeEvent],
agentHandler({
instructions: `You are a joke writer. You are given a topic and you need to write a joke about it.`,
results: [critiqueEvent],
}),
);
// This step critiques the joke and asks the writer to improve the joke or send a final result event for stopping.
jokeFlow.handle(
[critiqueEvent],
agentHandler({
instructions: `
You are given a joke and you need to critique it. Follow the following guidelines:
1. You have maximum 3 times to improve the joke.
2. If the joke is not good, increase the retriedTimes, describe how to improve the joke and send a writeJokeEvent.
3. If the joke is good, trigger the finalResultEvent event.
`,
results: [writeJokeEvent, finalResultEvent],
}),
);
// Usage
async function main() {
const { stream, sendEvent } = jokeFlow.createContext();
sendEvent(writeJokeEvent.with({ description: "write a joke about llama" }));
await stream.until(finalResultEvent).forEach((event) => {
if (writeJokeEvent.include(event)) {
console.log(
"Triggering write joke: ",
JSON.stringify(event.data, null, 2),
);
} else if (critiqueEvent.include(event)) {
console.log("Written joke: ", JSON.stringify(event.data, null, 2));
} else if (finalResultEvent.include(event)) {
console.log("Output: ", JSON.stringify(event.data, null, 2));
} else {
console.log("Unknown event: ", JSON.stringify(event.data, null, 2));
}
});
console.log("Done");
}
main().catch(console.error);
+3 -2
View File
@@ -45,9 +45,10 @@
"peerDependencies": {
"@llamaindex/core": "workspace:*",
"@llamaindex/env": "workspace:*",
"zod": "^3.23.8"
"zod": "^3.23.8",
"zod-to-json-schema": "^3.23.3"
},
"dependencies": {
"@llama-flow/core": "^0.4.3"
"@llama-flow/core": "^0.4.4"
}
}
@@ -0,0 +1,110 @@
import { getContext, type WorkflowEventData } from "@llama-flow/core";
import {
AgentWorkflow,
startAgentEvent,
stopAgentEvent,
} from "./agent-workflow";
import { agentToolCallEvent, type AgentToolCall } from "./events";
import {
FunctionAgent,
type StepHandlerParams,
type ZodEvent,
} from "./function-agent";
async function handleWorkflowStep(
workflow: AgentWorkflow,
event: WorkflowEventData<unknown>,
results: ZodEvent[],
) {
const agent = workflow.getAgents()[0];
if (!agent) {
throw new Error("No valid agent found");
}
const { sendEvent, stream } = workflow.createContext();
sendEvent(
startAgentEvent.with({
userInput: "Handle with this input data: " + JSON.stringify(event.data),
}),
);
const agentEvents = await stream.until(stopAgentEvent).toArray();
checkAgentSentResultEvents(agentEvents, results);
}
/**
* Create a single agent to handle a workflow step
* @param params - Parameters for the step handler
* @returns A new AgentWorkflow instance
*/
function createWorkflowForStepHandler(
params: StepHandlerParams,
): AgentWorkflow {
if (!params.workflowContext) {
throw new Error("workflowContext must be provided");
}
if (!params.results) {
throw new Error("results must have at least one event");
}
if (!params.instructions) {
throw new Error("instructions must be provided");
}
const agent = FunctionAgent.fromWorkflowStep({
workflowContext: params.workflowContext,
results: params.results,
events: params.events ?? [],
instructions: params.instructions,
tools: params.tools,
llm: params.llm,
});
return new AgentWorkflow({
agents: [agent],
rootAgent: agent,
});
}
/**
* Add an agent handler to the workflow
* @param params - Parameters for the agent handler
* @returns A function that handles a workflow step
*/
export const agentHandler = (
params: Omit<StepHandlerParams, "workflowContext">,
) => {
return async (event: WorkflowEventData<unknown>) => {
const context = getContext();
const workflow = createWorkflowForStepHandler({
...params,
workflowContext: context,
});
await handleWorkflowStep(workflow, event, params.results);
};
};
/**
* Check if the agent already sent at least one result event
* @param agentEvents - Agent workflow events
* @param results - The result events that the agent should send
* @returns True if the agent already sent at least one result event or throw an error if the agent finished without sending a result event
*/
const checkAgentSentResultEvents = (
agentEvents: WorkflowEventData<unknown>[],
results: ZodEvent[],
) => {
// We cannot check the result event directly because it's not sent to the agent workflow
// instead, we check for the tool call event to see if there is a tool call event that match with result events
const toolCallEvents = agentEvents.filter((event) =>
agentToolCallEvent.include(event),
);
const resultToolNames = new Set(results.map((r) => `send_${r.debugLabel}`));
for (const toolCallEvent of toolCallEvents) {
const toolCall = toolCallEvent.data as AgentToolCall;
if (resultToolNames.has(toolCall.toolName)) {
return true;
}
}
throw new Error(
"The agent finished without emitting a required result event.",
);
};
+198 -21
View File
@@ -1,4 +1,4 @@
import type { WorkflowContext } from "@llama-flow/core";
import { type WorkflowContext, type WorkflowEvent } from "@llama-flow/core";
import type { JSONObject } from "@llamaindex/core/global";
import { Settings } from "@llamaindex/core/global";
import {
@@ -7,6 +7,9 @@ import {
type ChatMessage,
type ChatResponseChunk,
} from "@llamaindex/core/llms";
import { tool } from "@llamaindex/core/tools";
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
import { AgentWorkflow } from "./agent-workflow";
import { type AgentWorkflowState, type BaseWorkflowAgent } from "./base";
import {
@@ -19,6 +22,51 @@ import {
const DEFAULT_SYSTEM_PROMPT =
"You are a helpful assistant. Use the provided tools to answer questions.";
const STEP_HANDLER_SYSTEM_PROMPT_TPL = `
You are a part of a workflow program that is composed of multiple steps.
Your task is to handle the step using the provided tools and finally send an output event back to the workflow and summarize the result.
## Instructions
### Follow these default instructions:
1. Provide a plan to handle the actions based on context and the user request.
2. Use the provided tools to proceed with your actions. You can call multiple tools to handle the step and send events.
3. Always return at least one result event at the end to the workflow by using the provided result tools. Identify the event to send based on the user's instructions.
### Here is the user's instructions:
{instructions}
`;
export type ZodEvent = WorkflowEvent<unknown> & {
schema: z.ZodType<unknown>;
};
export type StepHandlerParams = {
/**
* Workflow context
*/
workflowContext: WorkflowContext;
/**
* User instructions to guide the agent to handle the step.
*/
instructions: string;
/**
* Event that this agent will return
*/
results: ZodEvent[];
/**
* List of additional events that the agent can emit
*/
events?: ZodEvent[];
/**
* LLM to use for the agent, required.
*/
llm?: ToolCallLLM | undefined;
/**
* List of tools that the agent can use
*/
tools?: BaseToolWithCall[] | undefined;
};
export type FunctionAgentParams = {
/**
* Agent name
@@ -36,7 +84,7 @@ export type FunctionAgentParams = {
/**
* List of tools that the agent can use, requires at least one tool.
*/
tools: BaseToolWithCall[];
tools?: BaseToolWithCall[] | undefined;
/**
* List of agents that this agent can delegate tasks to
* Can be a list of agent names as strings, BaseWorkflowAgent instances, or AgentWorkflow instances
@@ -48,6 +96,11 @@ export type FunctionAgentParams = {
systemPrompt?: string | undefined;
};
export type EmitEvent = {
event: WorkflowEvent<unknown> & { schema: z.ZodType<unknown> };
name: string;
};
export class FunctionAgent implements BaseWorkflowAgent {
readonly name: string;
readonly systemPrompt: string;
@@ -72,40 +125,43 @@ export class FunctionAgent implements BaseWorkflowAgent {
this.description =
description ??
"A single agent that uses the provided tools or functions.";
this.tools = tools;
if (tools.length === 0) {
throw new Error("FunctionAgent must have at least one tool");
}
// Process canHandoffTo to extract agent names
this.canHandoffTo = [];
if (canHandoffTo) {
if (Array.isArray(canHandoffTo)) {
if (canHandoffTo.length > 0) {
if (typeof canHandoffTo[0] === "string") {
this.tools = tools ?? [];
this.systemPrompt = systemPrompt ?? DEFAULT_SYSTEM_PROMPT;
this.canHandoffTo = this.initHandOffNames(canHandoffTo ?? []);
}
private initHandOffNames(
handoffTo: string[] | BaseWorkflowAgent[] | AgentWorkflow[],
): string[] {
const handoffToNames: string[] = [];
if (handoffTo) {
if (Array.isArray(handoffTo)) {
if (handoffTo.length > 0) {
if (typeof handoffTo[0] === "string") {
// string[] case
this.canHandoffTo = canHandoffTo as string[];
} else if (canHandoffTo[0] instanceof AgentWorkflow) {
handoffToNames.push(...(handoffTo as string[]));
} else if (handoffTo[0] instanceof AgentWorkflow) {
// AgentWorkflow[] case
const workflows = canHandoffTo as AgentWorkflow[];
const workflows = handoffTo as AgentWorkflow[];
workflows.forEach((workflow) => {
const agentNames = workflow
.getAgents()
.map((agent) => agent.name);
this.canHandoffTo.push(...agentNames);
handoffToNames.push(...agentNames);
});
} else {
// BaseWorkflowAgent[] case
const agents = canHandoffTo as BaseWorkflowAgent[];
this.canHandoffTo = agents.map((agent) => agent.name);
const agents = handoffTo as BaseWorkflowAgent[];
handoffToNames.push(...agents.map((agent) => agent.name));
}
}
}
}
const uniqueHandoffAgents = new Set(this.canHandoffTo);
if (uniqueHandoffAgents.size !== this.canHandoffTo.length) {
const uniqueHandoffAgents = new Set(handoffToNames);
if (uniqueHandoffAgents.size !== handoffToNames.length) {
throw new Error("Duplicate handoff agents");
}
this.systemPrompt = systemPrompt ?? DEFAULT_SYSTEM_PROMPT;
return handoffToNames;
}
async takeStep(
@@ -256,4 +312,125 @@ export class FunctionAgent implements BaseWorkflowAgent {
return toolCalls;
}
/**
* Create a FunctionAgent to handle a step of the workflow.
* @param params.workflowContext - The workflow context.
* @param params.result - The event to send when the agent is done.
* @param params.events - Additional events that the agent can emit.
* @param params.instructions - The user instructions to guide the agent to handle the step.
* @param params.tools - The tools to use for the agent.
* @returns A new FunctionAgent instance
*/
static fromWorkflowStep({
workflowContext,
results,
events,
instructions,
tools,
llm,
}: StepHandlerParams): FunctionAgent {
if (!workflowContext) {
throw new Error("workflowContext must be provided");
}
if (results.length === 0) {
throw new Error("results must have at least one event");
}
if (!instructions) {
throw new Error("instructions must be provided");
}
// Provided tools
const allTools = [...(tools ?? [])];
// Add tools for result events
results.forEach((result) => {
if (!result.debugLabel) {
throw new Error("Result event must have a debug label");
}
const description = `Use this tool to send the ${result.debugLabel} event as the final result of your task.`;
allTools.push(
createEventEmitterTool(
`send_${result.debugLabel}`,
result,
workflowContext,
description,
),
);
});
// Add tools for additional events
events?.forEach((event) => {
if (!event.debugLabel) {
throw new Error("Event must have a debug label");
}
allTools.push(
createEventEmitterTool(
`send_${event.debugLabel}`,
event,
workflowContext,
`Use this tool to send the ${event.debugLabel} event to the workflow program.`,
),
);
});
// Construct the system prompt
const newSystemPrompt = STEP_HANDLER_SYSTEM_PROMPT_TPL.replace(
"{instructions}",
instructions,
);
// Check if llm is provided or default LLM is a tool call LLM
const llmToUse = llm ?? (Settings.llm as ToolCallLLM);
if (!llmToUse.supportToolCall) {
throw new Error("LLM must support tool calls");
}
// Create the function agent
return new FunctionAgent({
llm: llmToUse,
systemPrompt: newSystemPrompt,
tools: allTools,
});
}
}
/**
* Create a tool that sends an event to the workflow.
* @param name - The name of the tool.
* @param event - The event to send.
* @param workflowContext - The workflow context.
* @param description - The description of the tool.
*/
const createEventEmitterTool = (
name: string,
event: WorkflowEvent<unknown> & { schema: z.ZodType<unknown> },
workflowContext: WorkflowContext,
description?: string,
) => {
// To ensure the model correctly interprets the event data, including the schema in the tool description is crucial.
// This is particularly important for special types like literals and enums, which the model might struggle with otherwise.
// By incorporating the schema into the tool description, we can facilitate the model's understanding of the event data.
const toolDescriptionWithSchema =
(description ??
event.schema.description ??
"Use this tool to send the event to the workflow.") +
`\n\nPlease provide the event data in the following JSON schema: ${JSON.stringify(
zodToJsonSchema(z.object({ eventData: event.schema })),
)}`;
return tool({
name: name,
description: toolDescriptionWithSchema,
parameters: z.object({
eventData: event.schema,
}),
execute: (
{ eventData }: { eventData?: z.infer<typeof event.schema> },
getContext?: () => WorkflowContext,
) => {
if (!getContext) {
throw new Error("Workflow context is not provided.");
}
const context = getContext();
context.sendEvent(event.with(eventData ?? {}));
return `Successfully sent a ${name} event!`;
},
}).bind(() => workflowContext);
};
+1
View File
@@ -1,3 +1,4 @@
export * from "./agent-handler";
export * from "./agent-workflow";
export * from "./base";
export * from "./events";
+1
View File
@@ -2,4 +2,5 @@ export * from "@llama-flow/core";
export * from "@llama-flow/core/middleware/snapshot";
export * from "@llama-flow/core/middleware/state";
export * from "@llama-flow/core/stream/run";
export { zodEvent } from "@llama-flow/core/util/zod";
export * from "./agent/index.js";
+63 -1
View File
@@ -1,7 +1,9 @@
import { type WorkflowContext } from "@llama-flow/core";
import { zodEvent } from "@llama-flow/core/util/zod";
import { ChatMessage } from "@llamaindex/core/llms";
import { tool } from "@llamaindex/core/tools";
import { MockLLM } from "@llamaindex/core/utils";
import { describe, expect, test } from "vitest";
import { describe, expect, test, vi } from "vitest";
import { z } from "zod";
import { AgentToolCallResult, FunctionAgent } from "../src/agent";
@@ -59,4 +61,64 @@ describe("FunctionAgent", () => {
},
});
});
test("should be initialized with correct tools", () => {
// Mock WorkflowContext
const mockWorkflowContext = {
sendEvent: vi.fn(),
} as unknown as WorkflowContext;
// Create a regular tool
const addTool = tool({
name: "add",
description: "Adds two numbers",
parameters: z.object({
x: z.number(),
y: z.number(),
}),
execute: (params: { x: number; y: number }) => params.x + params.y,
});
// Create a result event
const resultEvent = zodEvent(
z.object({
value: z.string(),
}),
{
debugLabel: "my_result_event",
},
);
// Create an additional event
const additionalEvent = zodEvent(
z.object({
value: z.number(),
}),
{
debugLabel: "additional_event",
},
);
// Create the FunctionAgent using fromWorkflowStep
const agent = FunctionAgent.fromWorkflowStep({
workflowContext: mockWorkflowContext,
results: [resultEvent],
events: [additionalEvent],
instructions: "Test instructions",
tools: [addTool],
llm: mockLLM,
});
// Check if the agent is created
expect(agent).toBeInstanceOf(FunctionAgent);
// Check the number of tools
expect(agent.tools.length).toBe(3);
// Check the names of the tools
const toolNames = agent.tools.map((t) => t.metadata.name);
expect(toolNames).toContain("add");
expect(toolNames).toContain("send_my_result_event");
expect(toolNames).toContain("send_additional_event");
});
});
+8 -5
View File
@@ -1808,11 +1808,14 @@ importers:
packages/workflow:
dependencies:
'@llama-flow/core':
specifier: ^0.4.3
version: 0.4.3(@modelcontextprotocol/sdk@1.9.0)(hono@4.7.7)(next@15.3.2(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.2)
specifier: ^0.4.4
version: 0.4.4(@modelcontextprotocol/sdk@1.9.0)(hono@4.7.7)(next@15.3.2(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.2)
zod:
specifier: ^3.23.8
version: 3.24.2
zod-to-json-schema:
specifier: ^3.23.3
version: 3.24.5(zod@3.24.2)
devDependencies:
'@llamaindex/core':
specifier: workspace:*
@@ -3947,8 +3950,8 @@ packages:
zod:
optional: true
'@llama-flow/core@0.4.3':
resolution: {integrity: sha512-fxvuCO0Jpa/WZ/NFk2HCpKwjE4bwpHAIFyW/MC0L+gKGKj8DMYjJla6WVhADU35EUnxdpf9ZYJoN32yPrJUMMQ==}
'@llama-flow/core@0.4.4':
resolution: {integrity: sha512-hwK1EQ+atUG/E7XcDV3KsTaA8op29pb8gbpVurpsqbLnGFkdTT4F/6V7Hy1cC2o/yOY+DKc/rxoIsH1uJS0cZg==}
peerDependencies:
'@modelcontextprotocol/sdk': ^1.7.0
hono: ^4.7.4
@@ -16607,7 +16610,7 @@ snapshots:
p-retry: 6.2.1
zod: 3.25.7
'@llama-flow/core@0.4.3(@modelcontextprotocol/sdk@1.9.0)(hono@4.7.7)(next@15.3.2(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.2)':
'@llama-flow/core@0.4.4(@modelcontextprotocol/sdk@1.9.0)(hono@4.7.7)(next@15.3.2(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.2)':
optionalDependencies:
'@modelcontextprotocol/sdk': 1.9.0
hono: 4.7.7