Skip to content

Commit

Permalink
Issue i-am-bee#121: Initial draft and work-in-progress on Human Inter…
Browse files Browse the repository at this point in the history
…vention Abstraction
  • Loading branch information
matiasmolinas committed Nov 22, 2024
1 parent e6590e0 commit 771642d
Show file tree
Hide file tree
Showing 8 changed files with 334 additions and 37 deletions.
33 changes: 30 additions & 3 deletions examples/agents/bee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,31 @@ import { LocalPythonStorage } from "bee-agent-framework/tools/python/storage";
import { DuckDuckGoSearchTool } from "bee-agent-framework/tools/search/duckDuckGoSearch";
import { WikipediaTool } from "bee-agent-framework/tools/search/wikipedia";
import { OpenMeteoTool } from "bee-agent-framework/tools/weather/openMeteo";
import { HumanTool } from "@/tools/human.js";
import { dirname } from "node:path";
import { fileURLToPath } from "node:url";
import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat";
//import { OllamaChatLLM } from "bee-agent-framework/adapters/ollama/chat";
import { OpenAIChatLLM } from "bee-agent-framework/adapters/openai/chat";

import {
BeeSystemPrompt,
BeeAssistantPrompt,
BeeUserPrompt,
BeeUserEmptyPrompt,
BeeToolErrorPrompt,
BeeToolInputErrorPrompt,
BeeToolNoResultsPrompt,
BeeToolNotFoundPrompt,
} from "@/agents/bee/prompts.js";

Logger.root.level = "silent"; // disable internal logs
const logger = new Logger({ name: "app", level: "trace" });

const llm = new OllamaChatLLM({
modelId: "llama3.1", // llama3.1:70b for better performance
//const llm = new OllamaChatLLM({
// modelId: "llama3.1", // llama3.1:70b for better performance
//});
const llm = new OpenAIChatLLM({
modelId: "gpt-4o", // gpt-4o
});

const codeInterpreterUrl = process.env.CODE_INTERPRETER_URL;
Expand All @@ -35,6 +51,7 @@ const agent = new BeeAgent({
// new WebCrawlerTool(), // HTML web page crawler
new WikipediaTool(),
new OpenMeteoTool(), // weather tool
new HumanTool(), //human tool
// new ArXivTool(), // research papers
// new DynamicTool() // custom python tool
...(codeInterpreterUrl
Expand All @@ -49,6 +66,16 @@ const agent = new BeeAgent({
]
: []),
],
templates: {
system: BeeSystemPrompt,
assistant: BeeAssistantPrompt,
user: BeeUserPrompt,
userEmpty: BeeUserEmptyPrompt,
toolError: BeeToolErrorPrompt,
toolInputError: BeeToolInputErrorPrompt,
toolNoResultError: BeeToolNoResultsPrompt,
toolNotFoundError: BeeToolNotFoundPrompt,
},
});

const reader = createConsoleReader();
Expand Down
4 changes: 3 additions & 1 deletion src/agents/bee/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ export type BeeParserInput = LinePrefixParser.define<{
tool_input: JSONParserField<Record<string, any>>;
tool_output: ZodParserField<string>;
final_answer: ZodParserField<string>;
human_tool_input: ZodParserField<string>; // Added field for HumanTool input
human_tool_output: ZodParserField<string>; // Added field for HumanTool output
}>;

type BeeParser = LinePrefixParser<BeeParserInput>;
export type BeeIterationResult = LinePrefixParser.inferOutput<BeeParser>;
export type BeeIterationResultPartial = LinePrefixParser.inferPartialOutput<BeeParser>;
export type BeeIterationToolResult = NonUndefined<BeeIterationResult, "tool_input" | "tool_name">;
export type BeeIterationToolResult = NonUndefined<BeeIterationResult, "tool_input" | "tool_name">;
15 changes: 14 additions & 1 deletion src/agents/bee/prompts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
Expand Down Expand Up @@ -70,13 +70,24 @@ Message: Can you translate "How are you" into French?
Thought: The user wants to translate a text into French. I can do that.
Final Answer: Comment vas-tu?
Message: I need advice.
Thought: The user's request is too general. I need to ask for more specifics.
Function Name: HumanTool
Function Input: { "message": "Could you please specify what you need advice on?" }
Function Output: // Waits for user input
Thought: The user has provided more details. I can now assist them.
Final Answer: [Provide the advice based on user's input]
# Instructions
User can only see the Final Answer, all answers must be provided there.
{{^tools.length}}
You must always use the communication structure and instructions defined above. Do not forget that Thought must be immediately followed by Final Answer.
{{/tools.length}}
{{#tools.length}}
You must always use the communication structure and instructions defined above. Do not forget that Thought must be immediately followed by either Function Name or Final Answer.
When the message is unclear or you need more information from the user, you **must** use the "HumanTool" function to ask for clarification and **should not** ask for more information directly in the Final Answer.
Functions must be used to retrieve factual or historical information to answer the message.
{{/tools.length}}
If the user suggests using a function that is not available, answer that the function is not available. You can suggest alternatives if appropriate.
Expand All @@ -97,6 +108,8 @@ Prefer to use these capabilities over functions.
- When using search engines, you try different formulations of the query, possibly even in a different language.
- You cannot do complex calculations, computations, or data manipulations without using functions.
When the message is unclear or you need more information from the user, you must use the "HumanTool" to ask for clarification.
# Role
{{instructions}}`,
});
Expand Down
45 changes: 44 additions & 1 deletion src/agents/bee/runner.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Copyright 2024 IBM Corp.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
Expand All @@ -20,6 +20,10 @@ import { BaseMessage, Role } from "@/llms/primitives/message.js";
import { BaseMemory } from "@/memory/base.js";
import { BeeUserPrompt } from "@/agents/bee/prompts.js";
import { zip } from "remeda";
import { HumanTool } from "@/tools/human.js";
import { Emitter } from "@/emitter/emitter.js";
import { BeeIterationToolResult } from "@/agents/bee/parser.js";
import { BeeCallbacks } from "@/agents/bee/types.js";

vi.mock("@/memory/tokenMemory.js", async () => {
const { UnconstrainedMemory } = await import("@/memory/unconstrainedMemory.js");
Expand Down Expand Up @@ -129,4 +133,43 @@ describe("Bee Agent Runner", () => {
expect(template.render({ input: a.text, meta: undefined })).toStrictEqual(b.text);
}
});

it("Handles HumanTool correctly", async () => {
const memory = new UnconstrainedMemory();
const prompt = "I need human intervention.";
const instance = await BeeAgentRunner.create(
{
llm: expect.any(Function),
memory,
tools: [new HumanTool()],
templates: {},
},
{},
prompt,
);

// Create a full iteration object with required properties
const iteration: BeeIterationToolResult = {
tool_name: "HumanTool",
tool_input: { message: "Please provide input." },
thought: "I need to ask the human for input.",
tool_output: "",
final_answer: "",
human_tool_input: "",
human_tool_output: "",
};

// Instantiate an actual Emitter<BeeCallbacks>
const emitter = new Emitter<BeeCallbacks>();

const result = await instance.tool({
iteration: iteration,
signal: new AbortController().signal,
emitter: emitter,
meta: { iteration: 1 },
});

expect(result.output).toBeDefined();
expect(result.success).toBe(true);
});
});
Loading

0 comments on commit 771642d

Please sign in to comment.