From 286499388dffab6deb86c46f6b2174df4cf4b7a5 Mon Sep 17 00:00:00 2001
From: Alex Yang <himself65@outlook.com>
Date: Mon, 22 Apr 2024 02:13:29 -0500
Subject: [PATCH] fix: agent class should implement ChatEngine interface (#746)

---
 packages/core/e2e/node/claude.e2e.ts          |  6 ++-
 packages/core/e2e/node/openai.e2e.ts          | 24 ++++++++----
 packages/core/e2e/tsconfig.json               | 11 ++----
 packages/core/src/agent/base.ts               | 39 ++++++++++++++-----
 packages/core/src/cloud/LlamaCloudIndex.ts    |  4 +-
 .../chat/CondenseQuestionChatEngine.ts        |  6 +--
 packages/core/src/engines/chat/types.ts       | 16 ++++----
 .../src/engines/query/RetrieverQueryEngine.ts |  7 +---
 .../src/engines/query/RouterQueryEngine.ts    |  8 ++--
 .../engines/query/SubQuestionQueryEngine.ts   |  7 +---
 packages/core/src/indices/BaseIndex.ts        |  4 +-
 packages/core/src/indices/keyword/index.ts    |  4 +-
 packages/core/src/indices/summary/index.ts    |  4 +-
 .../core/src/indices/vectorStore/index.ts     |  4 +-
 packages/core/src/tools/QueryEngineTool.ts    |  6 +--
 packages/core/src/types.ts                    |  2 +-
 .../edge/e2e/test-edge-runtime/package.json   |  2 +-
 .../src/engines/query/JSONQueryEngine.ts      |  4 +-
 pnpm-lock.yaml                                | 11 +-----
 19 files changed, 92 insertions(+), 77 deletions(-)

diff --git a/packages/core/e2e/node/claude.e2e.ts b/packages/core/e2e/node/claude.e2e.ts
index 1afda5e5b..c22a717f2 100644
--- a/packages/core/e2e/node/claude.e2e.ts
+++ b/packages/core/e2e/node/claude.e2e.ts
@@ -2,7 +2,7 @@ import { consola } from "consola";
 import { Anthropic, FunctionTool, Settings, type LLM } from "llamaindex";
 import { AnthropicAgent } from "llamaindex/agent/anthropic";
 import { extractText } from "llamaindex/llm/utils";
-import { ok } from "node:assert";
+import { ok, strictEqual } from "node:assert";
 import { beforeEach, test } from "node:test";
 import { sumNumbersTool } from "./fixtures/tools.js";
 import { mockLLMEvent } from "./utils.js";
@@ -71,10 +71,12 @@ await test("anthropic agent", async (t) => {
         },
       ],
     });
-    const { response } = await agent.chat({
+    const { response, sources } = await agent.chat({
       message: "What is the weather in San Francisco?",
     });
     consola.debug("response:", response.message.content);
+
+    strictEqual(sources.length, 1);
     ok(extractText(response.message.content).includes("35"));
   });
 
diff --git a/packages/core/e2e/node/openai.e2e.ts b/packages/core/e2e/node/openai.e2e.ts
index 5bd086915..0d18634e3 100644
--- a/packages/core/e2e/node/openai.e2e.ts
+++ b/packages/core/e2e/node/openai.e2e.ts
@@ -13,6 +13,7 @@ import {
   SummaryIndex,
   VectorStoreIndex,
   type LLM,
+  type ToolOutput,
 } from "llamaindex";
 import { extractText } from "llamaindex/llm/utils";
 import { ok, strictEqual } from "node:assert";
@@ -222,10 +223,12 @@ await test("agent with object function call", async (t) => {
         ),
       ],
     });
-    const { response } = await agent.chat({
+    const { response, sources } = await agent.chat({
       message: "What is the weather in San Francisco?",
     });
     consola.debug("response:", response.message.content);
+
+    strictEqual(sources.length, 1);
     ok(extractText(response.message.content).includes("72"));
   });
 });
