Skip to content

Commit 1b34f9a

Browse files
Merge pull request #464 from ag-ui-protocol/fix/llamaindex-frontend-actions-infinite-tool-calling
fix: normalize empty tool results for LlamaIndex to prevent loop
2 parents 22abfba + 1dba75d commit 1b34f9a

File tree

2 files changed

+38
-2
lines changed

2 files changed

+38
-2
lines changed

typescript-sdk/integrations/llamaindex/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@ag-ui/llamaindex",
33
"author": "Logan Markewich <[email protected]>",
4-
"version": "0.1.3",
4+
"version": "0.1.4-next.0",
55
"main": "./dist/index.js",
66
"module": "./dist/index.mjs",
77
"types": "./dist/index.d.ts",

typescript-sdk/integrations/llamaindex/src/index.ts

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,41 @@
44
*/
55

66
import { HttpAgent } from "@ag-ui/client";
7+
import type { BaseEvent, Message, RunAgentInput } from "@ag-ui/core";
8+
import { Observable } from "rxjs";
79

8-
export class LlamaIndexAgent extends HttpAgent {}
10+
/**
11+
* Normalizes AG-UI tool result messages before sending them to the LlamaIndex server.
12+
*
13+
* Context: When a frontend tool returns `undefined`, upstream encoders serialize the
14+
* result as an empty string (""). Some LlamaIndex workflows treat an empty tool
15+
* result as insufficient evidence and immediately re-plan the same tool call,
16+
* which can produce repeated frontend tool invocations (e.g., duplicate alerts).
17+
*
18+
* This integration adapts those messages for LlamaIndex by converting empty tool
19+
* results into a non-empty canonical value ("ok"). This preserves semantics for
20+
* tools that return no meaningful payload while preventing the planner from
21+
* needlessly re-invoking the same tool.
22+
*/
23+
function normalizeEmptyToolResults(messages: Message[]): Message[] {
24+
return messages.map((message: Message): Message => {
25+
if (message.role === "tool") {
26+
const content: string | undefined = message.content;
27+
const isEmpty: boolean = (content ?? "").trim().length === 0;
28+
if (isEmpty) {
29+
return { ...message, content: "ok" };
30+
}
31+
}
32+
return message;
33+
});
34+
}
35+
36+
export class LlamaIndexAgent extends HttpAgent {
37+
public override run(input: RunAgentInput): Observable<BaseEvent> {
38+
const sanitizedInput: RunAgentInput = {
39+
...input,
40+
messages: normalizeEmptyToolResults(input.messages),
41+
};
42+
return super.run(sanitizedInput);
43+
}
44+
}

0 commit comments

Comments
 (0)