chore: remove requireContext from tools (#1949)

This commit is contained in:
Marcus Schiesser
2025-05-14 16:38:44 +07:00
committed by GitHub
parent 389acbd307
commit 680b529e94
5 changed files with 53 additions and 74 deletions
+6
View File
@@ -0,0 +1,6 @@
---
"@llamaindex/workflow": patch
"@llamaindex/core": patch
---
Remove requireContext from tools - better use binding to pass context
+1 -1
View File
@@ -92,7 +92,7 @@ async function multiWeatherAgent() {
agentInputEvent.include(event) ||
stopAgentEvent.include(event)
) {
console.log(event);
console.log(event.data);
} else if (agentStreamEvent.include(event)) {
for (const chunk of event.data.delta) {
process.stdout.write(chunk);
-4
View File
@@ -256,10 +256,6 @@ export type ToolMetadata<
* @link https://json-schema.org/understanding-json-schema
*/
parameters?: Parameters;
/**
* Whether the tool requires workflow context to be passed in.
*/
requireContext?: boolean;
};
/**
+3 -19
View File
@@ -134,32 +134,16 @@ export class FunctionTool<
};
call = (input: T) => {
if (this.#metadata.requireContext) {
const inputWithContext = input as Record<string, unknown>;
if (!inputWithContext.context) {
throw new Error(
"Tool call requires context, but context parameter is missing",
);
}
}
let params = input;
if (this.#zodType) {
const result = this.#zodType.safeParse(input);
if (result.success) {
if (this.#metadata.requireContext) {
const { context } = input as Record<string, unknown>;
return this.#fn.call(
null,
{ context, ...result.data },
this.#additionalArg,
);
} else {
return this.#fn.call(null, result.data, this.#additionalArg);
}
params = result.data;
} else {
console.warn(result.error.errors);
}
}
return this.#fn.call(null, input, this.#additionalArg);
return this.#fn.call(null, params, this.#additionalArg);
};
}
+43 -50
View File
@@ -13,7 +13,7 @@ import { Settings } from "@llamaindex/core/global";
import type { ChatMessage, MessageContent } from "@llamaindex/core/llms";
import { ChatMemoryBuffer } from "@llamaindex/core/memory";
import { PromptTemplate } from "@llamaindex/core/prompts";
import { FunctionTool } from "@llamaindex/core/tools";
import { tool } from "@llamaindex/core/tools";
import { stringifyJSONToMessageContent } from "@llamaindex/core/utils";
import { z } from "zod";
import type { AgentWorkflowState, BaseWorkflowAgent } from "./base";
@@ -244,7 +244,7 @@ export class AgentWorkflow implements Workflow {
agent.canHandoffTo.forEach((name) => {
toHandoffAgents.set(name, this.agents.get(name)!);
});
const handoffTool = createHandoffTool(toHandoffAgents);
const handoffTool = this.createHandoffTool(toHandoffAgents);
if (
agent.canHandoffTo.length > 0 &&
!agent.tools.some((t) => t.metadata.name === handoffTool.metadata.name)
@@ -558,15 +558,7 @@ export class AgentWorkflow implements Workflow {
if (!tool) {
throw new Error(`Tool ${toolCall.toolName} not found`);
}
if (tool.metadata.requireContext) {
const input = {
context: this.stateful.getContext().state,
...toolCall.toolKwargs,
};
return tool.call(input);
} else {
return tool.call(toolCall.toolKwargs);
}
return tool.call(toolCall.toolKwargs);
}
private createInitialState(): AgentWorkflowState {
@@ -620,42 +612,16 @@ export class AgentWorkflow implements Workflow {
}
return finalEvent;
}
}
const createHandoffTool = (agents: Map<string, BaseWorkflowAgent>) => {
const agentInfo = Array.from(agents.values()).reduce(
(acc, a) => {
acc[a.name] = a.description;
return acc;
},
{} as Record<string, string>,
);
return FunctionTool.from(
({
context,
toAgent,
reason,
}: {
context?: AgentWorkflowState;
toAgent: string;
reason: string;
}) => {
if (!context) {
throw new Error("Context is required for handoff");
}
const agents = context.agents;
if (!agents.includes(toAgent)) {
return `Agent ${toAgent} not found. Select a valid agent to hand off to. Valid agents: ${agents.join(
", ",
)}`;
}
context.nextAgentName = toAgent;
return DEFAULT_HANDOFF_OUTPUT_PROMPT.format({
to_agent: toAgent,
reason: reason,
});
},
{
createHandoffTool(agents: Map<string, BaseWorkflowAgent>) {
const agentInfo = Array.from(agents.values()).reduce(
(acc, a) => {
acc[a.name] = a.description;
return acc;
},
{} as Record<string, string>,
);
return tool({
name: "handOff",
description: DEFAULT_HANDOFF_PROMPT.format({
agent_info: JSON.stringify(agentInfo),
@@ -668,7 +634,34 @@ const createHandoffTool = (agents: Map<string, BaseWorkflowAgent>) => {
description: "The reason for handing off to the agent",
}),
}),
requireContext: true,
},
);
};
execute: (
{
toAgent,
reason,
}: {
toAgent: string;
reason: string;
},
contextProvider?: () => AgentWorkflowState,
) => {
if (!contextProvider) {
throw new Error(
"Handoff tool internal error: Context was not provided.",
);
}
const context = contextProvider();
const agents = context.agents;
if (!agents.includes(toAgent)) {
return `Agent ${toAgent} not found. Select a valid agent to hand off to. Valid agents: ${agents.join(
", ",
)}`;
}
context.nextAgentName = toAgent;
return DEFAULT_HANDOFF_OUTPUT_PROMPT.format({
to_agent: toAgent,
reason: reason,
});
},
}).bind(() => this.stateful.getContext().state);
}
}