@@ -253,10 +256,12 @@ await test("agent", async (t) => {
         },
       ],
     });
-    const { response } = await agent.chat({
+    const { response, sources } = await agent.chat({
       message: "What is the weather in San Francisco?",
     });
     consola.debug("response:", response.message.content);
+
+    strictEqual(sources.length, 1);
     ok(extractText(response.message.content).includes("35"));
   });
 
@@ -290,9 +295,10 @@ await test("agent", async (t) => {
     const agent = new OpenAIAgent({
       tools: [showUniqueId],
     });
-    const { response } = await agent.chat({
+    const { response, sources } = await agent.chat({
       message: "My name is Alex Yang. What is my unique id?",
     });
+    strictEqual(sources.length, 1);
     ok(extractText(response.message.content).includes(uniqueId));
   });
 
@@ -301,10 +307,11 @@ await test("agent", async (t) => {
       tools: [sumNumbersTool],
     });
 
-    const { response } = await openaiAgent.chat({
+    const { response, sources } = await openaiAgent.chat({
       message: "how much is 1 + 1?",
     });
 
+    strictEqual(sources.length, 1);
     ok(extractText(response.message.content).includes("2"));
   });
 });
@@ -319,18 +326,21 @@ await test("agent stream", async (t) => {
       tools: [sumNumbersTool, divideNumbersTool],
     });
 
-    const { response } = await agent.chat({
+    const stream = await agent.chat({
       message: "Divide 16 by 2 then add 20",
       stream: true,
     });
 
     let message = "";
+    let soruces: ToolOutput[] = [];
 
-    for await (const chunk of response) {
-      message += chunk.delta;
+    for await (const { response, sources: _sources } of stream) {
+      message += response.delta;
+      soruces = _sources;
     }
 
     strictEqual(fn.mock.callCount(), 2);
+    strictEqual(soruces.length, 2);
     ok(message.includes("28"));
     Settings.callbackManager.off("llm-tool-call", fn);
   });
diff --git a/packages/core/e2e/tsconfig.json b/packages/core/e2e/tsconfig.json
index 409139772..6260e0875 100644
--- a/packages/core/e2e/tsconfig.json
+++ b/packages/core/e2e/tsconfig.json
@@ -4,14 +4,11 @@
     "outDir": "./lib",
     "module": "node16",
     "moduleResolution": "node16",
-    "target": "ESNext"
+    "target": "ESNext",
+    "lib": ["ES2022"],
+    "types": ["node"]
   },
