mirror of
https://github.com/run-llama/create-llama.git
synced 2026-07-01 21:04:08 -04:00
feat: support human in the loop for TS (#686)
* feat: support human in the loop for TS * add example for custom workflow * fix: need to request humanResponseEvent to save missing step to snapshot * refactor: human response data should be any * refactor runWorkflow function to support resume stream * refactor: hitl * fix: workflow * add summary event * send tool event * use requestId from Vercel * update chat route.ts * fix copy utils/* * refactor: workflow and stream * Create eight-moons-perform.md * update typo * make schema simple * fix typo * use messages in startAgentEvent * save to snapshots folder * fix lint * feat: workflowBaseEvent * include response event in input event * simplify type * update readme * update document * fix typecheck * bump: "@llamaindex/workflow": "~1.1.8" * remove any * use fixed tsx version to fix e2e * fix wrong copy * add cli hitl examples as a use case for both Python and TS * update changeset to release create-llama also * fix e2e * fix e2e * hitl frontend chat * try disable hitl test
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@llamaindex/server": patch
|
||||
"create-llama": patch
|
||||
---
|
||||
|
||||
feat: support human in the loop for TS
|
||||
@@ -20,6 +20,7 @@ const useCases: TemplateUseCase[] = [
|
||||
"financial_report",
|
||||
"code_generator",
|
||||
"document_generator",
|
||||
"hitl",
|
||||
];
|
||||
const dataSource: string = process.env.DATASOURCE
|
||||
? process.env.DATASOURCE
|
||||
|
||||
@@ -27,6 +27,7 @@ const templateUseCases = [
|
||||
"financial_report",
|
||||
"deep_research",
|
||||
"code_generator",
|
||||
// "hitl",
|
||||
];
|
||||
const ejectDir = "next";
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { exec } from "child_process";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import util from "util";
|
||||
import { NO_DATA_USE_CASES } from "../../helpers/constant";
|
||||
import {
|
||||
TemplateFramework,
|
||||
TemplateType,
|
||||
@@ -25,6 +26,7 @@ const useCases: TemplateUseCase[] = [
|
||||
"financial_report",
|
||||
"code_generator",
|
||||
"document_generator",
|
||||
"hitl",
|
||||
];
|
||||
const dataSource: string = process.env.DATASOURCE
|
||||
? process.env.DATASOURCE
|
||||
@@ -83,7 +85,7 @@ test.describe("Test resolve TS dependencies", () => {
|
||||
});
|
||||
});
|
||||
// Skipping llamacloud for the use case doesn't use index.
|
||||
if (useCase !== "code_generator" && useCase !== "document_generator") {
|
||||
if (!useCase || !NO_DATA_USE_CASES.includes(useCase)) {
|
||||
test(`llamaParse - ${optionDescription}`, async () => {
|
||||
await runTest({
|
||||
templateType: templateType,
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
import { TemplateUseCase } from "./types";
|
||||
|
||||
export const COMMUNITY_OWNER = "run-llama";
|
||||
export const COMMUNITY_REPO = "create_llama_projects";
|
||||
export const LLAMA_PACK_OWNER = "run-llama";
|
||||
export const LLAMA_PACK_REPO = "llama_index";
|
||||
export const LLAMA_PACK_FOLDER = "llama-index-packs";
|
||||
export const LLAMA_PACK_FOLDER_PATH = `${LLAMA_PACK_OWNER}/${LLAMA_PACK_REPO}/main/${LLAMA_PACK_FOLDER}`;
|
||||
|
||||
// these use cases don't have data folder, so no need to run generate and no need to getIndex
|
||||
export const NO_DATA_USE_CASES: TemplateUseCase[] = [
|
||||
"code_generator",
|
||||
"document_generator",
|
||||
"hitl",
|
||||
];
|
||||
|
||||
@@ -4,6 +4,7 @@ import path from "path";
|
||||
import picocolors, { cyan } from "picocolors";
|
||||
|
||||
import fsExtra from "fs-extra";
|
||||
import { NO_DATA_USE_CASES } from "./constant";
|
||||
import { writeLoadersConfig } from "./datasources";
|
||||
import { createBackendEnvFile, createFrontendEnvFile } from "./env-variables";
|
||||
import { PackageManager } from "./get-pkg-manager";
|
||||
@@ -98,8 +99,9 @@ async function generateContextData(
|
||||
}
|
||||
} else {
|
||||
console.log(`Running ${runGenerate} to generate the context data.`);
|
||||
|
||||
const shouldRunGenerate =
|
||||
useCase !== "code_generator" && useCase !== "document_generator"; // Artifact use case doesn't use index.
|
||||
!useCase || !NO_DATA_USE_CASES.includes(useCase);
|
||||
|
||||
if (shouldRunGenerate) {
|
||||
await callPackageManager(packageManager, true, ["run", "generate"]);
|
||||
|
||||
@@ -59,7 +59,8 @@ export type TemplateUseCase =
|
||||
| "contract_review"
|
||||
| "agentic_rag"
|
||||
| "code_generator"
|
||||
| "document_generator";
|
||||
| "document_generator"
|
||||
| "hitl";
|
||||
// Config for both file and folder
|
||||
export type FileSourceConfig =
|
||||
| {
|
||||
|
||||
@@ -4,6 +4,7 @@ import path from "path";
|
||||
import { bold, cyan, red, yellow } from "picocolors";
|
||||
import { assetRelocator, copy } from "../helpers/copy";
|
||||
import { callPackageManager } from "../helpers/install";
|
||||
import { NO_DATA_USE_CASES } from "./constant";
|
||||
import { templatesDir } from "./dir";
|
||||
import { PackageManager } from "./get-pkg-manager";
|
||||
import { InstallTemplateArgs, ModelProvider, TemplateVectorDB } from "./types";
|
||||
@@ -83,7 +84,7 @@ const installLlamaIndexServerTemplate = async ({
|
||||
}
|
||||
|
||||
// Simplify use case code
|
||||
if (useCase === "code_generator" || useCase === "document_generator") {
|
||||
if (useCase && NO_DATA_USE_CASES.includes(useCase)) {
|
||||
// Artifact use case doesn't use index.
|
||||
// We don't need data.ts, generate.ts
|
||||
await fs.rm(path.join(root, "src", "app", "data.ts"));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import prompts from "prompts";
|
||||
import { NO_DATA_USE_CASES } from "../helpers/constant";
|
||||
import { EXAMPLE_10K_SEC_FILES, EXAMPLE_FILE } from "../helpers/datasources";
|
||||
import { askModelConfig } from "../helpers/providers";
|
||||
import { getTools } from "../helpers/tools";
|
||||
@@ -11,7 +12,8 @@ type AppType =
|
||||
| "financial_report"
|
||||
| "deep_research"
|
||||
| "code_generator"
|
||||
| "document_generator";
|
||||
| "document_generator"
|
||||
| "hitl";
|
||||
|
||||
type SimpleAnswers = {
|
||||
appType: AppType;
|
||||
@@ -57,6 +59,12 @@ export const askSimpleQuestions = async (
|
||||
value: "document_generator",
|
||||
description: "Build a OpenAI canvas-styled document generator.",
|
||||
},
|
||||
{
|
||||
title: "Human in the Loop",
|
||||
value: "hitl",
|
||||
description:
|
||||
"Build a CLI command workflow that is reviewed by a human before execution",
|
||||
},
|
||||
],
|
||||
},
|
||||
questionHandlers,
|
||||
@@ -81,7 +89,8 @@ export const askSimpleQuestions = async (
|
||||
);
|
||||
language = newLanguage;
|
||||
|
||||
if (appType !== "code_generator" && appType !== "document_generator") {
|
||||
const shouldAskLlamaCloud = !NO_DATA_USE_CASES.includes(appType);
|
||||
if (shouldAskLlamaCloud) {
|
||||
const { useLlamaCloud: newUseLlamaCloud } = await prompts(
|
||||
{
|
||||
type: "toggle",
|
||||
@@ -170,6 +179,12 @@ const convertAnswers = async (
|
||||
tools: [],
|
||||
modelConfig: MODEL_GPT41,
|
||||
},
|
||||
hitl: {
|
||||
template: "llamaindexserver",
|
||||
dataSources: [],
|
||||
tools: [],
|
||||
modelConfig: MODEL_GPT41,
|
||||
},
|
||||
};
|
||||
|
||||
const results = lookup[answers.appType];
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardFooter } from "@/components/ui/card";
|
||||
import { JSONValue, useChatUI } from "@llamaindex/chat-ui";
|
||||
import React, { FC, useState } from "react";
|
||||
import { z } from "zod";
|
||||
|
||||
// This schema is equivalent to the CLICommand model defined in events.py
|
||||
const CLIInputEventSchema = z.object({
|
||||
command: z.string(),
|
||||
});
|
||||
type CLIInputEvent = z.infer<typeof CLIInputEventSchema>;
|
||||
|
||||
const CLIHumanInput: FC<{
|
||||
events: JSONValue[];
|
||||
}> = ({ events }) => {
|
||||
const inputEvent = (events || [])
|
||||
.map((ev) => {
|
||||
const parseResult = CLIInputEventSchema.safeParse(ev);
|
||||
return parseResult.success ? parseResult.data : null;
|
||||
})
|
||||
.filter((ev): ev is CLIInputEvent => ev !== null)
|
||||
.at(-1);
|
||||
|
||||
const { append } = useChatUI();
|
||||
const [confirmedValue, setConfirmedValue] = useState<boolean | null>(null);
|
||||
const [editableCommand, setEditableCommand] = useState<string | undefined>(
|
||||
inputEvent?.command,
|
||||
);
|
||||
|
||||
// Update editableCommand if inputEvent changes (e.g. new event comes in)
|
||||
React.useEffect(() => {
|
||||
setEditableCommand(inputEvent?.command);
|
||||
}, [inputEvent?.command]);
|
||||
|
||||
const handleConfirm = () => {
|
||||
append({
|
||||
content: "Yes",
|
||||
role: "user",
|
||||
annotations: [
|
||||
{
|
||||
type: "human_response",
|
||||
data: {
|
||||
execute: true,
|
||||
command: editableCommand, // Use editable command
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
setConfirmedValue(true);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
append({
|
||||
content: "No",
|
||||
role: "user",
|
||||
annotations: [
|
||||
{
|
||||
type: "human_response",
|
||||
data: {
|
||||
execute: false,
|
||||
command: inputEvent?.command,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
setConfirmedValue(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className="my-4">
|
||||
<CardContent className="pt-6">
|
||||
<p className="text-sm text-gray-700">
|
||||
Do you want to execute the following command?
|
||||
</p>
|
||||
<input
|
||||
disabled
|
||||
type="text"
|
||||
value={editableCommand || ""}
|
||||
onChange={(e) => setEditableCommand(e.target.value)}
|
||||
className="my-2 w-full overflow-x-auto rounded border border-gray-300 bg-gray-100 p-3 font-mono text-xs text-gray-800"
|
||||
/>
|
||||
</CardContent>
|
||||
{confirmedValue === null ? (
|
||||
<CardFooter className="flex justify-end gap-2">
|
||||
<>
|
||||
<Button onClick={handleConfirm}>Yes</Button>
|
||||
<Button onClick={handleCancel}>No</Button>
|
||||
</>
|
||||
</CardFooter>
|
||||
) : null}
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default CLIHumanInput;
|
||||
@@ -0,0 +1,109 @@
|
||||
This is a [LlamaIndex](https://www.llamaindex.ai/) project using [Workflows](https://docs.llamaindex.ai/en/stable/understanding/workflows/).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, setup the environment with uv:
|
||||
|
||||
> **_Note:_** This step is not needed if you are using the dev-container.
|
||||
|
||||
```shell
|
||||
uv sync
|
||||
```
|
||||
|
||||
Then check the parameters that have been pre-configured in the `.env` file in this directory.
|
||||
Make sure you have set the `OPENAI_API_KEY` for the LLM.
|
||||
|
||||
Then, run the development server:
|
||||
|
||||
```shell
|
||||
uv run fastapi dev
|
||||
```
|
||||
|
||||
Then open [http://localhost:8000](http://localhost:8000) with your browser to start the chat UI.
|
||||
|
||||
To start the app optimized for **production**, run:
|
||||
|
||||
```
|
||||
uv run fastapi run
|
||||
```
|
||||
|
||||
## Configure LLM and Embedding Model
|
||||
|
||||
You can configure [LLM model](https://docs.llamaindex.ai/en/stable/module_guides/models/llms) and [embedding model](https://docs.llamaindex.ai/en/stable/module_guides/models/embeddings) in [settings.py](app/settings.py).
|
||||
|
||||
## Use Case
|
||||
|
||||
This example shows how to use the LlamaIndexServer with a human in the loop. It allows you to start CLI commands that are reviewed by a human before execution.
|
||||
|
||||
To update the workflow, you can modify the code in [`workflow.py`](app/workflow.py).
|
||||
|
||||
You can start by sending an request on the [chat UI](http://localhost:8000) or you can test the `/api/chat` endpoint with the following curl request:
|
||||
|
||||
```
|
||||
curl --location 'localhost:8000/api/chat' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{ "messages": [{ "role": "user", "content": "Show me the files in the current directory" }] }'
|
||||
```
|
||||
|
||||
## How does HITL work?
|
||||
|
||||
### Events
|
||||
|
||||
The human-in-the-loop approach used here is based on a simple idea: the workflow pauses and waits for a human response before proceeding to the next step.
|
||||
|
||||
To do this, you will need to implement two custom events:
|
||||
|
||||
- [HumanInputEvent](https://github.com/run-llama/create-llama/blob/main/packages/server/src/utils/hitl/events.ts): This event is used to request input from the user.
|
||||
- [HumanResponseEvent](https://github.com/run-llama/create-llama/blob/main/packages/server/src/utils/hitl/events.ts): This event is sent to the workflow to resume execution with input from the user.
|
||||
|
||||
In this example, we have implemented these two custom events in [`events.ts`](src/app/events.ts):
|
||||
|
||||
- `cliHumanInputEvent` – to request input from the user for CLI command execution.
|
||||
- `cliHumanResponseEvent` – to resume the workflow with the response from the user.
|
||||
|
||||
```typescript
|
||||
export const cliHumanInputEvent = humanInputEvent<{
|
||||
type: "cli_human_input";
|
||||
data: { command: string };
|
||||
response: typeof cliHumanResponseEvent;
|
||||
}>();
|
||||
|
||||
export const cliHumanResponseEvent = humanResponseEvent<{
|
||||
type: "human_response";
|
||||
data: { execute: boolean; command: string };
|
||||
}>();
|
||||
```
|
||||
|
||||
### UI Component
|
||||
|
||||
HITL also needs a custom UI component, that is shown when the LlamaIndexServer receives the `cliHumanInputEvent`. The name of the component is defined in the `type` field of the `cliHumanInputEvent` - in our case, it is `cli_human_input`, which corresponds to the [cli_human_input.tsx](./components/cli_human_input.tsx) component.
|
||||
|
||||
The custom component must use `append` to send a message with a `human_response` annotation. The data of the annotation must be in the format of the response event `cliHumanResponseEvent`, in our case, for sending to execute the command `ls -l`, we would send:
|
||||
|
||||
```tsx
|
||||
append({
|
||||
content: "Yes",
|
||||
role: "user",
|
||||
annotations: [
|
||||
{
|
||||
type: "human_response",
|
||||
data: {
|
||||
execute: true,
|
||||
command: "ls -l", // The command to execute
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
This component displays the command to execute and the user can choose to execute or cancel the command execution.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about LlamaIndex, take a look at the following resources:
|
||||
|
||||
- [LlamaIndex Documentation](https://docs.llamaindex.ai) - learn about LlamaIndex.
|
||||
- [Workflows Introduction](https://docs.llamaindex.ai/en/stable/understanding/workflows/) - learn about LlamaIndex workflows.
|
||||
- [LlamaIndex Server](https://pypi.org/project/llama-index-server/)
|
||||
|
||||
You can check out [the LlamaIndex GitHub repository](https://github.com/run-llama/llama_index) - your feedback and contributions are welcome!
|
||||
@@ -0,0 +1,34 @@
|
||||
from typing import Type
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from llama_index.server.models import HumanInputEvent, HumanResponseEvent
|
||||
|
||||
|
||||
class CLIHumanResponseEvent(HumanResponseEvent):
|
||||
execute: bool = Field(
|
||||
description="True if the human wants to execute the command, False otherwise."
|
||||
)
|
||||
command: str = Field(description="The command to execute.")
|
||||
|
||||
|
||||
class CLICommand(BaseModel):
|
||||
command: str = Field(description="The command to execute.")
|
||||
|
||||
|
||||
# We need an event that extends from HumanInputEvent for HITL feature
|
||||
class CLIHumanInputEvent(HumanInputEvent):
|
||||
"""
|
||||
CLIInputRequiredEvent is sent when the agent needs permission from the user to execute the CLI command or not.
|
||||
Render this event by showing the command and a boolean button to execute the command or not.
|
||||
"""
|
||||
|
||||
event_type: str = (
|
||||
"cli_human_input" # used by UI to render with appropriate component
|
||||
)
|
||||
response_event_type: Type = (
|
||||
CLIHumanResponseEvent # used by workflow to resume with the correct event
|
||||
)
|
||||
data: CLICommand = Field( # the data that sent to the UI for rendering
|
||||
description="The command to execute.",
|
||||
)
|
||||
@@ -0,0 +1,87 @@
|
||||
import platform
|
||||
import subprocess
|
||||
from typing import Any
|
||||
|
||||
from app.events import CLICommand, CLIHumanInputEvent, CLIHumanResponseEvent
|
||||
|
||||
from llama_index.core.prompts import PromptTemplate
|
||||
from llama_index.core.settings import Settings
|
||||
from llama_index.core.workflow import (
|
||||
Context,
|
||||
StartEvent,
|
||||
StopEvent,
|
||||
Workflow,
|
||||
step,
|
||||
)
|
||||
|
||||
|
||||
def create_workflow() -> Workflow:
|
||||
return CLIWorkflow()
|
||||
|
||||
|
||||
class CLIWorkflow(Workflow):
|
||||
"""
|
||||
A workflow has ability to execute command line tool with human in the loop for confirmation.
|
||||
"""
|
||||
|
||||
default_prompt = PromptTemplate(
|
||||
template="""
|
||||
You are a helpful assistant who can write CLI commands to execute using {cli_language}.
|
||||
Your task is to analyze the user's request and write a CLI command to execute.
|
||||
|
||||
## User Request
|
||||
{user_request}
|
||||
|
||||
Don't be verbose, only respond with the CLI command without any other text.
|
||||
"""
|
||||
)
|
||||
|
||||
def __init__(self, **kwargs: Any) -> None:
|
||||
# HITL Workflow should disable timeout otherwise, we will get a timeout error from callback
|
||||
kwargs["timeout"] = None
|
||||
super().__init__(**kwargs)
|
||||
|
||||
@step
|
||||
async def start(self, ctx: Context, ev: StartEvent) -> CLIHumanInputEvent:
|
||||
user_msg = ev.user_msg
|
||||
if user_msg is None:
|
||||
raise ValueError("Missing user_msg in StartEvent")
|
||||
await ctx.set("user_msg", user_msg)
|
||||
# Request LLM to generate a CLI command
|
||||
os_name = platform.system()
|
||||
if os_name == "Linux" or os_name == "Darwin":
|
||||
cli_language = "bash"
|
||||
else:
|
||||
cli_language = "cmd"
|
||||
prompt = self.default_prompt.format(
|
||||
user_request=user_msg, cli_language=cli_language
|
||||
)
|
||||
llm = Settings.llm
|
||||
if llm is None:
|
||||
raise ValueError("Missing LLM in Settings")
|
||||
response = await llm.acomplete(prompt, formatted=True)
|
||||
command = response.text.strip()
|
||||
if command == "":
|
||||
raise ValueError("Couldn't generate a command")
|
||||
# Send the command to the user for confirmation
|
||||
await ctx.set("command", command)
|
||||
return CLIHumanInputEvent( # type: ignore
|
||||
data=CLICommand(command=command),
|
||||
response_event_type=CLIHumanResponseEvent,
|
||||
)
|
||||
|
||||
@step
|
||||
async def handle_human_response(
|
||||
self,
|
||||
ctx: Context,
|
||||
ev: CLIHumanResponseEvent, # This event is sent by LlamaIndexServer when user response
|
||||
) -> StopEvent:
|
||||
# If we have human response, check the confirmation and execute the command
|
||||
if ev.execute:
|
||||
command = ev.command or ""
|
||||
if command == "":
|
||||
raise ValueError("Missing command in CLIExecutionEvent")
|
||||
res = subprocess.run(command, shell=True, capture_output=True, text=True)
|
||||
return StopEvent(result=res.stdout or res.stderr)
|
||||
else:
|
||||
return StopEvent(result=None)
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
This is a [LlamaIndex](https://www.llamaindex.ai/) project bootstrapped with [`create-llama`](https://github.com/run-llama/LlamaIndexTS/tree/main/packages/create-llama).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, install the dependencies:
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
Second, run the development server:
|
||||
|
||||
```
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the chat UI.
|
||||
|
||||
## Configure LLM and Embedding Model
|
||||
|
||||
You can configure [LLM model](https://ts.llamaindex.ai/docs/llamaindex/modules/llms) in the [settings file](src/app/settings.ts).
|
||||
|
||||
## Use Case
|
||||
|
||||
This example shows how to use the LlamaIndexServer with a human in the loop. It allows you to start CLI commands that are reviewed by a human before execution.
|
||||
|
||||
To update the workflow, you can modify the code in [`workflow.py`](app/workflow.py).
|
||||
|
||||
You can start by sending an request on the [chat UI](http://localhost:8000) or you can test the `/api/chat` endpoint with the following curl request:
|
||||
|
||||
```
|
||||
curl --location 'localhost:8000/api/chat' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{ "messages": [{ "role": "user", "content": "Show me the files in the current directory" }] }'
|
||||
```
|
||||
|
||||
## How does HITL work?
|
||||
|
||||
### Events
|
||||
|
||||
The human-in-the-loop approach used here is based on a simple idea: the workflow pauses and waits for a human response before proceeding to the next step.
|
||||
|
||||
To do this, you will need to implement two custom events:
|
||||
|
||||
- [HumanInputEvent](https://github.com/run-llama/create-llama/blob/main/packages/server/src/utils/hitl/events.ts): This event is used to request input from the user.
|
||||
- [HumanResponseEvent](https://github.com/run-llama/create-llama/blob/main/packages/server/src/utils/hitl/events.ts): This event is sent to the workflow to resume execution with input from the user.
|
||||
|
||||
In this example, we have implemented these two custom events in [`events.ts`](src/app/events.ts):
|
||||
|
||||
- `cliHumanInputEvent` – to request input from the user for CLI command execution.
|
||||
- `cliHumanResponseEvent` – to resume the workflow with the response from the user.
|
||||
|
||||
```typescript
|
||||
export const cliHumanInputEvent = humanInputEvent<{
|
||||
type: "cli_human_input";
|
||||
data: { command: string };
|
||||
response: typeof cliHumanResponseEvent;
|
||||
}>();
|
||||
|
||||
export const cliHumanResponseEvent = humanResponseEvent<{
|
||||
type: "human_response";
|
||||
data: { execute: boolean; command: string };
|
||||
}>();
|
||||
```
|
||||
|
||||
### UI Component
|
||||
|
||||
HITL also needs a custom UI component, that is shown when the LlamaIndexServer receives the `cliHumanInputEvent`. The name of the component is defined in the `type` field of the `cliHumanInputEvent` - in our case, it is `cli_human_input`, which corresponds to the [cli_human_input.tsx](./components/cli_human_input.tsx) component.
|
||||
|
||||
The custom component must use `append` to send a message with a `human_response` annotation. The data of the annotation must be in the format of the response event `cliHumanResponseEvent`, in our case, for sending to execute the command `ls -l`, we would send:
|
||||
|
||||
```tsx
|
||||
append({
|
||||
content: "Yes",
|
||||
role: "user",
|
||||
annotations: [
|
||||
{
|
||||
type: "human_response",
|
||||
data: {
|
||||
execute: true,
|
||||
command: "ls -l", // The command to execute
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
This component displays the command to execute and the user can choose to execute or cancel the command execution.
|
||||
|
||||
## Eject Mode
|
||||
|
||||
If you want to fully customize the server UI and routes, you can use `npm eject`. It will create a normal Next.js project with the same functionality as @llamaindex/server.
|
||||
|
||||
```bash
|
||||
npm run eject
|
||||
```
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn more about LlamaIndex, take a look at the following resources:
|
||||
|
||||
- [LlamaIndex Documentation](https://docs.llamaindex.ai) - learn about LlamaIndex (Python features).
|
||||
- [LlamaIndexTS Documentation](https://ts.llamaindex.ai/docs/llamaindex) - learn about LlamaIndex (Typescript features).
|
||||
- [Workflows Introduction](https://ts.llamaindex.ai/docs/llamaindex/modules/workflows) - learn about LlamaIndexTS workflows.
|
||||
|
||||
You can check out [the LlamaIndexTS GitHub repository](https://github.com/run-llama/LlamaIndexTS) - your feedback and contributions are welcome!
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
import { humanInputEvent, humanResponseEvent } from "@llamaindex/server";
|
||||
|
||||
export const cliHumanInputEvent = humanInputEvent<{
|
||||
type: "cli_human_input";
|
||||
data: { command: string };
|
||||
response: typeof cliHumanResponseEvent;
|
||||
}>();
|
||||
|
||||
export const cliHumanResponseEvent = humanResponseEvent<{
|
||||
type: "human_response";
|
||||
data: { execute: boolean; command: string };
|
||||
}>();
|
||||
@@ -0,0 +1,20 @@
|
||||
import { execSync } from "child_process";
|
||||
import { tool } from "llamaindex";
|
||||
import { z } from "zod";
|
||||
|
||||
export const cliExecutor = tool({
|
||||
name: "cli_executor",
|
||||
description: "This tool executes a command and returns the output.",
|
||||
parameters: z.object({ command: z.string() }),
|
||||
execute: async ({ command }) => {
|
||||
try {
|
||||
const output = execSync(command, {
|
||||
encoding: "utf-8",
|
||||
});
|
||||
return output;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return "Command failed";
|
||||
}
|
||||
},
|
||||
});
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
import { toAgentRunEvent, writeResponseToStream } from "@llamaindex/server";
|
||||
import { chatWithTools } from "@llamaindex/tools";
|
||||
import {
|
||||
createWorkflow,
|
||||
getContext,
|
||||
startAgentEvent,
|
||||
stopAgentEvent,
|
||||
withSnapshot,
|
||||
workflowEvent,
|
||||
} from "@llamaindex/workflow";
|
||||
import { ChatMessage, Settings, ToolCallLLM } from "llamaindex";
|
||||
import { cliHumanInputEvent, cliHumanResponseEvent } from "./events";
|
||||
import { cliExecutor } from "./tools";
|
||||
|
||||
const summaryEvent = workflowEvent<string>(); // simple event to summarize the result
|
||||
|
||||
export const workflowFactory = (body: unknown) => {
|
||||
const llm = Settings.llm as ToolCallLLM;
|
||||
|
||||
if (!llm.supportToolCall) {
|
||||
throw new Error("LLM is not a ToolCallLLM");
|
||||
}
|
||||
|
||||
const { messages } = body as { messages: ChatMessage[] };
|
||||
|
||||
const workflow = withSnapshot(createWorkflow());
|
||||
|
||||
workflow.handle([startAgentEvent], async ({ data }) => {
|
||||
const { userInput, chatHistory = [] } = data;
|
||||
if (!userInput) {
|
||||
throw new Error("User input is required");
|
||||
}
|
||||
|
||||
// in this example, we use chatWithTools to decide should perform a tool call or not
|
||||
// if cli executor is called, emit HumanInputEvent to ask user for permission
|
||||
const toolCallResponse = await chatWithTools(
|
||||
llm,
|
||||
[cliExecutor],
|
||||
chatHistory.concat({ role: "user", content: userInput }),
|
||||
);
|
||||
const cliExecutorToolCall = toolCallResponse.toolCalls.find(
|
||||
(toolCall) => toolCall.name === cliExecutor.metadata.name,
|
||||
);
|
||||
const command = cliExecutorToolCall?.input?.command as string;
|
||||
if (command) {
|
||||
return cliHumanInputEvent.with({
|
||||
type: "cli_human_input",
|
||||
data: { command },
|
||||
response: cliHumanResponseEvent,
|
||||
});
|
||||
}
|
||||
|
||||
// if no tool call, just response as normal
|
||||
return summaryEvent.with("");
|
||||
});
|
||||
|
||||
// do actions after getting response from human
|
||||
workflow.handle([cliHumanResponseEvent], async ({ data }) => {
|
||||
const { sendEvent } = getContext();
|
||||
const { command, execute } = data.data;
|
||||
|
||||
if (!execute) {
|
||||
// stop the workflow if user reject to execute the command
|
||||
return summaryEvent.with(`User reject to execute the command ${command}`);
|
||||
}
|
||||
|
||||
sendEvent(
|
||||
toAgentRunEvent({
|
||||
agent: "CLI Executor",
|
||||
text: `Execute the command "${command}" and return the result`,
|
||||
type: "text",
|
||||
}),
|
||||
);
|
||||
|
||||
const result = (await cliExecutor.call({ command })) as string;
|
||||
|
||||
return summaryEvent.with(
|
||||
`Executed the command ${command} and got the result: ${result}`,
|
||||
);
|
||||
});
|
||||
|
||||
workflow.handle([summaryEvent], async ({ data: summaryResult }) => {
|
||||
const { sendEvent } = getContext();
|
||||
|
||||
const chatHistory = messages;
|
||||
if (summaryResult) {
|
||||
chatHistory.push({ role: "user", content: summaryResult });
|
||||
}
|
||||
|
||||
const stream = await llm.chat({
|
||||
messages: chatHistory,
|
||||
stream: true,
|
||||
});
|
||||
|
||||
const result = await writeResponseToStream(stream, sendEvent);
|
||||
|
||||
return stopAgentEvent.with({ result });
|
||||
});
|
||||
|
||||
return workflow;
|
||||
};
|
||||
@@ -12,7 +12,7 @@
|
||||
"dependencies": {
|
||||
"@llamaindex/openai": "~0.4.0",
|
||||
"@llamaindex/server": "~0.2.1",
|
||||
"@llamaindex/workflow": "~1.1.3",
|
||||
"@llamaindex/workflow": "~1.1.8",
|
||||
"@llamaindex/tools": "~0.0.11",
|
||||
"llamaindex": "~0.11.0",
|
||||
"dotenv": "^16.4.7",
|
||||
@@ -20,7 +20,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.10.3",
|
||||
"tsx": "^4.7.2",
|
||||
"tsx": "4.7.2",
|
||||
"typescript": "^5.3.2",
|
||||
"nodemon": "^3.1.10"
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ LlamaIndexServer is a Next.js-based application that allows you to quickly launc
|
||||
- Edit code and document artifacts in an OpenAI Canvas-style UI
|
||||
- Extendable UI components for events and headers
|
||||
- Built on Next.js for high performance and easy API development
|
||||
- Human-in-the-loop (HITL) support, check out the [Human-in-the-loop](https://github.com/run-llama/create-llama/blob/main/packages/server/examples/hitl/README.md) documentation for more details.
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
# Human in the Loop
|
||||
|
||||
This example shows how to use the LlamaIndexServer with a human in the loop. It allows you to start CLI commands that are reviewed by a human before execution.
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Environment Setup
|
||||
|
||||
Export your OpenAI API key:
|
||||
|
||||
```bash
|
||||
export OPENAI_API_KEY=<your-openai-api-key>
|
||||
```
|
||||
|
||||
### Starting the Server
|
||||
|
||||
Run the server in development mode:
|
||||
|
||||
```bash
|
||||
npx nodemon --exec tsx index.ts --ignore output/*
|
||||
```
|
||||
|
||||
### Access the Application
|
||||
|
||||
Open your browser and go to:
|
||||
|
||||
```
|
||||
http://localhost:3000
|
||||
```
|
||||
|
||||
You will see the LlamaIndexServer UI, where you can interact with the HITL agent. Try "List all files in the current directory" and see how the agent pauses and waits for a human response before executing the command.
|
||||
|
||||
## How does HITL work?
|
||||
|
||||
### Events
|
||||
|
||||
The human-in-the-loop approach used here is based on a simple idea: the workflow pauses and waits for a human response before proceeding to the next step.
|
||||
|
||||
To do this, you will need to implement two custom events:
|
||||
|
||||
- [HumanInputEvent](https://github.com/run-llama/create-llama/blob/main/packages/server/src/utils/hitl/events.ts): This event is used to request input from the user.
|
||||
- [HumanResponseEvent](https://github.com/run-llama/create-llama/blob/main/packages/server/src/utils/hitl/events.ts): This event is sent to the workflow to resume execution with input from the user.
|
||||
|
||||
In this example, we have implemented these two custom events in [`events.ts`](src/app/events.ts):
|
||||
|
||||
- `cliHumanInputEvent` – to request input from the user for CLI command execution.
|
||||
- `cliHumanResponseEvent` – to resume the workflow with the response from the user.
|
||||
|
||||
```typescript
|
||||
export const cliHumanInputEvent = humanInputEvent<{
|
||||
type: "cli_human_input";
|
||||
data: { command: string };
|
||||
response: typeof cliHumanResponseEvent;
|
||||
}>();
|
||||
|
||||
export const cliHumanResponseEvent = humanResponseEvent<{
|
||||
type: "human_response";
|
||||
data: { execute: boolean; command: string };
|
||||
}>();
|
||||
```
|
||||
|
||||
### UI Component
|
||||
|
||||
HITL also needs a custom UI component, that is shown when the LlamaIndexServer receives the `cliHumanInputEvent`. The name of the component is defined in the `type` field of the `cliHumanInputEvent` - in our case, it is `cli_human_input`, which corresponds to the [cli_human_input.tsx](./components/cli_human_input.tsx) component.
|
||||
|
||||
The custom component must use `append` to send a message with a `human_response` annotation. The data of the annotation must be in the format of the response event `cliHumanResponseEvent`, in our case, for sending to execute the command `ls -l`, we would send:
|
||||
|
||||
```tsx
|
||||
append({
|
||||
content: "Yes",
|
||||
role: "user",
|
||||
annotations: [
|
||||
{
|
||||
type: "human_response",
|
||||
data: {
|
||||
execute: true,
|
||||
command: "ls -l", // The command to execute
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
This component displays the command to execute and the user can choose to execute or cancel the command execution.
|
||||
|
||||
### Workflow Implementation
|
||||
|
||||
The workflow is implemented in [`workflow.ts`](src/app/workflow.ts) using LlamaIndex workflows. The workflow handles three main steps:
|
||||
|
||||
1. **Initial Request Handling**: When a user input is received, the workflow uses `chatWithTools` to determine if a CLI command should be executed. If so, it emits a `cliHumanInputEvent` to request user permission.
|
||||
|
||||
```typescript
|
||||
workflow.handle([startAgentEvent], async ({ data }) => {
|
||||
const { userInput, chatHistory = [] } = data;
|
||||
|
||||
const toolCallResponse = await chatWithTools(
|
||||
llm,
|
||||
[cliExecutor],
|
||||
chatHistory.concat({ role: "user", content: userInput }),
|
||||
);
|
||||
|
||||
const cliExecutorToolCall = toolCallResponse.toolCalls.find(
|
||||
(toolCall) => toolCall.name === cliExecutor.metadata.name,
|
||||
);
|
||||
|
||||
const command = cliExecutorToolCall?.input?.command as string;
|
||||
if (command) {
|
||||
return cliHumanInputEvent.with({
|
||||
type: "cli_human_input",
|
||||
data: { command },
|
||||
response: cliHumanResponseEvent,
|
||||
});
|
||||
}
|
||||
|
||||
return summaryEvent.with("");
|
||||
});
|
||||
```
|
||||
|
||||
2. **Human Response Handling**: After receiving human input, the workflow either executes the command or cancels based on the user's choice.
|
||||
|
||||
```typescript
|
||||
workflow.handle([cliHumanResponseEvent], async ({ data }) => {
|
||||
const { command, execute } = data.data;
|
||||
|
||||
if (!execute) {
|
||||
return summaryEvent.with(`User reject to execute the command ${command}`);
|
||||
}
|
||||
|
||||
const result = (await cliExecutor.call({ command })) as string;
|
||||
|
||||
return summaryEvent.with(
|
||||
`Executed the command ${command} and got the result: ${result}`,
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
3. **Final Response**: The workflow generates a final response based on the execution result and streams it back to the user.
|
||||
|
||||
### Tools
|
||||
|
||||
The CLI executor tool is defined in [`tools.ts`](src/app/tools.ts):
|
||||
|
||||
```typescript
|
||||
export const cliExecutor = tool({
|
||||
name: "cli_executor",
|
||||
description: "This tool executes a command and returns the output.",
|
||||
parameters: z.object({ command: z.string() }),
|
||||
execute: async ({ command }) => {
|
||||
try {
|
||||
const output = execSync(command, {
|
||||
encoding: "utf-8",
|
||||
});
|
||||
return output;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return "Command failed";
|
||||
}
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
The HITL implementation consists of:
|
||||
|
||||
1. **Workflow Factory** (`workflow.ts`): Creates and configures the workflow with event handlers
|
||||
2. **Events** (`events.ts`): Defines typed events for human input and response
|
||||
3. **Tools** (`tools.ts`): Implements the CLI executor tool
|
||||
4. **UI Component** (`components/cli_human_input.tsx`): Provides the user interface for human approval
|
||||
5. **Server Entry** (`index.ts`): Configures and starts the LlamaIndexServer
|
||||
|
||||
This architecture ensures that dangerous operations like CLI command execution require explicit human approval before proceeding.
|
||||
@@ -0,0 +1,95 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Card, CardContent, CardFooter } from "@/components/ui/card";
|
||||
import { JSONValue, useChatUI } from "@llamaindex/chat-ui";
|
||||
import React, { FC, useState } from "react";
|
||||
import { z } from "zod";
|
||||
|
||||
// This schema is equivalent to the CLICommand model defined in events.py
|
||||
const CLIInputEventSchema = z.object({
|
||||
command: z.string(),
|
||||
});
|
||||
type CLIInputEvent = z.infer<typeof CLIInputEventSchema>;
|
||||
|
||||
const CLIHumanInput: FC<{
|
||||
events: JSONValue[];
|
||||
}> = ({ events }) => {
|
||||
const inputEvent = (events || [])
|
||||
.map((ev) => {
|
||||
const parseResult = CLIInputEventSchema.safeParse(ev);
|
||||
return parseResult.success ? parseResult.data : null;
|
||||
})
|
||||
.filter((ev): ev is CLIInputEvent => ev !== null)
|
||||
.at(-1);
|
||||
|
||||
const { append } = useChatUI();
|
||||
const [confirmedValue, setConfirmedValue] = useState<boolean | null>(null);
|
||||
const [editableCommand, setEditableCommand] = useState<string | undefined>(
|
||||
inputEvent?.command,
|
||||
);
|
||||
|
||||
// Update editableCommand if inputEvent changes (e.g. new event comes in)
|
||||
React.useEffect(() => {
|
||||
setEditableCommand(inputEvent?.command);
|
||||
}, [inputEvent?.command]);
|
||||
|
||||
const handleConfirm = () => {
|
||||
append({
|
||||
content: "Yes",
|
||||
role: "user",
|
||||
annotations: [
|
||||
{
|
||||
type: "human_response",
|
||||
data: {
|
||||
execute: true,
|
||||
command: editableCommand, // Use editable command
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
setConfirmedValue(true);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
append({
|
||||
content: "No",
|
||||
role: "user",
|
||||
annotations: [
|
||||
{
|
||||
type: "human_response",
|
||||
data: {
|
||||
execute: false,
|
||||
command: inputEvent?.command,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
setConfirmedValue(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Card className="my-4">
|
||||
<CardContent className="pt-6">
|
||||
<p className="text-sm text-gray-700">
|
||||
Do you want to execute the following command?
|
||||
</p>
|
||||
<input
|
||||
disabled
|
||||
type="text"
|
||||
value={editableCommand || ""}
|
||||
onChange={(e) => setEditableCommand(e.target.value)}
|
||||
className="my-2 w-full overflow-x-auto rounded border border-gray-300 bg-gray-100 p-3 font-mono text-xs text-gray-800"
|
||||
/>
|
||||
</CardContent>
|
||||
{confirmedValue === null ? (
|
||||
<CardFooter className="flex justify-end gap-2">
|
||||
<>
|
||||
<Button onClick={handleConfirm}>Yes</Button>
|
||||
<Button onClick={handleCancel}>No</Button>
|
||||
</>
|
||||
</CardFooter>
|
||||
) : null}
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default CLIHumanInput;
|
||||
@@ -0,0 +1,20 @@
|
||||
import { OpenAI } from "@llamaindex/openai";
|
||||
import { LlamaIndexServer } from "@llamaindex/server";
|
||||
import { Settings } from "llamaindex";
|
||||
import { workflowFactory } from "./src/app/workflow";
|
||||
|
||||
Settings.llm = new OpenAI({
|
||||
model: "gpt-4o-mini",
|
||||
});
|
||||
|
||||
new LlamaIndexServer({
|
||||
workflow: workflowFactory,
|
||||
uiConfig: {
|
||||
starterQuestions: [
|
||||
"Check status of git in the current directory",
|
||||
"List all files in the current directory",
|
||||
],
|
||||
componentsDir: "components",
|
||||
},
|
||||
port: 3000,
|
||||
}).start();
|
||||
@@ -0,0 +1,12 @@
|
||||
import { humanInputEvent, humanResponseEvent } from "@llamaindex/server";
|
||||
|
||||
export const cliHumanInputEvent = humanInputEvent<{
|
||||
type: "cli_human_input";
|
||||
data: { command: string };
|
||||
response: typeof cliHumanResponseEvent;
|
||||
}>();
|
||||
|
||||
export const cliHumanResponseEvent = humanResponseEvent<{
|
||||
type: "human_response";
|
||||
data: { execute: boolean; command: string };
|
||||
}>();
|
||||
@@ -0,0 +1,20 @@
|
||||
import { execSync } from "child_process";
|
||||
import { tool } from "llamaindex";
|
||||
import { z } from "zod";
|
||||
|
||||
export const cliExecutor = tool({
|
||||
name: "cli_executor",
|
||||
description: "This tool executes a command and returns the output.",
|
||||
parameters: z.object({ command: z.string() }),
|
||||
execute: async ({ command }) => {
|
||||
try {
|
||||
const output = execSync(command, {
|
||||
encoding: "utf-8",
|
||||
});
|
||||
return output;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return "Command failed";
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,106 @@
|
||||
import { OpenAI } from "@llamaindex/openai";
|
||||
import { toAgentRunEvent, writeResponseToStream } from "@llamaindex/server";
|
||||
import { chatWithTools } from "@llamaindex/tools";
|
||||
import {
|
||||
createWorkflow,
|
||||
getContext,
|
||||
startAgentEvent,
|
||||
stopAgentEvent,
|
||||
withSnapshot,
|
||||
workflowEvent,
|
||||
} from "@llamaindex/workflow";
|
||||
import { ChatMessage, Settings, ToolCallLLM } from "llamaindex";
|
||||
import { cliHumanInputEvent, cliHumanResponseEvent } from "./events";
|
||||
import { cliExecutor } from "./tools";
|
||||
|
||||
Settings.llm = new OpenAI({
|
||||
model: "gpt-4o-mini",
|
||||
});
|
||||
|
||||
const summaryEvent = workflowEvent<string>(); // simple event to summarize the result
|
||||
|
||||
export const workflowFactory = (body: unknown) => {
|
||||
const llm = Settings.llm as ToolCallLLM;
|
||||
|
||||
if (!llm.supportToolCall) {
|
||||
throw new Error("LLM is not a ToolCallLLM");
|
||||
}
|
||||
|
||||
const { messages } = body as { messages: ChatMessage[] };
|
||||
|
||||
const workflow = withSnapshot(createWorkflow());
|
||||
|
||||
workflow.handle([startAgentEvent], async ({ data }) => {
|
||||
const { userInput, chatHistory = [] } = data;
|
||||
if (!userInput) {
|
||||
throw new Error("User input is required");
|
||||
}
|
||||
|
||||
// in this example, we use chatWithTools to decide should perform a tool call or not
|
||||
// if cli executor is called, emit HumanInputEvent to ask user for permission
|
||||
const toolCallResponse = await chatWithTools(
|
||||
llm,
|
||||
[cliExecutor],
|
||||
chatHistory.concat({ role: "user", content: userInput }),
|
||||
);
|
||||
const cliExecutorToolCall = toolCallResponse.toolCalls.find(
|
||||
(toolCall) => toolCall.name === cliExecutor.metadata.name,
|
||||
);
|
||||
const command = cliExecutorToolCall?.input?.command as string;
|
||||
if (command) {
|
||||
return cliHumanInputEvent.with({
|
||||
type: "cli_human_input",
|
||||
data: { command },
|
||||
response: cliHumanResponseEvent,
|
||||
});
|
||||
}
|
||||
|
||||
// if no tool call, just response as normal
|
||||
return summaryEvent.with("");
|
||||
});
|
||||
|
||||
// do actions after getting response from human
|
||||
workflow.handle([cliHumanResponseEvent], async ({ data }) => {
|
||||
const { sendEvent } = getContext();
|
||||
const { command, execute } = data.data;
|
||||
|
||||
if (!execute) {
|
||||
// stop the workflow if user reject to execute the command
|
||||
return summaryEvent.with(`User reject to execute the command ${command}`);
|
||||
}
|
||||
|
||||
sendEvent(
|
||||
toAgentRunEvent({
|
||||
agent: "CLI Executor",
|
||||
text: `Execute the command "${command}" and return the result`,
|
||||
type: "text",
|
||||
}),
|
||||
);
|
||||
|
||||
const result = (await cliExecutor.call({ command })) as string;
|
||||
|
||||
return summaryEvent.with(
|
||||
`Executed the command ${command} and got the result: ${result}`,
|
||||
);
|
||||
});
|
||||
|
||||
workflow.handle([summaryEvent], async ({ data: summaryResult }) => {
|
||||
const { sendEvent } = getContext();
|
||||
|
||||
const chatHistory = messages;
|
||||
if (summaryResult) {
|
||||
chatHistory.push({ role: "user", content: summaryResult });
|
||||
}
|
||||
|
||||
const stream = await llm.chat({
|
||||
messages: chatHistory,
|
||||
stream: true,
|
||||
});
|
||||
|
||||
const result = await writeResponseToStream(stream, sendEvent);
|
||||
|
||||
return stopAgentEvent.with({ result });
|
||||
});
|
||||
|
||||
return workflow;
|
||||
};
|
||||
@@ -18,7 +18,7 @@
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.10.3",
|
||||
"nodemon": "^3.1.10",
|
||||
"tsx": "^4.7.2",
|
||||
"tsx": "4.7.2",
|
||||
"typescript": "^5.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,5 +10,5 @@
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": ["**/*"],
|
||||
"exclude": ["node_modules", "dist", "custom-layout/layout"]
|
||||
"exclude": ["node_modules", "dist", "custom-layout/layout", "hitl/components"]
|
||||
}
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
import { type AgentInputData } from "@llamaindex/workflow";
|
||||
import { type Message } from "ai";
|
||||
import { type MessageType } from "llamaindex";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
// import chat utils
|
||||
import {
|
||||
getHumanResponsesFromMessage,
|
||||
pauseForHumanInput,
|
||||
processWorkflowStream,
|
||||
runWorkflow,
|
||||
sendSuggestedQuestionsEvent,
|
||||
toDataStream,
|
||||
} from "./utils";
|
||||
|
||||
// import workflow factory and settings from local file
|
||||
import { stopAgentEvent } from "@llamaindex/workflow";
|
||||
import { initSettings } from "./app/settings";
|
||||
import { workflowFactory } from "./app/workflow";
|
||||
|
||||
@@ -21,7 +24,10 @@ export async function POST(req: NextRequest) {
|
||||
const reqBody = await req.json();
|
||||
const suggestNextQuestions = process.env.SUGGEST_NEXT_QUESTIONS === "true";
|
||||
|
||||
const { messages } = reqBody as { messages: Message[] };
|
||||
const { messages, id: requestId } = reqBody as {
|
||||
messages: Message[];
|
||||
id?: string;
|
||||
};
|
||||
const chatHistory = messages.map((message) => ({
|
||||
role: message.role as MessageType,
|
||||
content: message.content,
|
||||
@@ -36,25 +42,31 @@ export async function POST(req: NextRequest) {
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
const workflowInput: AgentInputData = {
|
||||
userInput: lastMessage.content,
|
||||
chatHistory,
|
||||
};
|
||||
|
||||
const abortController = new AbortController();
|
||||
req.signal.addEventListener("abort", () =>
|
||||
abortController.abort("Connection closed"),
|
||||
);
|
||||
|
||||
const workflow = await workflowFactory(reqBody);
|
||||
const workflowEventStream = await runWorkflow(
|
||||
workflow,
|
||||
workflowInput,
|
||||
abortController.signal,
|
||||
const context = await runWorkflow({
|
||||
workflow: await workflowFactory(reqBody),
|
||||
input: { userInput: lastMessage.content, chatHistory },
|
||||
human: {
|
||||
snapshotId: requestId, // use requestId to restore snapshot
|
||||
responses: getHumanResponsesFromMessage(lastMessage),
|
||||
},
|
||||
});
|
||||
|
||||
const stream = processWorkflowStream(context.stream).until(
|
||||
(event) =>
|
||||
abortController.signal.aborted || stopAgentEvent.include(event),
|
||||
);
|
||||
|
||||
const dataStream = toDataStream(workflowEventStream, {
|
||||
const dataStream = toDataStream(stream, {
|
||||
callbacks: {
|
||||
onPauseForHumanInput: async (responseEvent) => {
|
||||
await pauseForHumanInput(context, responseEvent, requestId); // use requestId to save snapshot
|
||||
},
|
||||
onFinal: async (completion, dataStreamWriter) => {
|
||||
chatHistory.push({
|
||||
role: "assistant" as MessageType,
|
||||
@@ -66,7 +78,6 @@ export async function POST(req: NextRequest) {
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return new Response(dataStream, {
|
||||
status: 200,
|
||||
headers: {
|
||||
|
||||
@@ -114,7 +114,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@llamaindex/env": "~0.1.30",
|
||||
"@llamaindex/workflow": "~1.1.3",
|
||||
"@llamaindex/workflow": "~1.1.8",
|
||||
"llamaindex": "~0.11.0",
|
||||
"zod": "^3.24.2",
|
||||
"zod-to-json-schema": "^3.23.3"
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"prettier-plugin-organize-imports": "^4.1.0",
|
||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||
"tailwindcss": "^4",
|
||||
"tsx": "^4.19.3",
|
||||
"tsx": "4.7.2",
|
||||
"tw-animate-css": "1.2.5",
|
||||
"typescript": "^5"
|
||||
},
|
||||
@@ -46,7 +46,7 @@
|
||||
"@llamaindex/openai": "~0.4.0",
|
||||
"@llamaindex/readers": "~3.1.4",
|
||||
"@llamaindex/tools": "~0.0.11",
|
||||
"@llamaindex/workflow": "~1.1.3",
|
||||
"@llamaindex/workflow": "~1.1.8",
|
||||
"@radix-ui/react-accordion": "^1.2.3",
|
||||
"@radix-ui/react-alert-dialog": "^1.1.7",
|
||||
"@radix-ui/react-aspect-ratio": "^1.1.3",
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
import type { AgentInputData } from "@llamaindex/workflow";
|
||||
import { stopAgentEvent } from "@llamaindex/workflow";
|
||||
import { type Message } from "ai";
|
||||
import { IncomingMessage, ServerResponse } from "http";
|
||||
import type { MessageType } from "llamaindex";
|
||||
import { type WorkflowFactory } from "../types";
|
||||
import { sendSuggestedQuestionsEvent } from "../utils";
|
||||
import {
|
||||
getHumanResponsesFromMessage,
|
||||
pauseForHumanInput,
|
||||
} from "../utils/hitl";
|
||||
import {
|
||||
parseRequestBody,
|
||||
pipeStreamToResponse,
|
||||
sendJSONResponse,
|
||||
} from "../utils/request";
|
||||
import { toDataStream } from "../utils/stream";
|
||||
import { sendSuggestedQuestionsEvent } from "../utils/suggestion";
|
||||
import { runWorkflow } from "../utils/workflow";
|
||||
import { processWorkflowStream, runWorkflow } from "../utils/workflow";
|
||||
|
||||
export const handleChat = async (
|
||||
req: IncomingMessage,
|
||||
@@ -18,37 +22,47 @@ export const handleChat = async (
|
||||
workflowFactory: WorkflowFactory,
|
||||
suggestNextQuestions: boolean,
|
||||
) => {
|
||||
const abortController = new AbortController();
|
||||
res.on("close", () => abortController.abort("Connection closed"));
|
||||
|
||||
try {
|
||||
const body = await parseRequestBody(req);
|
||||
const { messages } = body as { messages: Message[] };
|
||||
const { messages, id: requestId } = body as {
|
||||
messages: Message[];
|
||||
id?: string;
|
||||
};
|
||||
|
||||
const lastMessage = messages[messages.length - 1];
|
||||
if (lastMessage?.role !== "user" || !lastMessage.content) {
|
||||
return sendJSONResponse(res, 400, {
|
||||
error: "Messages cannot be empty and last message must be from user",
|
||||
});
|
||||
}
|
||||
|
||||
const chatHistory = messages.map((message) => ({
|
||||
role: message.role as MessageType,
|
||||
content: message.content,
|
||||
}));
|
||||
|
||||
const lastMessage = messages[messages.length - 1];
|
||||
if (lastMessage?.role !== "user") {
|
||||
return sendJSONResponse(res, 400, {
|
||||
error: "Messages cannot be empty and last message must be from user",
|
||||
});
|
||||
}
|
||||
const workflowInput: AgentInputData = {
|
||||
userInput: lastMessage.content,
|
||||
chatHistory,
|
||||
};
|
||||
const context = await runWorkflow({
|
||||
workflow: await workflowFactory(body),
|
||||
input: { userInput: lastMessage.content, chatHistory },
|
||||
human: {
|
||||
snapshotId: requestId, // use requestId to restore snapshot
|
||||
responses: getHumanResponsesFromMessage(lastMessage),
|
||||
},
|
||||
});
|
||||
|
||||
const abortController = new AbortController();
|
||||
res.on("close", () => abortController.abort("Connection closed"));
|
||||
|
||||
const workflow = await workflowFactory(body);
|
||||
const workflowEventStream = await runWorkflow(
|
||||
workflow,
|
||||
workflowInput,
|
||||
abortController.signal,
|
||||
const stream = processWorkflowStream(context.stream).until(
|
||||
(event) =>
|
||||
abortController.signal.aborted || stopAgentEvent.include(event),
|
||||
);
|
||||
|
||||
const dataStream = toDataStream(workflowEventStream, {
|
||||
const dataStream = toDataStream(stream, {
|
||||
callbacks: {
|
||||
onPauseForHumanInput: async (responseEvent) => {
|
||||
await pauseForHumanInput(context, responseEvent, requestId); // use requestId to save snapshot
|
||||
},
|
||||
onFinal: async (completion, dataStreamWriter) => {
|
||||
chatHistory.push({
|
||||
role: "assistant" as MessageType,
|
||||
|
||||
@@ -3,5 +3,7 @@ export * from "./types";
|
||||
export * from "./utils/events";
|
||||
export { getStoredFilePath } from "./utils/file";
|
||||
export { generateEventComponent } from "./utils/gen-ui";
|
||||
export * from "./utils/hitl";
|
||||
export * from "./utils/inline";
|
||||
export * from "./utils/prompts";
|
||||
export * from "./utils/stream";
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import {
|
||||
type WorkflowEvent,
|
||||
type WorkflowEventData,
|
||||
workflowEvent,
|
||||
} from "@llamaindex/workflow";
|
||||
import type { Message } from "ai";
|
||||
import type { JSONValue } from "llamaindex";
|
||||
import z from "zod";
|
||||
|
||||
export type HumanInputEventData = {
|
||||
type: string;
|
||||
data?: JSONValue;
|
||||
response: WorkflowEvent<HumanResponseEventData>;
|
||||
};
|
||||
|
||||
export const humanInputEvent = workflowBaseEvent<HumanInputEventData>();
|
||||
|
||||
export type HumanResponseEventData = {
|
||||
type: "human_response";
|
||||
data?: JSONValue;
|
||||
};
|
||||
|
||||
export const humanResponseEvent = workflowBaseEvent<HumanResponseEventData>();
|
||||
|
||||
// helper function to extract human responses from message annotations
|
||||
export const getHumanResponsesFromMessage = (message: Message) => {
|
||||
const schema = z.object({ type: z.literal("human_response"), data: z.any() });
|
||||
return (
|
||||
message.annotations?.filter(
|
||||
(annotation): annotation is z.infer<typeof schema> =>
|
||||
schema.safeParse(annotation).success,
|
||||
) ?? []
|
||||
);
|
||||
};
|
||||
// TODO: move to llama-flow package
|
||||
export type BaseEvent<K> = (<T extends K>() => WorkflowEvent<T>) &
|
||||
WorkflowEvent<K>;
|
||||
|
||||
export function workflowBaseEvent<K = unknown>(): BaseEvent<K> {
|
||||
const baseEvent = workflowEvent<K>();
|
||||
const derivedEvents = new Set<WorkflowEvent<unknown>>();
|
||||
|
||||
function eventFn<T>(): WorkflowEvent<T> {
|
||||
const event = workflowEvent<T>();
|
||||
derivedEvents.add(event);
|
||||
return event;
|
||||
}
|
||||
|
||||
const originalInclude = baseEvent.include;
|
||||
const enhancedBaseEvent = Object.assign(baseEvent, {
|
||||
include: (
|
||||
instance: WorkflowEventData<unknown>,
|
||||
): instance is WorkflowEventData<void> => {
|
||||
// Base event accepts its own instances OR instances from any derived events
|
||||
return (
|
||||
originalInclude(instance) ||
|
||||
Array.from(derivedEvents).some((e) => e.include(instance))
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
return Object.assign(eventFn, enhancedBaseEvent) as typeof eventFn &
|
||||
typeof baseEvent;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./events";
|
||||
export * from "./pause";
|
||||
export * from "./resume";
|
||||
export * from "./snapshot";
|
||||
@@ -0,0 +1,25 @@
|
||||
import {
|
||||
request,
|
||||
type WorkflowContext,
|
||||
type WorkflowEvent,
|
||||
} from "@llamaindex/workflow";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import type { HumanResponseEventData } from "./events";
|
||||
import { ensureSnapshotWorkflowContext, saveSnapshot } from "./snapshot";
|
||||
|
||||
// pause the workflow and save the snapshot
|
||||
export const pauseForHumanInput = async (
|
||||
context: WorkflowContext,
|
||||
responseEvent: WorkflowEvent<HumanResponseEventData>,
|
||||
snapshotId: string = randomUUID(), // automatically generate a request id if not provided
|
||||
) => {
|
||||
const snapshotWorkflowContext = ensureSnapshotWorkflowContext(context);
|
||||
const { snapshot, sendEvent } = snapshotWorkflowContext;
|
||||
|
||||
// send a request event to save the missing step (`humanResponseEvent`) to the snapshot
|
||||
sendEvent(request(responseEvent));
|
||||
|
||||
// get and save snapshot
|
||||
const [_, snapshotData] = await snapshot();
|
||||
await saveSnapshot(snapshotId, snapshotData);
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
import { type Workflow } from "@llamaindex/workflow";
|
||||
import type { HumanResponseEventData } from "./events";
|
||||
import {
|
||||
ensureSnapshotWorkflow,
|
||||
loadSnapshot,
|
||||
type SnapshotWorkflowContext,
|
||||
} from "./snapshot";
|
||||
|
||||
// create workflow context from snapshot and start running it from the last missing step
|
||||
export const resumeWorkflowFromHumanResponses = async (
|
||||
workflow: Workflow, // the workflow to resume
|
||||
humanResponses: Array<HumanResponseEventData>, // human can send multiple responses
|
||||
snapshotId: string,
|
||||
): Promise<SnapshotWorkflowContext> => {
|
||||
// check workflow is snapshotable
|
||||
const snapshotWorkflow = ensureSnapshotWorkflow(workflow);
|
||||
|
||||
const snapshot = await loadSnapshot(snapshotId);
|
||||
if (!snapshot) {
|
||||
// if there is no snapshot, we can't resume the workflow
|
||||
throw new Error("No snapshot found for request id: " + snapshotId);
|
||||
}
|
||||
|
||||
// resume the workflow from the snapshot with human response
|
||||
const context = snapshotWorkflow.resume(humanResponses, snapshot);
|
||||
|
||||
return context;
|
||||
};
|
||||
@@ -0,0 +1,78 @@
|
||||
import {
|
||||
withSnapshot,
|
||||
type Workflow,
|
||||
type WorkflowContext,
|
||||
} from "@llamaindex/workflow";
|
||||
import { promises as fs } from "fs";
|
||||
import path from "path";
|
||||
|
||||
// @llama-flow doesn't export snapshot types, we need to infer them from the functions
|
||||
export type SnapshotWorkflow = ReturnType<typeof withSnapshot<Workflow>>;
|
||||
export type SnapshotWorkflowContext = ReturnType<
|
||||
SnapshotWorkflow["createContext"]
|
||||
>;
|
||||
export type SnapshotData = Awaited<
|
||||
ReturnType<SnapshotWorkflowContext["snapshot"]>
|
||||
>[1];
|
||||
|
||||
const SNAPSHOTS_DIR = path.join("output", "snapshots");
|
||||
|
||||
// Ensure the checkpoints directory exists
|
||||
const ensureCheckpointsDir = async () => {
|
||||
try {
|
||||
await fs.mkdir(SNAPSHOTS_DIR, { recursive: true });
|
||||
} catch (error) {
|
||||
console.error("Failed to create checkpoints directory:", error);
|
||||
}
|
||||
};
|
||||
|
||||
export const saveSnapshot = async (
|
||||
requestId: string,
|
||||
snapshot: SnapshotData,
|
||||
) => {
|
||||
try {
|
||||
await ensureCheckpointsDir();
|
||||
const filePath = path.join(SNAPSHOTS_DIR, `${requestId}.json`);
|
||||
await fs.writeFile(filePath, JSON.stringify(snapshot, null, 2), "utf8");
|
||||
console.log(`Snapshot saved to: ${filePath}`);
|
||||
} catch (error) {
|
||||
console.error("Failed to save snapshot:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const loadSnapshot = async (
|
||||
requestId: string,
|
||||
): Promise<SnapshotData | undefined> => {
|
||||
try {
|
||||
const filePath = path.join(SNAPSHOTS_DIR, `${requestId}.json`);
|
||||
const data = await fs.readFile(filePath, "utf8");
|
||||
return JSON.parse(data);
|
||||
} catch (error) {
|
||||
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
|
||||
return undefined; // File doesn't exist
|
||||
}
|
||||
console.error("Failed to load snapshot:", error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export function ensureSnapshotWorkflow(workflow: Workflow): SnapshotWorkflow {
|
||||
if (!("resume" in workflow)) {
|
||||
throw new Error(
|
||||
"Workflow is not a snapshot workflow. Please use withSnapshot() to make it snapshotable.",
|
||||
);
|
||||
}
|
||||
return workflow as SnapshotWorkflow;
|
||||
}
|
||||
|
||||
export function ensureSnapshotWorkflowContext(
|
||||
context: WorkflowContext,
|
||||
): SnapshotWorkflowContext {
|
||||
if (!("snapshot" in context)) {
|
||||
throw new Error(
|
||||
"Cannot get snapshot of the workflow. Please use withSnapshot() to make workflow snapshotable.",
|
||||
);
|
||||
}
|
||||
return context as SnapshotWorkflowContext;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
export * from "./events";
|
||||
export * from "./file";
|
||||
export * from "./gen-ui";
|
||||
export * from "./hitl";
|
||||
export * from "./inline";
|
||||
export * from "./prompts";
|
||||
export * from "./request";
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import { agentStreamEvent, type WorkflowEventData } from "@llamaindex/workflow";
|
||||
import {
|
||||
agentStreamEvent,
|
||||
type WorkflowEvent,
|
||||
type WorkflowEventData,
|
||||
} from "@llamaindex/workflow";
|
||||
import {
|
||||
createDataStream,
|
||||
formatDataStreamPart,
|
||||
type DataStreamWriter,
|
||||
type JSONValue,
|
||||
} from "ai";
|
||||
import type { ChatResponseChunk } from "llamaindex";
|
||||
import { humanInputEvent, type HumanResponseEventData } from "./hitl";
|
||||
|
||||
/**
|
||||
* Configuration options and helper callback methods for stream lifecycle events.
|
||||
@@ -24,6 +30,11 @@ export interface StreamCallbacks {
|
||||
text: string,
|
||||
dataStreamWriter: DataStreamWriter,
|
||||
) => Promise<void> | void;
|
||||
|
||||
/** `onPauseForHumanInput`: Called when human input event is emitted. */
|
||||
onPauseForHumanInput?:
|
||||
| ((event: WorkflowEvent<HumanResponseEventData>) => Promise<void> | void)
|
||||
| undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,6 +72,14 @@ export function toDataStream(
|
||||
await callbacks.onText(content, dataStreamWriter);
|
||||
}
|
||||
}
|
||||
} else if (humanInputEvent.include(event)) {
|
||||
const { response, ...rest } = event.data;
|
||||
dataStreamWriter.writeMessageAnnotation(rest); // show human input in UI
|
||||
|
||||
if (callbacks?.onPauseForHumanInput) {
|
||||
await callbacks.onPauseForHumanInput(response);
|
||||
return; // stop the stream
|
||||
}
|
||||
} else {
|
||||
dataStreamWriter.writeMessageAnnotation(event.data as JSONValue);
|
||||
}
|
||||
@@ -78,3 +97,24 @@ export function toDataStream(
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export async function writeResponseToStream(
|
||||
generator: AsyncIterable<ChatResponseChunk<object>>,
|
||||
sendEvent: (event: WorkflowEventData<unknown>) => void,
|
||||
) {
|
||||
let response = "";
|
||||
if (generator) {
|
||||
for await (const chunk of generator) {
|
||||
response += chunk.delta;
|
||||
sendEvent(
|
||||
agentStreamEvent.with({
|
||||
delta: chunk.delta,
|
||||
response,
|
||||
currentAgentName: "LLM",
|
||||
raw: chunk.raw,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import {
|
||||
agentToolCallEvent,
|
||||
agentToolCallResultEvent,
|
||||
run,
|
||||
startAgentEvent,
|
||||
stopAgentEvent,
|
||||
WorkflowStream,
|
||||
type AgentInputData,
|
||||
type Workflow,
|
||||
type WorkflowContext,
|
||||
type WorkflowEventData,
|
||||
} from "@llamaindex/workflow";
|
||||
import {
|
||||
@@ -22,30 +21,48 @@ import {
|
||||
type SourceEventNode,
|
||||
} from "./events";
|
||||
import { downloadFile } from "./file";
|
||||
import {
|
||||
resumeWorkflowFromHumanResponses,
|
||||
type HumanResponseEventData,
|
||||
} from "./hitl/index";
|
||||
import { toInlineAnnotationEvent } from "./inline";
|
||||
|
||||
export async function runWorkflow(
|
||||
workflow: Workflow,
|
||||
input: AgentInputData,
|
||||
abortSignal?: AbortSignal,
|
||||
): Promise<WorkflowStream<WorkflowEventData<unknown>>> {
|
||||
if (!input.userInput) {
|
||||
throw new Error("Missing user input to start the workflow");
|
||||
}
|
||||
const workflowStream = run(workflow, [
|
||||
startAgentEvent.with({
|
||||
userInput: input.userInput,
|
||||
chatHistory: input.chatHistory,
|
||||
}),
|
||||
]);
|
||||
export async function runWorkflow({
|
||||
workflow,
|
||||
input,
|
||||
human,
|
||||
}: {
|
||||
workflow: Workflow;
|
||||
input: AgentInputData;
|
||||
human?: {
|
||||
snapshotId?: string | undefined; // the snapshot id to restore workflow
|
||||
responses?: HumanResponseEventData[]; // the data from human to trigger events after restoring
|
||||
};
|
||||
}): Promise<WorkflowContext> {
|
||||
let context: WorkflowContext;
|
||||
|
||||
// Transform the stream to handle annotations
|
||||
return processWorkflowStream(workflowStream).until(
|
||||
(event) => abortSignal?.aborted || stopAgentEvent.include(event),
|
||||
);
|
||||
if (human?.responses?.length && human?.snapshotId) {
|
||||
// resume the workflow if there is human response
|
||||
context = await resumeWorkflowFromHumanResponses(
|
||||
workflow,
|
||||
human.responses,
|
||||
human.snapshotId,
|
||||
);
|
||||
} else {
|
||||
// otherwise, create a new empty context and run the workflow with startAgentEvent
|
||||
context = workflow.createContext();
|
||||
context.sendEvent(
|
||||
startAgentEvent.with({
|
||||
userInput: input.userInput,
|
||||
chatHistory: input.chatHistory,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
function processWorkflowStream(
|
||||
export function processWorkflowStream(
|
||||
stream: WorkflowStream<WorkflowEventData<unknown>>,
|
||||
) {
|
||||
return stream.pipeThrough(
|
||||
|
||||
Generated
+273
-23
@@ -187,8 +187,8 @@ importers:
|
||||
specifier: ~0.1.30
|
||||
version: 0.1.30
|
||||
'@llamaindex/workflow':
|
||||
specifier: ~1.1.3
|
||||
version: 1.1.3(@llamaindex/core@0.6.6)(@llamaindex/env@0.1.30)(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.3)
|
||||
specifier: ~1.1.8
|
||||
version: 1.1.8(@llamaindex/core@0.6.6)(@llamaindex/env@0.1.30)(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.3)
|
||||
'@radix-ui/react-accordion':
|
||||
specifier: ^1.2.3
|
||||
version: 1.2.8(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
@@ -342,7 +342,7 @@ importers:
|
||||
version: 7.20.7
|
||||
llamaindex:
|
||||
specifier: ~0.11.0
|
||||
version: 0.11.1(@llama-flow/core@0.4.1(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.3))(tree-sitter@0.22.4)(web-tree-sitter@0.24.7)(zod@3.24.3)
|
||||
version: 0.11.1(@llama-flow/core@0.4.4(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.3))(tree-sitter@0.22.4)(web-tree-sitter@0.24.7)(zod@3.24.3)
|
||||
postcss:
|
||||
specifier: ^8.5.3
|
||||
version: 8.5.3
|
||||
@@ -381,7 +381,7 @@ importers:
|
||||
version: 16.5.0
|
||||
llamaindex:
|
||||
specifier: ~0.11.0
|
||||
version: 0.11.1(@llama-flow/core@0.4.1(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.25.13))(tree-sitter@0.22.4)(web-tree-sitter@0.24.7)(zod@3.25.13)
|
||||
version: 0.11.1(@llama-flow/core@0.4.4(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.25.13))(tree-sitter@0.22.4)(web-tree-sitter@0.24.7)(zod@3.25.13)
|
||||
zod:
|
||||
specifier: ^3.24.2
|
||||
version: 3.25.13
|
||||
@@ -393,8 +393,8 @@ importers:
|
||||
specifier: ^3.1.10
|
||||
version: 3.1.10
|
||||
tsx:
|
||||
specifier: ^4.7.2
|
||||
version: 4.19.3
|
||||
specifier: 4.7.2
|
||||
version: 4.7.2
|
||||
typescript:
|
||||
specifier: ^5.3.2
|
||||
version: 5.8.3
|
||||
@@ -699,6 +699,12 @@ packages:
|
||||
'@emnapi/wasi-threads@1.0.2':
|
||||
resolution: {integrity: sha512-5n3nTJblwRi8LlXkJ9eBzu+kZR8Yxcc7ubakyQTFzPMtIhFpUBRbsnc2Dv88IZDIbCDlBiWrknhB4Lsz7mg6BA==}
|
||||
|
||||
'@esbuild/aix-ppc64@0.19.12':
|
||||
resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/aix-ppc64@0.21.5':
|
||||
resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -711,6 +717,12 @@ packages:
|
||||
cpu: [ppc64]
|
||||
os: [aix]
|
||||
|
||||
'@esbuild/android-arm64@0.19.12':
|
||||
resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm64@0.21.5':
|
||||
resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -723,6 +735,12 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.19.12':
|
||||
resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-arm@0.21.5':
|
||||
resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -735,6 +753,12 @@ packages:
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.19.12':
|
||||
resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/android-x64@0.21.5':
|
||||
resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -747,6 +771,12 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
|
||||
'@esbuild/darwin-arm64@0.19.12':
|
||||
resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-arm64@0.21.5':
|
||||
resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -759,6 +789,12 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.19.12':
|
||||
resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/darwin-x64@0.21.5':
|
||||
resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -771,6 +807,12 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.19.12':
|
||||
resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-arm64@0.21.5':
|
||||
resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -783,6 +825,12 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.19.12':
|
||||
resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/freebsd-x64@0.21.5':
|
||||
resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -795,6 +843,12 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@esbuild/linux-arm64@0.19.12':
|
||||
resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm64@0.21.5':
|
||||
resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -807,6 +861,12 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.19.12':
|
||||
resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-arm@0.21.5':
|
||||
resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -819,6 +879,12 @@ packages:
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.19.12':
|
||||
resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ia32@0.21.5':
|
||||
resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -831,6 +897,12 @@ packages:
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.19.12':
|
||||
resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-loong64@0.21.5':
|
||||
resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -843,6 +915,12 @@ packages:
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.19.12':
|
||||
resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-mips64el@0.21.5':
|
||||
resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -855,6 +933,12 @@ packages:
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.19.12':
|
||||
resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-ppc64@0.21.5':
|
||||
resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -867,6 +951,12 @@ packages:
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.19.12':
|
||||
resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-riscv64@0.21.5':
|
||||
resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -879,6 +969,12 @@ packages:
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.19.12':
|
||||
resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-s390x@0.21.5':
|
||||
resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -891,6 +987,12 @@ packages:
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.19.12':
|
||||
resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@esbuild/linux-x64@0.21.5':
|
||||
resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -909,6 +1011,12 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-x64@0.19.12':
|
||||
resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
|
||||
'@esbuild/netbsd-x64@0.21.5':
|
||||
resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -927,6 +1035,12 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.19.12':
|
||||
resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/openbsd-x64@0.21.5':
|
||||
resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -939,6 +1053,12 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
|
||||
'@esbuild/sunos-x64@0.19.12':
|
||||
resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/sunos-x64@0.21.5':
|
||||
resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -951,6 +1071,12 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
|
||||
'@esbuild/win32-arm64@0.19.12':
|
||||
resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-arm64@0.21.5':
|
||||
resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -963,6 +1089,12 @@ packages:
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.19.12':
|
||||
resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-ia32@0.21.5':
|
||||
resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -975,6 +1107,12 @@ packages:
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.19.12':
|
||||
resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@esbuild/win32-x64@0.21.5':
|
||||
resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -1333,8 +1471,8 @@ packages:
|
||||
'@lezer/yaml@1.0.3':
|
||||
resolution: {integrity: sha512-GuBLekbw9jDBDhGur82nuwkxKQ+a3W5H0GfaAthDXcAu+XdpS43VlnxA9E9hllkpSP5ellRDKjLLj7Lu9Wr6xA==}
|
||||
|
||||
'@llama-flow/core@0.4.1':
|
||||
resolution: {integrity: sha512-xHhJMRmY16C1pYPWIonmLWPkkjTGuj1iVQCTXOM6sXajQ3r0+mEVERQCjPqf48tvX0K+szbdgxjg6wx+KwVqcg==}
|
||||
'@llama-flow/core@0.4.4':
|
||||
resolution: {integrity: sha512-hwK1EQ+atUG/E7XcDV3KsTaA8op29pb8gbpVurpsqbLnGFkdTT4F/6V7Hy1cC2o/yOY+DKc/rxoIsH1uJS0cZg==}
|
||||
peerDependencies:
|
||||
'@modelcontextprotocol/sdk': ^1.7.0
|
||||
hono: ^4.7.4
|
||||
@@ -1425,10 +1563,10 @@ packages:
|
||||
'@llamaindex/env': 0.1.29
|
||||
zod: ^3.23.8
|
||||
|
||||
'@llamaindex/workflow@1.1.3':
|
||||
resolution: {integrity: sha512-B9wlN4xMtfbnIQW84wTC0GdyIaLGXYnZ4I0LENV2UM/0wqlXKI7YoBTO3cJvi6pO1sPA+K29Tqw822VsGF+GkA==}
|
||||
'@llamaindex/workflow@1.1.8':
|
||||
resolution: {integrity: sha512-40uy5dWnqqlojq/fjlrIw8ZQOcFmZ2kSrvTyH65vQtypoTP8JWgBSTt3SFTWBUndwijNsfl9VvLh5S9INb0XBQ==}
|
||||
peerDependencies:
|
||||
'@llamaindex/core': 0.6.6
|
||||
'@llamaindex/core': 0.6.9
|
||||
'@llamaindex/env': 0.1.30
|
||||
zod: ^3.23.8
|
||||
|
||||
@@ -3861,6 +3999,11 @@ packages:
|
||||
resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==}
|
||||
engines: {node: '>=0.12'}
|
||||
|
||||
esbuild@0.19.12:
|
||||
resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==}
|
||||
engines: {node: '>=12'}
|
||||
hasBin: true
|
||||
|
||||
esbuild@0.21.5:
|
||||
resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -6715,6 +6858,11 @@ packages:
|
||||
engines: {node: '>=18.0.0'}
|
||||
hasBin: true
|
||||
|
||||
tsx@4.7.2:
|
||||
resolution: {integrity: sha512-BCNd4kz6fz12fyrgCTEdZHGJ9fWTGeUzXmQysh0RVocDY3h4frk05ZNCXSy4kIenF7y/QnrdiVpTsyNRn6vlAw==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
hasBin: true
|
||||
|
||||
tunnel-agent@0.6.0:
|
||||
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
|
||||
|
||||
@@ -7730,102 +7878,153 @@ snapshots:
|
||||
tslib: 2.8.1
|
||||
optional: true
|
||||
|
||||
'@esbuild/aix-ppc64@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/aix-ppc64@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/aix-ppc64@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm64@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-arm@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/android-x64@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-arm64@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/darwin-x64@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-arm64@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/freebsd-x64@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm64@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-arm@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ia32@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-loong64@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-mips64el@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-ppc64@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-riscv64@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-s390x@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/linux-x64@0.21.5':
|
||||
optional: true
|
||||
|
||||
@@ -7835,6 +8034,9 @@ snapshots:
|
||||
'@esbuild/netbsd-arm64@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/netbsd-x64@0.21.5':
|
||||
optional: true
|
||||
|
||||
@@ -7844,30 +8046,45 @@ snapshots:
|
||||
'@esbuild/openbsd-arm64@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/openbsd-x64@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/sunos-x64@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-arm64@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.21.5':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-ia32@0.25.3':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.19.12':
|
||||
optional: true
|
||||
|
||||
'@esbuild/win32-x64@0.21.5':
|
||||
optional: true
|
||||
|
||||
@@ -8307,14 +8524,14 @@ snapshots:
|
||||
'@lezer/highlight': 1.2.1
|
||||
'@lezer/lr': 1.4.2
|
||||
|
||||
'@llama-flow/core@0.4.1(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.3)':
|
||||
'@llama-flow/core@0.4.4(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.3)':
|
||||
optionalDependencies:
|
||||
'@modelcontextprotocol/sdk': 1.12.1
|
||||
next: 15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
p-retry: 6.2.1
|
||||
zod: 3.24.3
|
||||
|
||||
'@llama-flow/core@0.4.1(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.25.13)':
|
||||
'@llama-flow/core@0.4.4(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.25.13)':
|
||||
optionalDependencies:
|
||||
'@modelcontextprotocol/sdk': 1.12.1
|
||||
next: 15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
|
||||
@@ -8373,17 +8590,17 @@ snapshots:
|
||||
- supports-color
|
||||
- yjs
|
||||
|
||||
'@llamaindex/cloud@4.0.9(@llama-flow/core@0.4.1(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.3))(@llamaindex/core@0.6.6)(@llamaindex/env@0.1.30)':
|
||||
'@llamaindex/cloud@4.0.9(@llama-flow/core@0.4.4(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.3))(@llamaindex/core@0.6.6)(@llamaindex/env@0.1.30)':
|
||||
dependencies:
|
||||
'@llama-flow/core': 0.4.1(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.3)
|
||||
'@llama-flow/core': 0.4.4(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.3)
|
||||
'@llamaindex/core': 0.6.6
|
||||
'@llamaindex/env': 0.1.30
|
||||
p-retry: 6.2.1
|
||||
zod: 3.25.13
|
||||
|
||||
'@llamaindex/cloud@4.0.9(@llama-flow/core@0.4.1(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.25.13))(@llamaindex/core@0.6.6)(@llamaindex/env@0.1.30)':
|
||||
'@llamaindex/cloud@4.0.9(@llama-flow/core@0.4.4(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.25.13))(@llamaindex/core@0.6.6)(@llamaindex/env@0.1.30)':
|
||||
dependencies:
|
||||
'@llama-flow/core': 0.4.1(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.25.13)
|
||||
'@llama-flow/core': 0.4.4(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.25.13)
|
||||
'@llamaindex/core': 0.6.6
|
||||
'@llamaindex/env': 0.1.30
|
||||
p-retry: 6.2.1
|
||||
@@ -8483,9 +8700,9 @@ snapshots:
|
||||
'@llamaindex/env': 0.1.30
|
||||
zod: 3.25.13
|
||||
|
||||
'@llamaindex/workflow@1.1.3(@llamaindex/core@0.6.6)(@llamaindex/env@0.1.30)(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.3)':
|
||||
'@llamaindex/workflow@1.1.8(@llamaindex/core@0.6.6)(@llamaindex/env@0.1.30)(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.3)':
|
||||
dependencies:
|
||||
'@llama-flow/core': 0.4.1(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.3)
|
||||
'@llama-flow/core': 0.4.4(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.3)
|
||||
'@llamaindex/core': 0.6.6
|
||||
'@llamaindex/env': 0.1.30
|
||||
zod: 3.24.3
|
||||
@@ -11070,6 +11287,32 @@ snapshots:
|
||||
d: 1.0.2
|
||||
ext: 1.7.0
|
||||
|
||||
esbuild@0.19.12:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.19.12
|
||||
'@esbuild/android-arm': 0.19.12
|
||||
'@esbuild/android-arm64': 0.19.12
|
||||
'@esbuild/android-x64': 0.19.12
|
||||
'@esbuild/darwin-arm64': 0.19.12
|
||||
'@esbuild/darwin-x64': 0.19.12
|
||||
'@esbuild/freebsd-arm64': 0.19.12
|
||||
'@esbuild/freebsd-x64': 0.19.12
|
||||
'@esbuild/linux-arm': 0.19.12
|
||||
'@esbuild/linux-arm64': 0.19.12
|
||||
'@esbuild/linux-ia32': 0.19.12
|
||||
'@esbuild/linux-loong64': 0.19.12
|
||||
'@esbuild/linux-mips64el': 0.19.12
|
||||
'@esbuild/linux-ppc64': 0.19.12
|
||||
'@esbuild/linux-riscv64': 0.19.12
|
||||
'@esbuild/linux-s390x': 0.19.12
|
||||
'@esbuild/linux-x64': 0.19.12
|
||||
'@esbuild/netbsd-x64': 0.19.12
|
||||
'@esbuild/openbsd-x64': 0.19.12
|
||||
'@esbuild/sunos-x64': 0.19.12
|
||||
'@esbuild/win32-arm64': 0.19.12
|
||||
'@esbuild/win32-ia32': 0.19.12
|
||||
'@esbuild/win32-x64': 0.19.12
|
||||
|
||||
esbuild@0.21.5:
|
||||
optionalDependencies:
|
||||
'@esbuild/aix-ppc64': 0.21.5
|
||||
@@ -12310,9 +12553,9 @@ snapshots:
|
||||
rfdc: 1.4.1
|
||||
wrap-ansi: 9.0.0
|
||||
|
||||
llamaindex@0.11.1(@llama-flow/core@0.4.1(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.3))(tree-sitter@0.22.4)(web-tree-sitter@0.24.7)(zod@3.24.3):
|
||||
llamaindex@0.11.1(@llama-flow/core@0.4.4(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.3))(tree-sitter@0.22.4)(web-tree-sitter@0.24.7)(zod@3.24.3):
|
||||
dependencies:
|
||||
'@llamaindex/cloud': 4.0.9(@llama-flow/core@0.4.1(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.3))(@llamaindex/core@0.6.6)(@llamaindex/env@0.1.30)
|
||||
'@llamaindex/cloud': 4.0.9(@llama-flow/core@0.4.4(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.24.3))(@llamaindex/core@0.6.6)(@llamaindex/env@0.1.30)
|
||||
'@llamaindex/core': 0.6.6
|
||||
'@llamaindex/env': 0.1.30
|
||||
'@llamaindex/node-parser': 2.0.6(@llamaindex/core@0.6.6)(@llamaindex/env@0.1.30)(tree-sitter@0.22.4)(web-tree-sitter@0.24.7)
|
||||
@@ -12330,9 +12573,9 @@ snapshots:
|
||||
- web-tree-sitter
|
||||
- zod
|
||||
|
||||
llamaindex@0.11.1(@llama-flow/core@0.4.1(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.25.13))(tree-sitter@0.22.4)(web-tree-sitter@0.24.7)(zod@3.25.13):
|
||||
llamaindex@0.11.1(@llama-flow/core@0.4.4(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.25.13))(tree-sitter@0.22.4)(web-tree-sitter@0.24.7)(zod@3.25.13):
|
||||
dependencies:
|
||||
'@llamaindex/cloud': 4.0.9(@llama-flow/core@0.4.1(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.25.13))(@llamaindex/core@0.6.6)(@llamaindex/env@0.1.30)
|
||||
'@llamaindex/cloud': 4.0.9(@llama-flow/core@0.4.4(@modelcontextprotocol/sdk@1.12.1)(next@15.3.1(@opentelemetry/api@1.9.0)(@playwright/test@1.52.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(p-retry@6.2.1)(zod@3.25.13))(@llamaindex/core@0.6.6)(@llamaindex/env@0.1.30)
|
||||
'@llamaindex/core': 0.6.6
|
||||
'@llamaindex/env': 0.1.30
|
||||
'@llamaindex/node-parser': 2.0.6(@llamaindex/core@0.6.6)(@llamaindex/env@0.1.30)(tree-sitter@0.22.4)(web-tree-sitter@0.24.7)
|
||||
@@ -14647,6 +14890,13 @@ snapshots:
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
|
||||
tsx@4.7.2:
|
||||
dependencies:
|
||||
esbuild: 0.19.12
|
||||
get-tsconfig: 4.10.0
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
|
||||
tunnel-agent@0.6.0:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
Reference in New Issue
Block a user