diff --git a/typescript-sdk/integrations/langgraph/examples/python/poetry.lock b/typescript-sdk/integrations/langgraph/examples/python/poetry.lock index 776843d3e..15e3723e1 100644 --- a/typescript-sdk/integrations/langgraph/examples/python/poetry.lock +++ b/typescript-sdk/integrations/langgraph/examples/python/poetry.lock @@ -2,18 +2,18 @@ [[package]] name = "ag-ui-langgraph" -version = "0.0.12a3" +version = "0.0.14a0" description = "Implementation of the AG-UI protocol for LangGraph." optional = false python-versions = "<3.14,>=3.10" groups = ["main"] files = [ - {file = "ag_ui_langgraph-0.0.12a3-py3-none-any.whl", hash = "sha256:5bea4056e413bb53952d742da44893d80712ecc9bd77473d9cccd07bd4cd00ee"}, - {file = "ag_ui_langgraph-0.0.12a3.tar.gz", hash = "sha256:0b0734c2a7a12bf98f7c411aaa9be3adacb77808ecb3c42360e5c129ea4b4411"}, + {file = "ag_ui_langgraph-0.0.14a0-py3-none-any.whl", hash = "sha256:3f89096d2e4e9e78bcf3693185d38dc06e88015bba2796070ad191ee22f22b68"}, + {file = "ag_ui_langgraph-0.0.14a0.tar.gz", hash = "sha256:a4154f9b2a07e007b54a54394c2bd7bef74dcdee2a979550ea8fa126cec090c2"}, ] [package.dependencies] -ag-ui-protocol = "0.1.7" +ag-ui-protocol = "0.1.9" fastapi = {version = ">=0.115.12,<0.116.0", optional = true, markers = "extra == \"fastapi\""} langchain = ">=0.3.0" langchain-core = ">=0.3.0" @@ -24,14 +24,14 @@ fastapi = ["fastapi (>=0.115.12,<0.116.0)"] [[package]] name = "ag-ui-protocol" -version = "0.1.7" +version = "0.1.9" description = "" optional = false python-versions = "<4.0,>=3.9" groups = ["main"] files = [ - {file = "ag_ui_protocol-0.1.7-py3-none-any.whl", hash = "sha256:8c821662ca6e9852569022f449b9f7aeb3f16aa75390fa8c28ceae2cce642baa"}, - {file = "ag_ui_protocol-0.1.7.tar.gz", hash = "sha256:0e93fd9f7c74d52afbd824d6e9738bd3422e859503905ba7582481cbc3c67ab2"}, + {file = "ag_ui_protocol-0.1.9-py3-none-any.whl", hash = "sha256:44c1238b0576a3915b3a16e1b3855724e08e92ebc96b1ff29379fbd3bfbd400b"}, + {file = "ag_ui_protocol-0.1.9.tar.gz", hash = "sha256:94d75e3919ff75e0b608a7eed445062ea0e6f11cd33b3386a7649047e0c7abd3"}, ] [package.dependencies] @@ -2970,4 +2970,4 @@ cffi = ["cffi (>=1.11)"] [metadata] lock-version = "2.1" python-versions = ">=3.12,<3.14" -content-hash = "aef84782b941a699c57297f1e9752de447f0c851a4370fbeebd2808601e8e369" +content-hash = "be9b9fc32655e0d4dceb29165d75a611f514138c36092c846da1c54ea39aebe6" diff --git a/typescript-sdk/integrations/langgraph/examples/python/pyproject.toml b/typescript-sdk/integrations/langgraph/examples/python/pyproject.toml index 71e46a9a5..db039a5b6 100644 --- a/typescript-sdk/integrations/langgraph/examples/python/pyproject.toml +++ b/typescript-sdk/integrations/langgraph/examples/python/pyproject.toml @@ -21,7 +21,7 @@ langchain-experimental = ">=0.0.11" langchain-google-genai = ">=2.1.9" langchain-openai = ">=0.0.1" langgraph = "^0.6.1" -ag-ui-langgraph = { version = "0.0.12a3", extras = ["fastapi"] } +ag-ui-langgraph = { version = "0.0.14a0", extras = ["fastapi"] } python-dotenv = "^1.0.0" fastapi = "^0.115.12" diff --git a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/agent.py b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/agent.py index 5a8a9d60a..54546b62a 100644 --- a/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/agent.py +++ b/typescript-sdk/integrations/langgraph/python/ag_ui_langgraph/agent.py @@ -446,12 +446,26 @@ def langgraph_default_merge_state(self, state: State, messages: List[BaseMessage else: tools_as_dicts.append(tool) + all_tools = [*state.get("tools", []), *tools_as_dicts] + + # Remove duplicates based on tool name + seen_names = set() + unique_tools = [] + for tool in all_tools: + tool_name = tool.get("name") if isinstance(tool, dict) else getattr(tool, "name", None) + if tool_name and tool_name not in seen_names: + seen_names.add(tool_name) + unique_tools.append(tool) + elif not tool_name: + # Keep tools without names (shouldn't happen, but just in case) + unique_tools.append(tool) + return { **state, "messages": new_messages, - "tools": [*state.get("tools", []), *tools_as_dicts], + "tools": unique_tools, "ag-ui": { - "tools": [*state.get("tools", []), *tools_as_dicts], + "tools": unique_tools, "context": input.context or [] } } diff --git a/typescript-sdk/integrations/langgraph/python/pyproject.toml b/typescript-sdk/integrations/langgraph/python/pyproject.toml index d1a27e19a..c0f3e31aa 100644 --- a/typescript-sdk/integrations/langgraph/python/pyproject.toml +++ b/typescript-sdk/integrations/langgraph/python/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "ag-ui-langgraph" -version = "0.0.13" +version = "0.0.14-alpha.0" description = "Implementation of the AG-UI protocol for LangGraph." authors = ["Ran Shem Tov "] readme = "README.md" diff --git a/typescript-sdk/integrations/langgraph/src/agent.ts b/typescript-sdk/integrations/langgraph/src/agent.ts index d16f4f590..e7993a4f1 100644 --- a/typescript-sdk/integrations/langgraph/src/agent.ts +++ b/typescript-sdk/integrations/langgraph/src/agent.ts @@ -25,7 +25,7 @@ import { PredictStateTool, LangGraphReasoning, StateEnrichment, - LangGraphTool, + LangGraphToolWithName, } from "./types"; import { AbstractAgent, @@ -1003,21 +1003,25 @@ export class LangGraphAgent extends AbstractAgent { const newMessages = messages.filter((message) => !existingMessageIds.has(message.id)); - const langGraphTools: LangGraphTool[] = [...(state.tools ?? []), ...(input.tools ?? [])].map((tool) => { - if (tool.type) { - return tool; + const langGraphTools: LangGraphToolWithName[] = [...(state.tools ?? []), ...(input.tools ?? [])].reduce((acc, tool) => { + let mappedTool = tool; + if (!tool.type) { + mappedTool = { + type: "function", + name: tool.name, + function: { + name: tool.name, + description: tool.description, + parameters: tool.parameters, + }, + } } - return { - type: "function", - name: tool.name, - function: { - name: tool.name, - description: tool.description, - parameters: tool.parameters, - }, - }; - }); + // Verify no duplicated + if (acc.find((t: LangGraphToolWithName) => (t.name === mappedTool.name) || t.function.name === mappedTool.function.name)) return acc; + + return [...acc, mappedTool]; + }, []); return { ...state, diff --git a/typescript-sdk/integrations/langgraph/src/types.ts b/typescript-sdk/integrations/langgraph/src/types.ts index 97abdbb84..4dec0d09b 100644 --- a/typescript-sdk/integrations/langgraph/src/types.ts +++ b/typescript-sdk/integrations/langgraph/src/types.ts @@ -15,8 +15,9 @@ export enum LangGraphEventTypes { OnInterrupt = "on_interrupt", } -export type LangGraphTool = { +export type LangGraphToolWithName = { type: "function"; + name?: string; function: { name: string; description: string; @@ -29,9 +30,9 @@ export type State> = { } & Record; export interface StateEnrichment { messages: LangGraphMessage[]; - tools: LangGraphTool[]; + tools: LangGraphToolWithName[]; 'ag-ui': { - tools: LangGraphTool[]; + tools: LangGraphToolWithName[]; context: RunAgentInput['context'] } }