-  "include": [
-    "./**/*.ts",
-    "./mock-module.js",
-    "./mock-register.js",
-    "./fixtures"
-  ],
+  "include": ["./node", "./mock-module.js", "./mock-register.js", "./fixtures"],
   "references": [
     {
       "path": "../../core/tsconfig.json"
diff --git a/packages/core/src/agent/base.ts b/packages/core/src/agent/base.ts
index 9c1b804c5..0a65937e1 100644
--- a/packages/core/src/agent/base.ts
+++ b/packages/core/src/agent/base.ts
@@ -1,5 +1,6 @@
 import { pipeline, randomUUID } from "@llamaindex/env";
 import {
+  type ChatEngine,
   type ChatEngineParamsNonStreaming,
   type ChatEngineParamsStreaming,
 } from "../engines/chat/index.js";
@@ -171,8 +172,9 @@ export async function* createTaskImpl<
 }
 
 export type AgentStreamChatResponse<Options extends object> = {
-  response: ReadableStream<ChatResponseChunk<Options>>;
-  sources: ToolOutput[];
+  response: ChatResponseChunk<Options>;
+  // sources of the response, will emit when new tool outputs are available
+  sources?: ToolOutput[];
 };
 
 export type AgentChatResponse<Options extends object> = {
@@ -276,7 +278,12 @@ export abstract class AgentRunner<
   >
     ? AdditionalMessageOptions
     : never,
-> {
+> implements
+    ChatEngine<
+      AgentChatResponse<AdditionalMessageOptions>,
+      ReadableStream<AgentStreamChatResponse<AdditionalMessageOptions>>
+    >
+{
   readonly #llm: AI;
   readonly #tools:
     | BaseToolWithCall[]
@@ -370,13 +377,13 @@ export abstract class AgentRunner<
   ): Promise<AgentChatResponse<AdditionalMessageOptions>>;
   async chat(
     params: ChatEngineParamsStreaming,
-  ): Promise<AgentStreamChatResponse<AdditionalMessageOptions>>;
+  ): Promise<ReadableStream<AgentStreamChatResponse<AdditionalMessageOptions>>>;
   @wrapEventCaller
   async chat(
     params: ChatEngineParamsNonStreaming | ChatEngineParamsStreaming,
   ): Promise<
     | AgentChatResponse<AdditionalMessageOptions>
-    | AgentStreamChatResponse<AdditionalMessageOptions>
+    | ReadableStream<AgentStreamChatResponse<AdditionalMessageOptions>>
   > {
     const task = await this.createTask(params.message, !!params.stream);
     const stepOutput = await pipeline(
@@ -397,14 +404,26 @@ export abstract class AgentRunner<
     const { output, taskStep } = stepOutput;
     this.#chatHistory = [...taskStep.context.store.messages];
     if (isAsyncIterable(output)) {
-      return {
-        response: output,
-        sources: [...taskStep.context.store.toolOutputs],
-      } satisfies AgentStreamChatResponse<AdditionalMessageOptions>;
+      return output.pipeThrough<
+        AgentStreamChatResponse<AdditionalMessageOptions>
+      >(
+        new TransformStream({
+          transform(chunk, controller) {
+            controller.enqueue({
+              response: chunk,
+              get sources() {
+                return [...taskStep.context.store.toolOutputs];
+              },
+            });
+          },
+        }),
+      );
     } else {
       return {
         response: output,
-        sources: [...taskStep.context.store.toolOutputs],
+        get sources() {
+          return [...taskStep.context.store.toolOutputs];
+        },
       } satisfies AgentChatResponse<AdditionalMessageOptions>;
     }
   }
diff --git a/packages/core/src/cloud/LlamaCloudIndex.ts b/packages/core/src/cloud/LlamaCloudIndex.ts
index 94c0d03c7..0445313db 100644
--- a/packages/core/src/cloud/LlamaCloudIndex.ts
+++ b/packages/core/src/cloud/LlamaCloudIndex.ts
@@ -5,7 +5,7 @@ import { RetrieverQueryEngine } from "../engines/query/RetrieverQueryEngine.js";
 import type { TransformComponent } from "../ingestion/types.js";
 import type { BaseNodePostprocessor } from "../postprocessors/types.js";
 import type { BaseSynthesizer } from "../synthesizers/types.js";
-import type { BaseQueryEngine } from "../types.js";
+import type { QueryEngine } from "../types.js";
 import type { CloudRetrieveParams } from "./LlamaCloudRetriever.js";
 import { LlamaCloudRetriever } from "./LlamaCloudRetriever.js";
 import { getPipelineCreate } from "./config.js";
@@ -178,7 +178,7 @@ export class LlamaCloudIndex {
       preFilters?: unknown;
       nodePostprocessors?: BaseNodePostprocessor[];
     } & CloudRetrieveParams,
-  ): BaseQueryEngine {
+  ): QueryEngine {
     const retriever = new LlamaCloudRetriever({
       ...this.params,
       ...params,
diff --git a/packages/core/src/engines/chat/CondenseQuestionChatEngine.ts b/packages/core/src/engines/chat/CondenseQuestionChatEngine.ts
index 6e629c1d4..2f885bfb5 100644
--- a/packages/core/src/engines/chat/CondenseQuestionChatEngine.ts
+++ b/packages/core/src/engines/chat/CondenseQuestionChatEngine.ts
@@ -12,7 +12,7 @@ import { wrapEventCaller } from "../../internal/context/EventCaller.js";
 import type { ChatMessage, LLM } from "../../llm/index.js";
 import { extractText, streamReducer } from "../../llm/utils.js";
 import { PromptMixin } from "../../prompts/index.js";
-import type { BaseQueryEngine } from "../../types.js";
+import type { QueryEngine } from "../../types.js";
 import type {
   ChatEngine,
   ChatEngineParamsNonStreaming,
@@ -33,13 +33,13 @@ export class CondenseQuestionChatEngine
   extends PromptMixin
   implements ChatEngine
 {
-  queryEngine: BaseQueryEngine;
+  queryEngine: QueryEngine;
   chatHistory: ChatHistory;
   llm: LLM;
   condenseMessagePrompt: CondenseQuestionPrompt;
 
   constructor(init: {
-    queryEngine: BaseQueryEngine;
+    queryEngine: QueryEngine;
     chatHistory: ChatMessage[];
     serviceContext?: ServiceContext;
     condenseMessagePrompt?: CondenseQuestionPrompt;
diff --git a/packages/core/src/engines/chat/types.ts b/packages/core/src/engines/chat/types.ts
index a3d554156..d81e0035a 100644
--- a/packages/core/src/engines/chat/types.ts
+++ b/packages/core/src/engines/chat/types.ts
@@ -23,21 +23,21 @@ export interface ChatEngineParamsNonStreaming extends ChatEngineParamsBase {
   stream?: false | null;
 }
 
-export interface ChatEngineAgentParams extends ChatEngineParamsBase {
-  toolChoice?: string | Record<string, any>;
-  stream?: boolean;
-}
-
 /**
  * A ChatEngine is used to handle back and forth chats between the application and the LLM.
  */
-export interface ChatEngine {
+export interface ChatEngine<
+  // synchronous response
+  R = Response,
+  // asynchronous response
+  AR extends AsyncIterable<unknown> = AsyncIterable<R>,
+> {
   /**
    * Send message along with the class's current chat history to the LLM.
    * @param params
    */
-  chat(params: ChatEngineParamsStreaming): Promise<AsyncIterable<Response>>;
-  chat(params: ChatEngineParamsNonStreaming): Promise<Response>;
+  chat(params: ChatEngineParamsStreaming): Promise<AR>;
+  chat(params: ChatEngineParamsNonStreaming): Promise<R>;
 
   /**
    * Resets the chat history so that it's empty.
diff --git a/packages/core/src/engines/query/RetrieverQueryEngine.ts b/packages/core/src/engines/query/RetrieverQueryEngine.ts
index da8d617a9..153cb4265 100644
--- a/packages/core/src/engines/query/RetrieverQueryEngine.ts
+++ b/packages/core/src/engines/query/RetrieverQueryEngine.ts
@@ -7,7 +7,7 @@ import { PromptMixin } from "../../prompts/Mixin.js";
 import type { BaseSynthesizer } from "../../synthesizers/index.js";
 import { ResponseSynthesizer } from "../../synthesizers/index.js";
 import type {
-  BaseQueryEngine,
+  QueryEngine,
   QueryEngineParamsNonStreaming,
   QueryEngineParamsStreaming,
 } from "../../types.js";
@@ -15,10 +15,7 @@ import type {
 /**
  * A query engine that uses a retriever to query an index and then synthesizes the response.
  */
-export class RetrieverQueryEngine
-  extends PromptMixin
-  implements BaseQueryEngine
-{
+export class RetrieverQueryEngine extends PromptMixin implements QueryEngine {
   retriever: BaseRetriever;
   responseSynthesizer: BaseSynthesizer;
   nodePostprocessors: BaseNodePostprocessor[];
diff --git a/packages/core/src/engines/query/RouterQueryEngine.ts b/packages/core/src/engines/query/RouterQueryEngine.ts
index 925fcfe6a..197fec076 100644
--- a/packages/core/src/engines/query/RouterQueryEngine.ts
+++ b/packages/core/src/engines/query/RouterQueryEngine.ts
@@ -7,14 +7,14 @@ import type { BaseSelector } from "../../selectors/index.js";
 import { LLMSingleSelector } from "../../selectors/index.js";
 import { TreeSummarize } from "../../synthesizers/index.js";
 import type {
-  BaseQueryEngine,
   QueryBundle,
+  QueryEngine,
   QueryEngineParamsNonStreaming,
   QueryEngineParamsStreaming,
 } from "../../types.js";
 
 type RouterQueryEngineTool = {
-  queryEngine: BaseQueryEngine;
+  queryEngine: QueryEngine;
   description: string;
 };
 
@@ -54,9 +54,9 @@ async function combineResponses(
 /**
  * A query engine that uses multiple query engines and selects the best one.
  */
-export class RouterQueryEngine extends PromptMixin implements BaseQueryEngine {
+export class RouterQueryEngine extends PromptMixin implements QueryEngine {
   private selector: BaseSelector;
-  private queryEngines: BaseQueryEngine[];
+  private queryEngines: QueryEngine[];
   private metadatas: RouterQueryEngineMetadata[];
   private summarizer: TreeSummarize;
   private verbose: boolean;
diff --git a/packages/core/src/engines/query/SubQuestionQueryEngine.ts b/packages/core/src/engines/query/SubQuestionQueryEngine.ts
index b06e40e96..188e0ab9a 100644
--- a/packages/core/src/engines/query/SubQuestionQueryEngine.ts
+++ b/packages/core/src/engines/query/SubQuestionQueryEngine.ts
@@ -11,8 +11,8 @@ import {
 } from "../../synthesizers/index.js";
 
 import type {
-  BaseQueryEngine,
   BaseTool,
+  QueryEngine,
   QueryEngineParamsNonStreaming,
   QueryEngineParamsStreaming,
   ToolMetadata,
@@ -24,10 +24,7 @@ import type { BaseQuestionGenerator, SubQuestion } from "./types.js";
 /**
  * SubQuestionQueryEngine decomposes a question into subquestions and then
  */
-export class SubQuestionQueryEngine
-  extends PromptMixin
-  implements BaseQueryEngine
-{
+export class SubQuestionQueryEngine extends PromptMixin implements QueryEngine {
   responseSynthesizer: BaseSynthesizer;
   questionGen: BaseQuestionGenerator;
   queryEngines: BaseTool[];
diff --git a/packages/core/src/indices/BaseIndex.ts b/packages/core/src/indices/BaseIndex.ts
index 2cce62428..69f9a79b9 100644
--- a/packages/core/src/indices/BaseIndex.ts
+++ b/packages/core/src/indices/BaseIndex.ts
@@ -8,7 +8,7 @@ import type { BaseDocumentStore } from "../storage/docStore/types.js";
 import type { BaseIndexStore } from "../storage/indexStore/types.js";
 import type { VectorStore } from "../storage/vectorStore/types.js";
 import type { BaseSynthesizer } from "../synthesizers/types.js";
-import type { BaseQueryEngine } from "../types.js";
+import type { QueryEngine } from "../types.js";
 import { IndexStruct } from "./IndexStruct.js";
 import { IndexStructType } from "./json-to-index-struct.js";
 
@@ -87,7 +87,7 @@ export abstract class BaseIndex<T> {
   abstract asQueryEngine(options?: {
     retriever?: BaseRetriever;
     responseSynthesizer?: BaseSynthesizer;
-  }): BaseQueryEngine;
+  }): QueryEngine;
 
   /**
    * Insert a document into the index.
diff --git a/packages/core/src/indices/keyword/index.ts b/packages/core/src/indices/keyword/index.ts
index 2f0441e0c..06d59fed6 100644
--- a/packages/core/src/indices/keyword/index.ts
+++ b/packages/core/src/indices/keyword/index.ts
@@ -17,7 +17,7 @@ import type { StorageContext } from "../../storage/StorageContext.js";
 import { storageContextFromDefaults } from "../../storage/StorageContext.js";
 import type { BaseDocumentStore } from "../../storage/docStore/types.js";
 import type { BaseSynthesizer } from "../../synthesizers/index.js";
-import type { BaseQueryEngine } from "../../types.js";
+import type { QueryEngine } from "../../types.js";
 import type { BaseIndexInit } from "../BaseIndex.js";
 import { BaseIndex, KeywordTable } from "../BaseIndex.js";
 import { IndexStructType } from "../json-to-index-struct.js";
@@ -234,7 +234,7 @@ export class KeywordTableIndex extends BaseIndex<KeywordTable> {
     responseSynthesizer?: BaseSynthesizer;
     preFilters?: unknown;
     nodePostprocessors?: BaseNodePostprocessor[];
-  }): BaseQueryEngine {
+  }): QueryEngine {
     const { retriever, responseSynthesizer } = options ?? {};
     return new RetrieverQueryEngine(
       retriever ?? this.asRetriever(),
diff --git a/packages/core/src/indices/summary/index.ts b/packages/core/src/indices/summary/index.ts
index 54f381738..3a29cd0ac 100644
--- a/packages/core/src/indices/summary/index.ts
+++ b/packages/core/src/indices/summary/index.ts
@@ -23,7 +23,7 @@ import {
   CompactAndRefine,
   ResponseSynthesizer,
 } from "../../synthesizers/index.js";
-import type { BaseQueryEngine } from "../../types.js";
+import type { QueryEngine } from "../../types.js";
 import type { BaseIndexInit } from "../BaseIndex.js";
 import { BaseIndex } from "../BaseIndex.js";
 import { IndexList, IndexStructType } from "../json-to-index-struct.js";
@@ -171,7 +171,7 @@ export class SummaryIndex extends BaseIndex<IndexList> {
     responseSynthesizer?: BaseSynthesizer;
     preFilters?: unknown;
     nodePostprocessors?: BaseNodePostprocessor[];
-  }): BaseQueryEngine & RetrieverQueryEngine {
+  }): QueryEngine & RetrieverQueryEngine {
     let { retriever, responseSynthesizer } = options ?? {};
 
     if (!retriever) {
diff --git a/packages/core/src/indices/vectorStore/index.ts b/packages/core/src/indices/vectorStore/index.ts
index c2818d3bd..cac64098b 100644
--- a/packages/core/src/indices/vectorStore/index.ts
+++ b/packages/core/src/indices/vectorStore/index.ts
@@ -37,7 +37,7 @@ import type {
 import type { BaseIndexStore } from "../../storage/indexStore/types.js";
 import { VectorStoreQueryMode } from "../../storage/vectorStore/types.js";
 import type { BaseSynthesizer } from "../../synthesizers/types.js";
-import type { BaseQueryEngine } from "../../types.js";
+import type { QueryEngine } from "../../types.js";
 import type { BaseIndexInit } from "../BaseIndex.js";
 import { BaseIndex } from "../BaseIndex.js";
 import { IndexDict, IndexStructType } from "../json-to-index-struct.js";
@@ -284,7 +284,7 @@ export class VectorStoreIndex extends BaseIndex<IndexDict> {
     responseSynthesizer?: BaseSynthesizer;
     preFilters?: MetadataFilters;
     nodePostprocessors?: BaseNodePostprocessor[];
-  }): BaseQueryEngine & RetrieverQueryEngine {
+  }): QueryEngine & RetrieverQueryEngine {
     const { retriever, responseSynthesizer } = options ?? {};
     return new RetrieverQueryEngine(
       retriever ?? this.asRetriever(),
diff --git a/packages/core/src/tools/QueryEngineTool.ts b/packages/core/src/tools/QueryEngineTool.ts
index 9af842c29..d2c03ad93 100644
--- a/packages/core/src/tools/QueryEngineTool.ts
+++ b/packages/core/src/tools/QueryEngineTool.ts
@@ -1,5 +1,5 @@
 import type { JSONSchemaType } from "ajv";
-import type { BaseQueryEngine, BaseTool, ToolMetadata } from "../types.js";
+import type { BaseTool, QueryEngine, ToolMetadata } from "../types.js";
 
 const DEFAULT_NAME = "query_engine_tool";
 const DEFAULT_DESCRIPTION =
@@ -17,7 +17,7 @@ const DEFAULT_PARAMETERS: JSONSchemaType<QueryEngineParam> = {
 };
 
 export type QueryEngineToolParams = {
-  queryEngine: BaseQueryEngine;
+  queryEngine: QueryEngine;
   metadata: ToolMetadata<JSONSchemaType<QueryEngineParam>>;
 };
 
@@ -26,7 +26,7 @@ export type QueryEngineParam = {
 };
 
 export class QueryEngineTool implements BaseTool<QueryEngineParam> {
-  private queryEngine: BaseQueryEngine;
+  private queryEngine: QueryEngine;
   metadata: ToolMetadata<JSONSchemaType<QueryEngineParam>>;
 
   constructor({ queryEngine, metadata }: QueryEngineToolParams) {
diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts
index 7e95ea709..f18764943 100644
--- a/packages/core/src/types.ts
+++ b/packages/core/src/types.ts
@@ -22,7 +22,7 @@ export interface QueryEngineParamsNonStreaming extends QueryEngineParamsBase {
 /**
  * A query engine is a question answerer that can use one or more steps.
  */
-export interface BaseQueryEngine {
+export interface QueryEngine {
   /**
    * Query the query engine and get a response.
    * @param params
diff --git a/packages/edge/e2e/test-edge-runtime/package.json b/packages/edge/e2e/test-edge-runtime/package.json
index ad68db43f..644dd5c1a 100644
--- a/packages/edge/e2e/test-edge-runtime/package.json
+++ b/packages/edge/e2e/test-edge-runtime/package.json
@@ -14,7 +14,7 @@
     "react-dom": "^18"
   },
   "devDependencies": {
-    "@types/node": "^20",
+    "@types/node": "^20.12.7",
     "@types/react": "^18",
     "@types/react-dom": "^18",
     "typescript": "^5"
diff --git a/packages/experimental/src/engines/query/JSONQueryEngine.ts b/packages/experimental/src/engines/query/JSONQueryEngine.ts
index 070a389fc..c91140796 100644
--- a/packages/experimental/src/engines/query/JSONQueryEngine.ts
+++ b/packages/experimental/src/engines/query/JSONQueryEngine.ts
@@ -5,7 +5,7 @@ import { Response } from "llamaindex";
 import { serviceContextFromDefaults, type ServiceContext } from "llamaindex";
 
 import type {
-  BaseQueryEngine,
+  QueryEngine,
   QueryEngineParamsNonStreaming,
   QueryEngineParamsStreaming,
 } from "llamaindex";
@@ -89,7 +89,7 @@ type OutputProcessor = typeof defaultOutputProcessor;
 /**
  * A JSON query engine that uses JSONPath to query a JSON object.
  */
-export class JSONQueryEngine implements BaseQueryEngine {
+export class JSONQueryEngine implements QueryEngine {
   jsonValue: JSONSchemaType;
   jsonSchema: JSONSchemaType;
   serviceContext: ServiceContext;
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 699e084a6..a0a8004b2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -484,8 +484,8 @@ importers:
         version: 18.2.0(react@18.2.0)
     devDependencies:
       '@types/node':
-        specifier: ^20
-        version: 20.11.20
+        specifier: ^20.12.7
+        version: 20.12.7
       '@types/react':
         specifier: ^18
         version: 18.2.65
@@ -2542,9 +2542,6 @@ packages:
   '@types/node@18.19.31':
     resolution: {integrity: sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==}
 
-  '@types/node@20.11.20':
-    resolution: {integrity: sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg==}
-
   '@types/node@20.12.7':
     resolution: {integrity: sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==}
 
@@ -11356,10 +11353,6 @@ snapshots:
     dependencies:
       undici-types: 5.26.5
 
-  '@types/node@20.11.20':
-    dependencies:
-      undici-types: 5.26.5
-
   '@types/node@20.12.7':
     dependencies:
       undici-types: 5.26.5
-- 
GitLab