Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion typescript-sdk/integrations/llamaindex/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@ag-ui/llamaindex",
"author": "Logan Markewich <[email protected]>",
"version": "0.1.3",
"version": "0.1.4-next.0",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
Expand Down
38 changes: 37 additions & 1 deletion typescript-sdk/integrations/llamaindex/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<BaseEvent> {
const sanitizedInput: RunAgentInput = {
...input,
messages: normalizeEmptyToolResults(input.messages),
};
return super.run(sanitizedInput);
}
}
Loading