diff --git a/typescript-sdk/integrations/llamaindex/package.json b/typescript-sdk/integrations/llamaindex/package.json index a2a315e62..ead7fc331 100644 --- a/typescript-sdk/integrations/llamaindex/package.json +++ b/typescript-sdk/integrations/llamaindex/package.json @@ -1,7 +1,7 @@ { "name": "@ag-ui/llamaindex", "author": "Logan Markewich ", - "version": "0.1.3", + "version": "0.1.4-next.0", "main": "./dist/index.js", "module": "./dist/index.mjs", "types": "./dist/index.d.ts", diff --git a/typescript-sdk/integrations/llamaindex/src/index.ts b/typescript-sdk/integrations/llamaindex/src/index.ts index 5d8574bfb..b89fe27d8 100644 --- a/typescript-sdk/integrations/llamaindex/src/index.ts +++ b/typescript-sdk/integrations/llamaindex/src/index.ts @@ -4,5 +4,41 @@ */ import { HttpAgent } from "@ag-ui/client"; +import type { BaseEvent, Message, RunAgentInput } from "@ag-ui/core"; +import { Observable } from "rxjs"; -export class LlamaIndexAgent extends HttpAgent {} +/** + * Normalizes AG-UI tool result messages before sending them to the LlamaIndex server. + * + * Context: When a frontend tool returns `undefined`, upstream encoders serialize the + * result as an empty string (""). Some LlamaIndex workflows treat an empty tool + * result as insufficient evidence and immediately re-plan the same tool call, + * which can produce repeated frontend tool invocations (e.g., duplicate alerts). + * + * This integration adapts those messages for LlamaIndex by converting empty tool + * results into a non-empty canonical value ("ok"). This preserves semantics for + * tools that return no meaningful payload while preventing the planner from + * needlessly re-invoking the same tool. + */ +function normalizeEmptyToolResults(messages: Message[]): Message[] { + return messages.map((message: Message): Message => { + if (message.role === "tool") { + const content: string | undefined = message.content; + const isEmpty: boolean = (content ?? "").trim().length === 0; + if (isEmpty) { + return { ...message, content: "ok" }; + } + } + return message; + }); +} + +export class LlamaIndexAgent extends HttpAgent { + public override run(input: RunAgentInput): Observable { + const sanitizedInput: RunAgentInput = { + ...input, + messages: normalizeEmptyToolResults(input.messages), + }; + return super.run(sanitizedInput); + } +}