Skip to content

Commit

Permalink
Merge pull request #146 from langchain-ai/nc/27jan/ui
Browse files Browse the repository at this point in the history
cr
  • Loading branch information
nfcampos authored Jan 29, 2024
2 parents 814032b + 2cdf879 commit f3e3975
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 22 deletions.
47 changes: 29 additions & 18 deletions backend/app/agent_types/openai_agent.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import json

from langchain.schema.messages import FunctionMessage
from langchain.schema.messages import ToolMessage
from langchain.tools import BaseTool
from langchain.tools.render import format_tool_to_openai_function
from langchain.tools.render import format_tool_to_openai_tool
from langchain_core.language_models.base import LanguageModelLike
from langchain_core.messages import SystemMessage
from langgraph.checkpoint import BaseCheckpointSaver
Expand All @@ -21,9 +21,7 @@ def _get_messages(messages):
return [SystemMessage(content=system_message)] + messages

if tools:
llm_with_tools = llm.bind(
functions=[format_tool_to_openai_function(t) for t in tools]
)
llm_with_tools = llm.bind(tools=[format_tool_to_openai_tool(t) for t in tools])
else:
llm_with_tools = llm
agent = _get_messages | llm_with_tools
Expand All @@ -33,30 +31,43 @@ def _get_messages(messages):
def should_continue(messages):
last_message = messages[-1]
# If there is no function call, then we finish
if "function_call" not in last_message.additional_kwargs:
if "tool_calls" not in last_message.additional_kwargs:
return "end"
# Otherwise if there is, we continue
else:
return "continue"

# Define the function to execute tools
async def call_tool(messages):
actions: list[ToolInvocation] = []
# Based on the continue condition
# we know the last message involves a function call
last_message = messages[-1]
# We construct an ToolInvocation from the function_call
action = ToolInvocation(
tool=last_message.additional_kwargs["function_call"]["name"],
tool_input=json.loads(
last_message.additional_kwargs["function_call"]["arguments"]
),
)
for tool_call in last_message.additional_kwargs["tool_calls"]:
function = tool_call["function"]
function_name = function["name"]
_tool_input = json.loads(function["arguments"] or "{}")
# We construct an ToolInvocation from the function_call
actions.append(
ToolInvocation(
tool=function_name,
tool_input=_tool_input,
)
)
# We call the tool_executor and get back a response
response = await tool_executor.ainvoke(action)
# We use the response to create a FunctionMessage
function_message = FunctionMessage(content=str(response), name=action.tool)
# We return a list, because this will get added to the existing list
return function_message
responses = await tool_executor.abatch(actions)
# We use the response to create a ToolMessage
tool_messages = [
ToolMessage(
tool_call_id=tool_call["id"],
content=json.dumps(response),
additional_kwargs={"name": tool_call["function"]["name"]},
)
for tool_call, response in zip(
last_message.additional_kwargs["tool_calls"], responses
)
]
return tool_messages

workflow = MessageGraph()

Expand Down
17 changes: 13 additions & 4 deletions frontend/src/components/Message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function Function(props: {
</span>
)}
{props.args && (
<div className="text-gray-900 mt-2 whitespace-pre-wrap break-words">
<div className="text-gray-900 my-2 whitespace-pre-wrap break-words">
<div className="ring-1 ring-gray-300 rounded">
<table className="divide-y divide-gray-300">
<tbody>
Expand Down Expand Up @@ -103,10 +103,10 @@ export const Message = memo(function Message(
{props.type}
</div>
<div className="flex-1">
{props.type === "function" && (
{["function", "tool"].includes(props.type) && (
<Function
call={false}
name={props.name}
name={props.name ?? props.additional_kwargs?.name}
open={open}
setOpen={setOpen}
/>
Expand All @@ -118,7 +118,16 @@ export const Message = memo(function Message(
args={props.additional_kwargs.function_call.arguments}
/>
)}
{(props.type === "function" ? open : true) ? (
{props.additional_kwargs?.tool_calls
?.filter((call) => call.function)
?.map((call) => (
<Function
call={true}
name={call.function?.name}
args={call.function?.arguments}
/>
))}
{(["function", "tool"].includes(props.type) ? open : true) ? (
typeof props.content === "string" ? (
<div
className="text-gray-900 prose"
Expand Down
7 changes: 7 additions & 0 deletions frontend/src/hooks/useChatList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,17 @@ export interface Message {
content: string;
name?: string;
additional_kwargs?: {
name?: string;
function_call?: {
name?: string;
arguments?: string;
};
tool_calls?: {
function?: {
name?: string;
arguments?: string;
};
}[];
};
example: boolean;
}
Expand Down

0 comments on commit f3e3975

Please sign in to comment.