diff --git a/.github/changes-filter.yaml b/.github/changes-filter.yaml
index 925f237460..f0d36110ca 100644
--- a/.github/changes-filter.yaml
+++ b/.github/changes-filter.yaml
@@ -25,6 +25,7 @@ starter-projects:
- "src/backend/base/langflow/components/**"
- "src/backend/base/langflow/services/**"
- "src/backend/base/langflow/custom/**"
+ - "src/backend/base/langflow/api/v1/chat.py"
- "src/frontend/src/pages/MainPage/**"
- "src/frontend/src/utils/reactflowUtils.ts"
- "src/frontend/tests/extended/features/**"
diff --git a/.github/workflows/codeflash.yml b/.github/workflows/codeflash.yml
index 55414a8764..63dd55a450 100644
--- a/.github/workflows/codeflash.yml
+++ b/.github/workflows/codeflash.yml
@@ -29,6 +29,7 @@ jobs:
- run: uv sync --extra dev
- name: Run Codeflash Optimizer
working-directory: ./src/backend/base
+ continue-on-error: true
run: uv run codeflash
- name: Minimize uv cache
run: uv cache prune --ci
diff --git a/Makefile b/Makefile
index 82f13284e3..b13b28196e 100644
--- a/Makefile
+++ b/Makefile
@@ -463,3 +463,51 @@ alembic-check: ## check migration status
alembic-stamp: ## stamp the database with a specific revision
@echo 'Stamping the database with revision $(revision)'
cd src/backend/base/langflow/ && uv run alembic stamp $(revision)
+
+######################
+# LOAD TESTING
+######################
+
+# Default values for locust configuration
+locust_users ?= 10
+locust_spawn_rate ?= 1
+locust_host ?= http://localhost:7860
+locust_headless ?= true
+locust_time ?= 300s
+locust_api_key ?= your-api-key
+locust_flow_id ?= your-flow-id
+locust_file ?= src/backend/tests/locust/locustfile.py
+locust_min_wait ?= 2000
+locust_max_wait ?= 5000
+locust_request_timeout ?= 30.0
+
+locust: ## run locust load tests (options: locust_users=10 locust_spawn_rate=1 locust_host=http://localhost:7860 locust_headless=true locust_time=300s locust_api_key=your-api-key locust_flow_id=your-flow-id locust_file=src/backend/tests/locust/locustfile.py locust_min_wait=2000 locust_max_wait=5000 locust_request_timeout=30.0)
+ @if [ ! -f "$(locust_file)" ]; then \
+ echo "$(RED)Error: Locustfile not found at $(locust_file)$(NC)"; \
+ exit 1; \
+ fi
+ @echo "Starting Locust with $(locust_users) users, spawn rate of $(locust_spawn_rate)"
+ @echo "Testing host: $(locust_host)"
+ @echo "Using locustfile: $(locust_file)"
+ @export API_KEY=$(locust_api_key) && \
+ export FLOW_ID=$(locust_flow_id) && \
+ export LANGFLOW_HOST=$(locust_host) && \
+ export MIN_WAIT=$(locust_min_wait) && \
+ export MAX_WAIT=$(locust_max_wait) && \
+ export REQUEST_TIMEOUT=$(locust_request_timeout) && \
+ cd $$(dirname "$(locust_file)") && \
+ if [ "$(locust_headless)" = "true" ]; then \
+ uv run locust \
+ --headless \
+ -u $(locust_users) \
+ -r $(locust_spawn_rate) \
+ --run-time $(locust_time) \
+ --host $(locust_host) \
+ -f $$(basename "$(locust_file)"); \
+ else \
+ uv run locust \
+ -u $(locust_users) \
+ -r $(locust_spawn_rate) \
+ --host $(locust_host) \
+ -f $$(basename "$(locust_file)"); \
+ fi
diff --git a/README.ES.md b/README.ES.md
index edb0acf48d..b90625eef8 100644
--- a/README.ES.md
+++ b/README.ES.md
@@ -31,6 +31,7 @@
+
diff --git a/README.KR.md b/README.KR.md
index 3032675fe2..082f94729f 100644
--- a/README.KR.md
+++ b/README.KR.md
@@ -38,6 +38,7 @@
+
diff --git a/README.PT.md b/README.PT.md
index 1d1942a450..881aa9bdb0 100644
--- a/README.PT.md
+++ b/README.PT.md
@@ -33,6 +33,7 @@
+
diff --git a/README.RU.md b/README.RU.md new file mode 100644 index 0000000000..9e33d6f163 --- /dev/null +++ b/README.RU.md @@ -0,0 +1,78 @@ + + + + +
+ Langflow — это инструмент для создания приложений с низким уровнем кода для RAG и многоагентных ИИ-приложений. Он основан на Python и не зависит от конкретных моделей, API или баз данных. +
+ ++ Документация - + Бесплатный облачный сервис - + Самостоятельное развертывание + +
+ + + +## ✨ Основные возможности + +1. **Основан на Python** и не зависит от моделей, API, источников данных или баз данных. +2. **Визуальная IDE** для построения и тестирования рабочих процессов методом drag-and-drop. +3. **Песочница** для мгновенного тестирования и итерации процессов с поэтапным контролем. +4. **Оркестрация многоагентных систем** с управлением диалогами и извлечением информации. +5. **Бесплатный облачный сервис**, позволяющий начать работу за считанные минуты без настройки. +6. **Публикация в виде API** или экспорт в виде Python-приложения. +7. **Наблюдаемость** с интеграцией LangSmith, LangFuse или LangWatch. +8. **Безопасность и масштабируемость уровня предприятия** с бесплатным облачным сервисом DataStax Langflow. +9. **Настройка рабочих процессов** или создание потоков исключительно на Python. +10. **Интеграция с экосистемами** через повторно используемые компоненты для любых моделей, API или баз данных. + + + +## 📦 Быстрый старт + +- **Установка через uv (рекомендуется)** (Python 3.10–3.12): + +```shell +uv pip install langflow +``` + +- **Установка через pip** (Python 3.10–3.12): + +```shell +pip install langflow +``` + +- **Облако:** DataStax Langflow — это управляемая среда без необходимости настройки. [Зарегистрируйтесь бесплатно.](https://astra.datastax.com/signup?type=langflow) +- **Самостоятельное развертывание:** Запустите Langflow в своей среде. [Установите Langflow](https://docs.langflow.org/get-started-installation), чтобы запустить локальный сервер Langflow, а затем воспользуйтесь [руководством по быстрому старту](https://docs.langflow.org/get-started-quickstart) для создания и выполнения потока. +- **Hugging Face:** [Клонируйте пространство по этой ссылке](https://huggingface.co/spaces/Langflow/Langflow?duplicate=true), чтобы создать рабочее пространство Langflow. + +[](https://www.youtube.com/watch?v=kinngWhaUKM) + +## ⭐ Будьте в курсе обновлений + +Добавьте Langflow в избранное на GitHub, чтобы мгновенно узнавать о новых релизах. + + + +## 👋 Внесите свой вклад + +Мы приветствуем вклад разработчиков любого уровня. Если хотите помочь в развитии проекта, ознакомьтесь с нашими [руководящими принципами для участников](./CONTRIBUTING.md) и сделайте Langflow еще доступнее. + +--- + +[](https://star-history.com/#langflow-ai/langflow&Date) + +## ❤️ Соавторы + +[](https://github.com/langflow-ai/langflow/graphs/contributors) diff --git a/README.ja.md b/README.ja.md index fc7418e7f2..2c2b3d0bb0 100644 --- a/README.ja.md +++ b/README.ja.md @@ -38,6 +38,7 @@
diff --git a/README.md b/README.md
index bef72b461f..3499b0c9ef 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,7 @@
+
## ✨ Core features
diff --git a/README.zh_CN.md b/README.zh_CN.md
index f567d96a8d..82cf2e6520 100644
--- a/README.zh_CN.md
+++ b/README.zh_CN.md
@@ -33,6 +33,7 @@
+
diff --git a/pyproject.toml b/pyproject.toml
index d3a0d9bedf..9f08c1aa99 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -191,6 +191,7 @@ dev-dependencies = [
"types-aiofiles>=24.1.0.20240626",
"codeflash>=0.8.4",
"hypothesis>=6.123.17",
+ "locust>=2.32.9",
]
diff --git a/src/backend/base/langflow/api/build.py b/src/backend/base/langflow/api/build.py
new file mode 100644
index 0000000000..384a74bdd0
--- /dev/null
+++ b/src/backend/base/langflow/api/build.py
@@ -0,0 +1,428 @@
+import asyncio
+import json
+import time
+import traceback
+import uuid
+from collections.abc import AsyncIterator
+
+from fastapi import BackgroundTasks, HTTPException
+from fastapi.responses import JSONResponse
+from loguru import logger
+from sqlmodel import select
+
+from langflow.api.disconnect import DisconnectHandlerStreamingResponse
+from langflow.api.utils import (
+ CurrentActiveUser,
+ build_graph_from_data,
+ build_graph_from_db,
+ format_elapsed_time,
+ format_exception_message,
+ get_top_level_vertices,
+ parse_exception,
+)
+from langflow.api.v1.schemas import (
+ FlowDataRequest,
+ InputValueRequest,
+ ResultDataResponse,
+ VertexBuildResponse,
+)
+from langflow.events.event_manager import EventManager
+from langflow.exceptions.component import ComponentBuildError
+from langflow.graph.graph.base import Graph
+from langflow.graph.utils import log_vertex_build
+from langflow.schema.message import ErrorMessage
+from langflow.schema.schema import OutputValue
+from langflow.services.database.models.flow import Flow
+from langflow.services.deps import get_chat_service, get_telemetry_service, session_scope
+from langflow.services.job_queue.service import JobQueueService
+from langflow.services.telemetry.schema import ComponentPayload, PlaygroundPayload
+
+
+async def start_flow_build(
+ *,
+ flow_id: uuid.UUID,
+ background_tasks: BackgroundTasks,
+ inputs: InputValueRequest | None,
+ data: FlowDataRequest | None,
+ files: list[str] | None,
+ stop_component_id: str | None,
+ start_component_id: str | None,
+ log_builds: bool,
+ current_user: CurrentActiveUser,
+ queue_service: JobQueueService,
+) -> str:
+ """Start the flow build process by setting up the queue and starting the build task.
+
+ Returns:
+ the job_id.
+ """
+ job_id = str(uuid.uuid4())
+ try:
+ _, event_manager = queue_service.create_queue(job_id)
+ task_coro = generate_flow_events(
+ flow_id=flow_id,
+ background_tasks=background_tasks,
+ event_manager=event_manager,
+ inputs=inputs,
+ data=data,
+ files=files,
+ stop_component_id=stop_component_id,
+ start_component_id=start_component_id,
+ log_builds=log_builds,
+ current_user=current_user,
+ )
+ queue_service.start_job(job_id, task_coro)
+ except Exception as e:
+ logger.exception("Failed to create queue and start task")
+ raise HTTPException(status_code=500, detail=str(e)) from e
+ return job_id
+
+
+async def get_flow_events_response(
+ *,
+ job_id: str,
+ queue_service: JobQueueService,
+ stream: bool = True,
+):
+ """Get events for a specific build job, either as a stream or single event."""
+ try:
+ main_queue, event_manager, event_task = queue_service.get_queue_data(job_id)
+ if stream:
+ if event_task is None:
+ raise HTTPException(status_code=404, detail="No event task found for job")
+ return await create_flow_response(
+ queue=main_queue,
+ event_manager=event_manager,
+ event_task=event_task,
+ )
+
+ # Polling mode - get exactly one event
+ _, value, _ = await main_queue.get()
+ if value is None:
+ # End of stream, trigger end event
+ if event_task is not None:
+ event_task.cancel()
+ event_manager.on_end(data={})
+
+ return JSONResponse({"event": value.decode("utf-8") if value else None})
+
+ except ValueError as exc:
+ raise HTTPException(status_code=404, detail=str(exc)) from exc
+
+
+async def create_flow_response(
+ queue: asyncio.Queue,
+ event_manager: EventManager,
+ event_task: asyncio.Task,
+) -> DisconnectHandlerStreamingResponse:
+ """Create a streaming response for the flow build process."""
+
+ async def consume_and_yield() -> AsyncIterator[str]:
+ while True:
+ try:
+ event_id, value, put_time = await queue.get()
+ if value is None:
+ break
+ get_time = time.time()
+ yield value.decode("utf-8")
+ logger.debug(f"Event {event_id} consumed in {get_time - put_time:.4f}s")
+ except Exception as exc: # noqa: BLE001
+ logger.exception(f"Error consuming event: {exc}")
+ break
+
+ def on_disconnect() -> None:
+ logger.debug("Client disconnected, closing tasks")
+ event_task.cancel()
+ event_manager.on_end(data={})
+
+ return DisconnectHandlerStreamingResponse(
+ consume_and_yield(),
+ media_type="application/x-ndjson",
+ on_disconnect=on_disconnect,
+ )
+
+
+async def generate_flow_events(
+ *,
+ flow_id: uuid.UUID,
+ background_tasks: BackgroundTasks,
+ event_manager: EventManager,
+ inputs: InputValueRequest | None,
+ data: FlowDataRequest | None,
+ files: list[str] | None,
+ stop_component_id: str | None,
+ start_component_id: str | None,
+ log_builds: bool,
+ current_user: CurrentActiveUser,
+) -> None:
+ """Generate events for flow building process.
+
+ This function handles the core flow building logic and generates appropriate events:
+ - Building and validating the graph
+ - Processing vertices
+ - Handling errors and cleanup
+ """
+ chat_service = get_chat_service()
+ telemetry_service = get_telemetry_service()
+ if not inputs:
+ inputs = InputValueRequest(session=str(flow_id))
+
+ async def build_graph_and_get_order() -> tuple[list[str], list[str], Graph]:
+ start_time = time.perf_counter()
+ components_count = 0
+ graph = None
+ try:
+ flow_id_str = str(flow_id)
+ # Create a fresh session for database operations
+ async with session_scope() as fresh_session:
+ graph = await create_graph(fresh_session, flow_id_str)
+
+ graph.validate_stream()
+ first_layer = sort_vertices(graph)
+
+ if inputs is not None and getattr(inputs, "session", None) is not None:
+ graph.session_id = inputs.session
+
+ for vertex_id in first_layer:
+ graph.run_manager.add_to_vertices_being_run(vertex_id)
+
+ # Now vertices is a list of lists
+ # We need to get the id of each vertex
+ # and return the same structure but only with the ids
+ components_count = len(graph.vertices)
+ vertices_to_run = list(graph.vertices_to_run.union(get_top_level_vertices(graph, graph.vertices_to_run)))
+
+ await chat_service.set_cache(flow_id_str, graph)
+ await log_telemetry(start_time, components_count, success=True)
+
+ except Exception as exc:
+ await log_telemetry(start_time, components_count, success=False, error_message=str(exc))
+
+ if "stream or streaming set to True" in str(exc):
+ raise HTTPException(status_code=400, detail=str(exc)) from exc
+ logger.exception("Error checking build status")
+ raise HTTPException(status_code=500, detail=str(exc)) from exc
+ return first_layer, vertices_to_run, graph
+
+ async def log_telemetry(
+ start_time: float, components_count: int, *, success: bool, error_message: str | None = None
+ ):
+ background_tasks.add_task(
+ telemetry_service.log_package_playground,
+ PlaygroundPayload(
+ playground_seconds=int(time.perf_counter() - start_time),
+ playground_component_count=components_count,
+ playground_success=success,
+ playground_error_message=str(error_message) if error_message else "",
+ ),
+ )
+
+ async def create_graph(fresh_session, flow_id_str: str) -> Graph:
+ if not data:
+ return await build_graph_from_db(flow_id=flow_id, session=fresh_session, chat_service=chat_service)
+
+ result = await fresh_session.exec(select(Flow.name).where(Flow.id == flow_id))
+ flow_name = result.first()
+
+ return await build_graph_from_data(
+ flow_id=flow_id_str,
+ payload=data.model_dump(),
+ user_id=str(current_user.id),
+ flow_name=flow_name,
+ )
+
+ def sort_vertices(graph: Graph) -> list[str]:
+ try:
+ return graph.sort_vertices(stop_component_id, start_component_id)
+ except Exception: # noqa: BLE001
+ logger.exception("Error sorting vertices")
+ return graph.sort_vertices()
+
+ async def _build_vertex(vertex_id: str, graph: Graph, event_manager: EventManager) -> VertexBuildResponse:
+ flow_id_str = str(flow_id)
+ next_runnable_vertices = []
+ top_level_vertices = []
+ start_time = time.perf_counter()
+ error_message = None
+ try:
+ vertex = graph.get_vertex(vertex_id)
+ try:
+ lock = chat_service.async_cache_locks[flow_id_str]
+ vertex_build_result = await graph.build_vertex(
+ vertex_id=vertex_id,
+ user_id=str(current_user.id),
+ inputs_dict=inputs.model_dump() if inputs else {},
+ files=files,
+ get_cache=chat_service.get_cache,
+ set_cache=chat_service.set_cache,
+ event_manager=event_manager,
+ )
+ result_dict = vertex_build_result.result_dict
+ params = vertex_build_result.params
+ valid = vertex_build_result.valid
+ artifacts = vertex_build_result.artifacts
+ next_runnable_vertices = await graph.get_next_runnable_vertices(lock, vertex=vertex, cache=False)
+ top_level_vertices = graph.get_top_level_vertices(next_runnable_vertices)
+
+ result_data_response = ResultDataResponse.model_validate(result_dict, from_attributes=True)
+ except Exception as exc: # noqa: BLE001
+ if isinstance(exc, ComponentBuildError):
+ params = exc.message
+ tb = exc.formatted_traceback
+ else:
+ tb = traceback.format_exc()
+ logger.exception("Error building Component")
+ params = format_exception_message(exc)
+ message = {"errorMessage": params, "stackTrace": tb}
+ valid = False
+ error_message = params
+ output_label = vertex.outputs[0]["name"] if vertex.outputs else "output"
+ outputs = {output_label: OutputValue(message=message, type="error")}
+ result_data_response = ResultDataResponse(results={}, outputs=outputs)
+ artifacts = {}
+ background_tasks.add_task(graph.end_all_traces, error=exc)
+
+ result_data_response.message = artifacts
+
+ # Log the vertex build
+ if not vertex.will_stream and log_builds:
+ background_tasks.add_task(
+ log_vertex_build,
+ flow_id=flow_id_str,
+ vertex_id=vertex_id,
+ valid=valid,
+ params=params,
+ data=result_data_response,
+ artifacts=artifacts,
+ )
+ else:
+ await chat_service.set_cache(flow_id_str, graph)
+
+ timedelta = time.perf_counter() - start_time
+ duration = format_elapsed_time(timedelta)
+ result_data_response.duration = duration
+ result_data_response.timedelta = timedelta
+ vertex.add_build_time(timedelta)
+ inactivated_vertices = list(graph.inactivated_vertices)
+ graph.reset_inactivated_vertices()
+ graph.reset_activated_vertices()
+ # graph.stop_vertex tells us if the user asked
+ # to stop the build of the graph at a certain vertex
+ # if it is in next_vertices_ids, we need to remove other
+ # vertices from next_vertices_ids
+ if graph.stop_vertex and graph.stop_vertex in next_runnable_vertices:
+ next_runnable_vertices = [graph.stop_vertex]
+
+ if not graph.run_manager.vertices_being_run and not next_runnable_vertices:
+ background_tasks.add_task(graph.end_all_traces)
+
+ build_response = VertexBuildResponse(
+ inactivated_vertices=list(set(inactivated_vertices)),
+ next_vertices_ids=list(set(next_runnable_vertices)),
+ top_level_vertices=list(set(top_level_vertices)),
+ valid=valid,
+ params=params,
+ id=vertex.id,
+ data=result_data_response,
+ )
+ background_tasks.add_task(
+ telemetry_service.log_package_component,
+ ComponentPayload(
+ component_name=vertex_id.split("-")[0],
+ component_seconds=int(time.perf_counter() - start_time),
+ component_success=valid,
+ component_error_message=error_message,
+ ),
+ )
+ except Exception as exc:
+ background_tasks.add_task(
+ telemetry_service.log_package_component,
+ ComponentPayload(
+ component_name=vertex_id.split("-")[0],
+ component_seconds=int(time.perf_counter() - start_time),
+ component_success=False,
+ component_error_message=str(exc),
+ ),
+ )
+ logger.exception("Error building Component")
+ message = parse_exception(exc)
+ raise HTTPException(status_code=500, detail=message) from exc
+
+ return build_response
+
+ async def build_vertices(
+ vertex_id: str,
+ graph: Graph,
+ event_manager: EventManager,
+ ) -> None:
+ """Build vertices and handle their events.
+
+ Args:
+ vertex_id: The ID of the vertex to build
+ graph: The graph instance
+ event_manager: Manager for handling events
+ """
+ try:
+ vertex_build_response: VertexBuildResponse = await _build_vertex(vertex_id, graph, event_manager)
+ except asyncio.CancelledError as exc:
+ logger.exception(exc)
+ raise
+
+ # send built event or error event
+ try:
+ vertex_build_response_json = vertex_build_response.model_dump_json()
+ build_data = json.loads(vertex_build_response_json)
+ except Exception as exc:
+ msg = f"Error serializing vertex build response: {exc}"
+ raise ValueError(msg) from exc
+
+ event_manager.on_end_vertex(data={"build_data": build_data})
+
+ if vertex_build_response.valid and vertex_build_response.next_vertices_ids:
+ tasks = []
+ for next_vertex_id in vertex_build_response.next_vertices_ids:
+ task = asyncio.create_task(
+ build_vertices(
+ next_vertex_id,
+ graph,
+ event_manager,
+ )
+ )
+ tasks.append(task)
+ await asyncio.gather(*tasks)
+
+ try:
+ ids, vertices_to_run, graph = await build_graph_and_get_order()
+ except Exception as e:
+ error_message = ErrorMessage(
+ flow_id=flow_id,
+ exception=e,
+ )
+ event_manager.on_error(data=error_message.data)
+ raise
+
+ event_manager.on_vertices_sorted(data={"ids": ids, "to_run": vertices_to_run})
+
+ tasks = []
+ for vertex_id in ids:
+ task = asyncio.create_task(build_vertices(vertex_id, graph, event_manager))
+ tasks.append(task)
+ try:
+ await asyncio.gather(*tasks)
+ except asyncio.CancelledError:
+ background_tasks.add_task(graph.end_all_traces)
+ raise
+ except Exception as e:
+ logger.error(f"Error building vertices: {e}")
+ custom_component = graph.get_vertex(vertex_id).custom_component
+ trace_name = getattr(custom_component, "trace_name", None)
+ error_message = ErrorMessage(
+ flow_id=flow_id,
+ exception=e,
+ session_id=graph.session_id,
+ trace_name=trace_name,
+ )
+ event_manager.on_error(data=error_message.data)
+ raise
+ event_manager.on_end(data={})
+ await event_manager.queue.put((None, None, time.time()))
diff --git a/src/backend/base/langflow/api/disconnect.py b/src/backend/base/langflow/api/disconnect.py
new file mode 100644
index 0000000000..a11454c732
--- /dev/null
+++ b/src/backend/base/langflow/api/disconnect.py
@@ -0,0 +1,31 @@
+import asyncio
+import typing
+
+from fastapi.responses import StreamingResponse
+from starlette.background import BackgroundTask
+from starlette.responses import ContentStream
+from starlette.types import Receive
+
+
+class DisconnectHandlerStreamingResponse(StreamingResponse):
+ def __init__(
+ self,
+ content: ContentStream,
+ status_code: int = 200,
+ headers: typing.Mapping[str, str] | None = None,
+ media_type: str | None = None,
+ background: BackgroundTask | None = None,
+ on_disconnect: typing.Callable | None = None,
+ ):
+ super().__init__(content, status_code, headers, media_type, background)
+ self.on_disconnect = on_disconnect
+
+ async def listen_for_disconnect(self, receive: Receive) -> None:
+ while True:
+ message = await receive()
+ if message["type"] == "http.disconnect":
+ if self.on_disconnect:
+ coro = self.on_disconnect()
+ if asyncio.iscoroutine(coro):
+ await coro
+ break
diff --git a/src/backend/base/langflow/api/limited_background_tasks.py b/src/backend/base/langflow/api/limited_background_tasks.py
new file mode 100644
index 0000000000..b09bc31db8
--- /dev/null
+++ b/src/backend/base/langflow/api/limited_background_tasks.py
@@ -0,0 +1,29 @@
+from fastapi import BackgroundTasks
+
+from langflow.graph.utils import log_vertex_build
+from langflow.services.deps import get_settings_service
+
+
+class LimitVertexBuildBackgroundTasks(BackgroundTasks):
+ """A subclass of FastAPI BackgroundTasks that limits the number of tasks added per vertex_id.
+
+ If more than max_vertex_builds_per_vertex tasks are added for a given vertex_id,
+ the oldest task is removed so that only the most recent remain.
+ This only applies to log_vertex_build tasks.
+ """
+
+ def add_task(self, func, *args, **kwargs):
+ # Only apply limiting logic to log_vertex_build tasks
+ if func == log_vertex_build:
+ vertex_id = kwargs.get("vertex_id")
+ if vertex_id is not None:
+ # Filter tasks that are log_vertex_build calls with the same vertex_id
+ relevant_tasks = [
+ t for t in self.tasks if t.func == log_vertex_build and t.kwargs.get("vertex_id") == vertex_id
+ ]
+ if len(relevant_tasks) >= get_settings_service().settings.max_vertex_builds_per_vertex:
+ # Remove the oldest task for this vertex_id
+ oldest_task = relevant_tasks[0]
+ self.tasks.remove(oldest_task)
+
+ super().add_task(func, *args, **kwargs)
diff --git a/src/backend/base/langflow/api/utils.py b/src/backend/base/langflow/api/utils.py
index fb02a54025..b65bfd31e1 100644
--- a/src/backend/base/langflow/api/utils.py
+++ b/src/backend/base/langflow/api/utils.py
@@ -14,6 +14,7 @@ from langflow.graph.graph.base import Graph
from langflow.services.auth.utils import get_current_active_user
from langflow.services.database.models import User
from langflow.services.database.models.flow import Flow
+from langflow.services.database.models.message import MessageTable
from langflow.services.database.models.transactions.model import TransactionTable
from langflow.services.database.models.vertex_builds.model import VertexBuildTable
from langflow.services.deps import get_session, session_scope
@@ -281,16 +282,16 @@ def parse_value(value: Any, input_type: str) -> Any:
async def cascade_delete_flow(session: AsyncSession, flow_id: uuid.UUID) -> None:
try:
- await session.exec(delete(TransactionTable).where(TransactionTable.flow_id == flow_id))
- await session.exec(delete(VertexBuildTable).where(VertexBuildTable.flow_id == flow_id))
# TODO: Verify if deleting messages is safe in terms of session id relevance
# If we delete messages directly, rather than setting flow_id to null,
# it might cause unexpected behaviors because the session id could still be
# used elsewhere to search for these messages.
- # await session.exec(delete(MessageTable).where(MessageTable.flow_id == flow_id))
+ await session.exec(delete(MessageTable).where(MessageTable.flow_id == flow_id))
+ await session.exec(delete(TransactionTable).where(TransactionTable.flow_id == flow_id))
+ await session.exec(delete(VertexBuildTable).where(VertexBuildTable.flow_id == flow_id))
await session.exec(delete(Flow).where(Flow.id == flow_id))
except Exception as e:
- msg = f"Unable to cascade delete flow: ${flow_id}"
+ msg = f"Unable to cascade delete flow: {flow_id}"
raise RuntimeError(msg, e) from e
diff --git a/src/backend/base/langflow/api/v1/chat.py b/src/backend/base/langflow/api/v1/chat.py
index fbabacc3c6..d9c88908e6 100644
--- a/src/backend/base/langflow/api/v1/chat.py
+++ b/src/backend/base/langflow/api/v1/chat.py
@@ -1,26 +1,23 @@
from __future__ import annotations
-import asyncio
-import json
import time
import traceback
-import typing
import uuid
from typing import TYPE_CHECKING, Annotated
-from fastapi import APIRouter, BackgroundTasks, Body, HTTPException
+from fastapi import APIRouter, BackgroundTasks, Body, Depends, HTTPException
from fastapi.responses import StreamingResponse
from loguru import logger
-from sqlmodel import select
-from starlette.background import BackgroundTask
-from starlette.responses import ContentStream
-from starlette.types import Receive
+from langflow.api.build import (
+ get_flow_events_response,
+ start_flow_build,
+)
+from langflow.api.limited_background_tasks import LimitVertexBuildBackgroundTasks
from langflow.api.utils import (
CurrentActiveUser,
DbSession,
build_and_cache_graph_from_data,
- build_graph_from_data,
build_graph_from_db,
format_elapsed_time,
format_exception_message,
@@ -35,16 +32,21 @@ from langflow.api.v1.schemas import (
VertexBuildResponse,
VerticesOrderResponse,
)
-from langflow.events.event_manager import EventManager, create_default_event_manager
from langflow.exceptions.component import ComponentBuildError
from langflow.graph.graph.base import Graph
from langflow.graph.utils import log_vertex_build
-from langflow.schema.message import ErrorMessage
from langflow.schema.schema import OutputValue
from langflow.services.cache.utils import CacheMiss
from langflow.services.chat.service import ChatService
from langflow.services.database.models.flow.model import Flow
-from langflow.services.deps import get_chat_service, get_session, get_telemetry_service, session_scope
+from langflow.services.deps import (
+ get_chat_service,
+ get_queue_service,
+ get_session,
+ get_telemetry_service,
+ session_scope,
+)
+from langflow.services.job_queue.service import JobQueueService
from langflow.services.telemetry.schema import ComponentPayload, PlaygroundPayload
if TYPE_CHECKING:
@@ -53,22 +55,6 @@ if TYPE_CHECKING:
router = APIRouter(tags=["Chat"])
-async def try_running_celery_task(vertex, user_id):
- # Try running the task in celery
- # and set the task_id to the local vertex
- # if it fails, run the task locally
- try:
- from langflow.worker import build_vertex
-
- task = build_vertex.delay(vertex)
- vertex.task_id = task.id
- except Exception: # noqa: BLE001
- logger.opt(exception=True).debug("Error running task in celery")
- vertex.task_id = None
- await vertex.build(user_id=user_id)
- return vertex
-
-
@router.post("/build/{flow_id}/vertices", deprecated=True)
async def retrieve_vertices_order(
*,
@@ -143,331 +129,52 @@ async def retrieve_vertices_order(
@router.post("/build/{flow_id}/flow")
async def build_flow(
*,
- background_tasks: BackgroundTasks,
flow_id: uuid.UUID,
+ background_tasks: LimitVertexBuildBackgroundTasks,
inputs: Annotated[InputValueRequest | None, Body(embed=True)] = None,
data: Annotated[FlowDataRequest | None, Body(embed=True)] = None,
files: list[str] | None = None,
stop_component_id: str | None = None,
start_component_id: str | None = None,
- log_builds: bool | None = True,
+ log_builds: bool = True,
current_user: CurrentActiveUser,
+ queue_service: Annotated[JobQueueService, Depends(get_queue_service)],
):
- chat_service = get_chat_service()
- telemetry_service = get_telemetry_service()
- if not inputs:
- inputs = InputValueRequest(session=str(flow_id))
+ """Build and process a flow, returning a job ID for event polling."""
+ # First verify the flow exists
+ async with session_scope() as session:
+ flow = await session.get(Flow, flow_id)
+ if not flow:
+ raise HTTPException(status_code=404, detail=f"Flow with id {flow_id} not found")
- async def build_graph_and_get_order() -> tuple[list[str], list[str], Graph]:
- start_time = time.perf_counter()
- components_count = 0
- graph = None
- try:
- flow_id_str = str(flow_id)
- # Create a fresh session for database operations
- async with session_scope() as fresh_session:
- graph = await create_graph(fresh_session, flow_id_str)
-
- graph.validate_stream()
- first_layer = sort_vertices(graph)
-
- if inputs is not None and hasattr(inputs, "session") and inputs.session is not None:
- graph.session_id = inputs.session
-
- for vertex_id in first_layer:
- graph.run_manager.add_to_vertices_being_run(vertex_id)
-
- # Now vertices is a list of lists
- # We need to get the id of each vertex
- # and return the same structure but only with the ids
- components_count = len(graph.vertices)
- vertices_to_run = list(graph.vertices_to_run.union(get_top_level_vertices(graph, graph.vertices_to_run)))
-
- await chat_service.set_cache(flow_id_str, graph)
- await log_telemetry(start_time, components_count, success=True)
-
- except Exception as exc:
- await log_telemetry(start_time, components_count, success=False, error_message=str(exc))
-
- if "stream or streaming set to True" in str(exc):
- raise HTTPException(status_code=400, detail=str(exc)) from exc
- logger.exception("Error checking build status")
- raise HTTPException(status_code=500, detail=str(exc)) from exc
- return first_layer, vertices_to_run, graph
-
- async def log_telemetry(
- start_time: float, components_count: int, *, success: bool, error_message: str | None = None
- ):
- background_tasks.add_task(
- telemetry_service.log_package_playground,
- PlaygroundPayload(
- playground_seconds=int(time.perf_counter() - start_time),
- playground_component_count=components_count,
- playground_success=success,
- playground_error_message=str(error_message) if error_message else "",
- ),
- )
-
- async def create_graph(fresh_session, flow_id_str: str) -> Graph:
- if not data:
- return await build_graph_from_db(flow_id=flow_id, session=fresh_session, chat_service=chat_service)
-
- result = await fresh_session.exec(select(Flow.name).where(Flow.id == flow_id))
- flow_name = result.first()
-
- return await build_graph_from_data(
- flow_id=flow_id_str,
- payload=data.model_dump(),
- user_id=str(current_user.id),
- flow_name=flow_name,
- )
-
- def sort_vertices(graph: Graph) -> list[str]:
- try:
- return graph.sort_vertices(stop_component_id, start_component_id)
- except Exception: # noqa: BLE001
- logger.exception("Error sorting vertices")
- return graph.sort_vertices()
-
- async def _build_vertex(vertex_id: str, graph: Graph, event_manager: EventManager) -> VertexBuildResponse:
- flow_id_str = str(flow_id)
- next_runnable_vertices = []
- top_level_vertices = []
- start_time = time.perf_counter()
- error_message = None
- try:
- vertex = graph.get_vertex(vertex_id)
- try:
- lock = chat_service.async_cache_locks[flow_id_str]
- vertex_build_result = await graph.build_vertex(
- vertex_id=vertex_id,
- user_id=str(current_user.id),
- inputs_dict=inputs.model_dump() if inputs else {},
- files=files,
- get_cache=chat_service.get_cache,
- set_cache=chat_service.set_cache,
- event_manager=event_manager,
- )
- result_dict = vertex_build_result.result_dict
- params = vertex_build_result.params
- valid = vertex_build_result.valid
- artifacts = vertex_build_result.artifacts
- next_runnable_vertices = await graph.get_next_runnable_vertices(lock, vertex=vertex, cache=False)
- top_level_vertices = graph.get_top_level_vertices(next_runnable_vertices)
-
- result_data_response = ResultDataResponse.model_validate(result_dict, from_attributes=True)
- except Exception as exc: # noqa: BLE001
- if isinstance(exc, ComponentBuildError):
- params = exc.message
- tb = exc.formatted_traceback
- else:
- tb = traceback.format_exc()
- logger.exception("Error building Component")
- params = format_exception_message(exc)
- message = {"errorMessage": params, "stackTrace": tb}
- valid = False
- error_message = params
- output_label = vertex.outputs[0]["name"] if vertex.outputs else "output"
- outputs = {output_label: OutputValue(message=message, type="error")}
- result_data_response = ResultDataResponse(results={}, outputs=outputs)
- artifacts = {}
- background_tasks.add_task(graph.end_all_traces, error=exc)
-
- result_data_response.message = artifacts
-
- # Log the vertex build
- if not vertex.will_stream and log_builds:
- background_tasks.add_task(
- log_vertex_build,
- flow_id=flow_id_str,
- vertex_id=vertex_id,
- valid=valid,
- params=params,
- data=result_data_response,
- artifacts=artifacts,
- )
- else:
- await chat_service.set_cache(flow_id_str, graph)
-
- timedelta = time.perf_counter() - start_time
- duration = format_elapsed_time(timedelta)
- result_data_response.duration = duration
- result_data_response.timedelta = timedelta
- vertex.add_build_time(timedelta)
- inactivated_vertices = list(graph.inactivated_vertices)
- graph.reset_inactivated_vertices()
- graph.reset_activated_vertices()
- # graph.stop_vertex tells us if the user asked
- # to stop the build of the graph at a certain vertex
- # if it is in next_vertices_ids, we need to remove other
- # vertices from next_vertices_ids
- if graph.stop_vertex and graph.stop_vertex in next_runnable_vertices:
- next_runnable_vertices = [graph.stop_vertex]
-
- if not graph.run_manager.vertices_being_run and not next_runnable_vertices:
- background_tasks.add_task(graph.end_all_traces)
-
- build_response = VertexBuildResponse(
- inactivated_vertices=list(set(inactivated_vertices)),
- next_vertices_ids=list(set(next_runnable_vertices)),
- top_level_vertices=list(set(top_level_vertices)),
- valid=valid,
- params=params,
- id=vertex.id,
- data=result_data_response,
- )
- background_tasks.add_task(
- telemetry_service.log_package_component,
- ComponentPayload(
- component_name=vertex_id.split("-")[0],
- component_seconds=int(time.perf_counter() - start_time),
- component_success=valid,
- component_error_message=error_message,
- ),
- )
- except Exception as exc:
- background_tasks.add_task(
- telemetry_service.log_package_component,
- ComponentPayload(
- component_name=vertex_id.split("-")[0],
- component_seconds=int(time.perf_counter() - start_time),
- component_success=False,
- component_error_message=str(exc),
- ),
- )
- logger.exception("Error building Component")
- message = parse_exception(exc)
- raise HTTPException(status_code=500, detail=message) from exc
-
- return build_response
-
- async def build_vertices(
- vertex_id: str,
- graph: Graph,
- client_consumed_queue: asyncio.Queue,
- event_manager: EventManager,
- ) -> None:
- build_task = asyncio.create_task(_build_vertex(vertex_id, graph, event_manager))
- try:
- await build_task
- vertex_build_response: VertexBuildResponse = build_task.result()
- except asyncio.CancelledError as exc:
- logger.exception(exc)
- build_task.cancel()
- return
-
- # send built event or error event
- try:
- vertex_build_response_json = vertex_build_response.model_dump_json()
- build_data = json.loads(vertex_build_response_json)
- except Exception as exc:
- msg = f"Error serializing vertex build response: {exc}"
- raise ValueError(msg) from exc
- event_manager.on_end_vertex(data={"build_data": build_data})
- await client_consumed_queue.get()
- if vertex_build_response.valid and vertex_build_response.next_vertices_ids:
- tasks = []
- for next_vertex_id in vertex_build_response.next_vertices_ids:
- task = asyncio.create_task(build_vertices(next_vertex_id, graph, client_consumed_queue, event_manager))
- tasks.append(task)
- try:
- await asyncio.gather(*tasks)
- except asyncio.CancelledError:
- for task in tasks:
- task.cancel()
- return
-
- async def event_generator(event_manager: EventManager, client_consumed_queue: asyncio.Queue) -> None:
- try:
- ids, vertices_to_run, graph = await build_graph_and_get_order()
- except Exception as e:
- error_message = ErrorMessage(
- flow_id=flow_id,
- exception=e,
- )
- event_manager.on_error(data=error_message.data)
- raise
- event_manager.on_vertices_sorted(data={"ids": ids, "to_run": vertices_to_run})
- await client_consumed_queue.get()
- tasks = []
- for vertex_id in ids:
- task = asyncio.create_task(build_vertices(vertex_id, graph, client_consumed_queue, event_manager))
- tasks.append(task)
- try:
- await asyncio.gather(*tasks)
- except asyncio.CancelledError:
- background_tasks.add_task(graph.end_all_traces)
- for task in tasks:
- task.cancel()
- return
- except Exception as e:
- logger.error(f"Error building vertices: {e}")
- custom_component = graph.get_vertex(vertex_id).custom_component
- trace_name = getattr(custom_component, "trace_name", None)
- error_message = ErrorMessage(
- flow_id=flow_id,
- exception=e,
- session_id=graph.session_id,
- trace_name=trace_name,
- )
- event_manager.on_error(data=error_message.data)
- raise
- event_manager.on_end(data={})
- await event_manager.queue.put((None, None, time.time))
-
- async def consume_and_yield(queue: asyncio.Queue, client_consumed_queue: asyncio.Queue) -> typing.AsyncGenerator:
- while True:
- event_id, value, put_time = await queue.get()
- if value is None:
- break
- get_time = time.time()
- yield value
- get_time_yield = time.time()
- client_consumed_queue.put_nowait(event_id)
- logger.debug(
- f"consumed event {event_id} "
- f"(time in queue, {get_time - put_time:.4f}, "
- f"client {get_time_yield - get_time:.4f})"
- )
-
- asyncio_queue: asyncio.Queue = asyncio.Queue()
- asyncio_queue_client_consumed: asyncio.Queue = asyncio.Queue()
- event_manager = create_default_event_manager(queue=asyncio_queue)
- main_task = asyncio.create_task(event_generator(event_manager, asyncio_queue_client_consumed))
-
- def on_disconnect() -> None:
- logger.debug("Client disconnected, closing tasks")
- main_task.cancel()
-
- return DisconnectHandlerStreamingResponse(
- consume_and_yield(asyncio_queue, asyncio_queue_client_consumed),
- media_type="application/x-ndjson",
- on_disconnect=on_disconnect,
+ job_id = await start_flow_build(
+ flow_id=flow_id,
+ background_tasks=background_tasks,
+ inputs=inputs,
+ data=data,
+ files=files,
+ stop_component_id=stop_component_id,
+ start_component_id=start_component_id,
+ log_builds=log_builds,
+ current_user=current_user,
+ queue_service=queue_service,
)
+ return {"job_id": job_id}
-class DisconnectHandlerStreamingResponse(StreamingResponse):
- def __init__(
- self,
- content: ContentStream,
- status_code: int = 200,
- headers: typing.Mapping[str, str] | None = None,
- media_type: str | None = None,
- background: BackgroundTask | None = None,
- on_disconnect: typing.Callable | None = None,
- ):
- super().__init__(content, status_code, headers, media_type, background)
- self.on_disconnect = on_disconnect
-
- async def listen_for_disconnect(self, receive: Receive) -> None:
- while True:
- message = await receive()
- if message["type"] == "http.disconnect":
- if self.on_disconnect:
- coro = self.on_disconnect()
- if asyncio.iscoroutine(coro):
- await coro
- break
+@router.get("/build/{job_id}/events")
+async def get_build_events(
+ job_id: str,
+ queue_service: Annotated[JobQueueService, Depends(get_queue_service)],
+ *,
+ stream: bool = True,
+):
+ """Get events for a specific build job."""
+ return await get_flow_events_response(
+ job_id=job_id,
+ queue_service=queue_service,
+ stream=stream,
+ )
@router.post("/build/{flow_id}/vertices/{vertex_id}", deprecated=True)
diff --git a/src/backend/base/langflow/api/v1/endpoints.py b/src/backend/base/langflow/api/v1/endpoints.py
index 89a31daa06..3a6ff403a4 100644
--- a/src/backend/base/langflow/api/v1/endpoints.py
+++ b/src/backend/base/langflow/api/v1/endpoints.py
@@ -44,7 +44,7 @@ from langflow.services.database.models.flow import Flow
from langflow.services.database.models.flow.model import FlowRead
from langflow.services.database.models.flow.utils import get_all_webhook_components_in_flow
from langflow.services.database.models.user.model import User, UserRead
-from langflow.services.deps import get_session_service, get_settings_service, get_task_service, get_telemetry_service
+from langflow.services.deps import get_session_service, get_settings_service, get_telemetry_service
from langflow.services.settings.feature_flags import FEATURE_FLAGS
from langflow.services.telemetry.schema import RunPayload
from langflow.utils.version import get_version_info
@@ -599,29 +599,16 @@ async def process() -> None:
)
-@router.get("/task/{task_id}")
-async def get_task_status(task_id: str) -> TaskStatusResponse:
- task_service = get_task_service()
- task = task_service.get_task(task_id)
- result = None
- if task is None:
- raise HTTPException(status_code=404, detail="Task not found")
- if task.ready():
- result = task.result
- # If result isinstance of Exception, can we get the traceback?
- if isinstance(result, Exception):
- logger.exception(task.traceback)
+@router.get("/task/{_task_id}", deprecated=True)
+async def get_task_status(_task_id: str) -> TaskStatusResponse:
+ """Get the status of a task by ID (Deprecated).
- if isinstance(result, dict) and "result" in result:
- result = result["result"]
- elif hasattr(result, "result"):
- result = result.result
-
- if task.status == "FAILURE":
- result = str(task.result)
- logger.error(f"Task {task_id} failed: {task.traceback}")
-
- return TaskStatusResponse(status=task.status, result=result)
+ This endpoint is deprecated and will be removed in a future version.
+ """
+ raise HTTPException(
+ status_code=status.HTTP_400_BAD_REQUEST,
+ detail="The /task endpoint is deprecated and will be removed in a future version. Please use /run instead.",
+ )
@router.post(
diff --git a/src/backend/base/langflow/api/v1/mcp.py b/src/backend/base/langflow/api/v1/mcp.py
index 1516111d36..5db1f83546 100644
--- a/src/backend/base/langflow/api/v1/mcp.py
+++ b/src/backend/base/langflow/api/v1/mcp.py
@@ -3,7 +3,6 @@ import base64
import json
import logging
import traceback
-from contextlib import suppress
from contextvars import ContextVar
from typing import Annotated
from urllib.parse import quote, unquote, urlparse
@@ -266,8 +265,9 @@ async def handle_call_tool(
return collected_results
finally:
progress_task.cancel()
- with suppress(asyncio.CancelledError):
- await progress_task
+ await asyncio.wait([progress_task])
+ if not progress_task.cancelled() and (exc := progress_task.exception()) is not None:
+ raise exc
except Exception as e:
msg = f"Error in async session: {e}"
logger.exception(msg)
@@ -333,6 +333,7 @@ async def handle_sse(request: Request, current_user: Annotated[User, Depends(get
logger.info("Client disconnected from SSE connection")
except asyncio.CancelledError:
logger.info("SSE connection was cancelled")
+ raise
except Exception as e:
msg = f"Error in MCP: {e!s}"
logger.exception(msg)
diff --git a/src/backend/base/langflow/api/v1/monitor.py b/src/backend/base/langflow/api/v1/monitor.py
index 5181a9ec43..718f426f49 100644
--- a/src/backend/base/langflow/api/v1/monitor.py
+++ b/src/backend/base/langflow/api/v1/monitor.py
@@ -35,6 +35,7 @@ async def get_vertex_builds(flow_id: Annotated[UUID, Query()], session: DbSessio
async def delete_vertex_builds(flow_id: Annotated[UUID, Query()], session: DbSession) -> None:
try:
await delete_vertex_builds_by_flow_id(session, flow_id)
+ await session.commit()
except Exception as e:
raise HTTPException(status_code=500, detail=str(e)) from e
diff --git a/src/backend/base/langflow/api/v1/schemas.py b/src/backend/base/langflow/api/v1/schemas.py
index 0d90d12df9..a1a58f5b4d 100644
--- a/src/backend/base/langflow/api/v1/schemas.py
+++ b/src/backend/base/langflow/api/v1/schemas.py
@@ -1,7 +1,7 @@
from datetime import datetime, timezone
from enum import Enum
from pathlib import Path
-from typing import Any
+from typing import Any, Literal
from uuid import UUID
from pydantic import BaseModel, ConfigDict, Field, field_serializer, field_validator, model_serializer
@@ -376,3 +376,4 @@ class ConfigResponse(BaseModel):
auto_saving_interval: int
health_check_max_retries: int
max_file_size_upload: int
+ event_delivery: Literal["polling", "streaming"]
diff --git a/src/backend/base/langflow/base/agents/agent.py b/src/backend/base/langflow/base/agents/agent.py
index ce4ee01ad7..33c95e138c 100644
--- a/src/backend/base/langflow/base/agents/agent.py
+++ b/src/backend/base/langflow/base/agents/agent.py
@@ -169,8 +169,9 @@ class LCAgentComponent(Component):
cast("SendMessageFunctionType", self.send_message),
)
except ExceptionWithMessageError as e:
- msg_id = e.agent_message.id
- await delete_message(id_=msg_id)
+ if hasattr(e, "agent_message") and hasattr(e.agent_message, "id"):
+ msg_id = e.agent_message.id
+ await delete_message(id_=msg_id)
await self._send_message_event(e.agent_message, category="remove_message")
logger.error(f"ExceptionWithMessageError: {e}")
raise
diff --git a/src/backend/base/langflow/components/embeddings/huggingface_inference_api.py b/src/backend/base/langflow/components/embeddings/huggingface_inference_api.py
index 762b927658..3ccd9f55c6 100644
--- a/src/backend/base/langflow/components/embeddings/huggingface_inference_api.py
+++ b/src/backend/base/langflow/components/embeddings/huggingface_inference_api.py
@@ -73,7 +73,7 @@ class HuggingFaceInferenceAPIEmbeddingsComponent(LCEmbeddingsModel):
def get_api_url(self) -> str:
if "huggingface" in self.inference_endpoint.lower():
- return f"{self.inference_endpoint}{self.model_name}"
+ return f"{self.inference_endpoint}"
return self.inference_endpoint
@retry(stop=stop_after_attempt(3), wait=wait_fixed(2))
diff --git a/src/backend/base/langflow/components/firecrawl/firecrawl_crawl_api.py b/src/backend/base/langflow/components/firecrawl/firecrawl_crawl_api.py
index ab9550d428..0e85c8c2b1 100644
--- a/src/backend/base/langflow/components/firecrawl/firecrawl_crawl_api.py
+++ b/src/backend/base/langflow/components/firecrawl/firecrawl_crawl_api.py
@@ -26,6 +26,7 @@ class FirecrawlCrawlApi(Component):
display_name="URL",
required=True,
info="The URL to scrape.",
+ tool_mode=True,
),
IntInput(
name="timeout",
diff --git a/src/backend/base/langflow/components/firecrawl/firecrawl_scrape_api.py b/src/backend/base/langflow/components/firecrawl/firecrawl_scrape_api.py
index 18defab85e..7356862859 100644
--- a/src/backend/base/langflow/components/firecrawl/firecrawl_scrape_api.py
+++ b/src/backend/base/langflow/components/firecrawl/firecrawl_scrape_api.py
@@ -30,6 +30,7 @@ class FirecrawlScrapeApi(Component):
display_name="URL",
required=True,
info="The URL to scrape.",
+ tool_mode=True,
),
IntInput(
name="timeout",
diff --git a/src/backend/base/langflow/components/helpers/batch_run.py b/src/backend/base/langflow/components/helpers/batch_run.py
index 6c91400601..5aeb509a13 100644
--- a/src/backend/base/langflow/components/helpers/batch_run.py
+++ b/src/backend/base/langflow/components/helpers/batch_run.py
@@ -1,9 +1,18 @@
from __future__ import annotations
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, Any
+
+from loguru import logger
from langflow.custom import Component
-from langflow.io import DataFrameInput, HandleInput, MultilineInput, Output, StrInput
+from langflow.io import (
+ BoolInput,
+ DataFrameInput,
+ HandleInput,
+ MessageTextInput,
+ MultilineInput,
+ Output,
+)
from langflow.schema import DataFrame
if TYPE_CHECKING:
@@ -14,8 +23,8 @@ class BatchRunComponent(Component):
display_name = "Batch Run"
description = (
"Runs a language model over each row of a DataFrame's text column and returns a new "
- "DataFrame with two columns: 'text_input' (the original text) and 'model_response' "
- "containing the model's response."
+ "DataFrame with three columns: '**text_input**' (the original text), "
+ "'**model_response**' (the model's response),and '**batch_index**' (the processing order)."
)
icon = "List"
beta = True
@@ -26,6 +35,7 @@ class BatchRunComponent(Component):
display_name="Language Model",
info="Connect the 'Language Model' output from your LLM component here.",
input_types=["LanguageModel"],
+ required=True,
),
MultilineInput(
name="system_message",
@@ -37,12 +47,23 @@ class BatchRunComponent(Component):
name="df",
display_name="DataFrame",
info="The DataFrame whose column (specified by 'column_name') we'll treat as text messages.",
+ required=True,
),
- StrInput(
+ MessageTextInput(
name="column_name",
display_name="Column Name",
info="The name of the DataFrame column to treat as text messages. Default='text'.",
value="text",
+ required=True,
+ advanced=True,
+ ),
+ BoolInput(
+ name="enable_metadata",
+ display_name="Enable Metadata",
+ info="If True, add metadata to the output DataFrame.",
+ value=True,
+ required=False,
+ advanced=True,
),
]
@@ -51,51 +72,123 @@ class BatchRunComponent(Component):
display_name="Batch Results",
name="batch_results",
method="run_batch",
- info="A DataFrame with two columns: 'text_input' and 'model_response'.",
+ info="A DataFrame with columns: 'text_input', 'model_response', 'batch_index', and 'metadata'.",
),
]
- async def run_batch(self) -> DataFrame:
- """For each row in df[column_name], combine that text with system_message, then invoke the model asynchronously.
+ def _create_base_row(self, text_input: str = "", model_response: str = "", batch_index: int = -1) -> dict[str, Any]:
+ """Create a base row with optional metadata."""
+ return {
+ "text_input": text_input,
+ "model_response": model_response,
+ "batch_index": batch_index,
+ }
- Returns a new DataFrame of the same length, with columns 'text_input' and 'model_response'.
+ def _add_metadata(
+ self, row: dict[str, Any], *, success: bool = True, system_msg: str = "", error: str | None = None
+ ) -> None:
+ """Add metadata to a row if enabled."""
+ if not self.enable_metadata:
+ return
+
+ if success:
+ row["metadata"] = {
+ "has_system_message": bool(system_msg),
+ "input_length": len(row["text_input"]),
+ "response_length": len(row["model_response"]),
+ "processing_status": "success",
+ }
+ else:
+ row["metadata"] = {
+ "error": error,
+ "processing_status": "failed",
+ }
+
+ async def run_batch(self) -> DataFrame:
+ """Process each row in df[column_name] with the language model asynchronously.
+
+ Returns:
+ DataFrame: A new DataFrame containing:
+ - text_input: The original input text
+ - model_response: The model's response
+ - batch_index: The processing order
+ - metadata: Additional processing information
+
+ Raises:
+ ValueError: If the specified column is not found in the DataFrame
+ TypeError: If the model is not compatible or input types are wrong
"""
model: Runnable = self.model
system_msg = self.system_message or ""
df: DataFrame = self.df
col_name = self.column_name or "text"
+ # Validate inputs first
+ if not isinstance(df, DataFrame):
+ msg = f"Expected DataFrame input, got {type(df)}"
+ raise TypeError(msg)
+
if col_name not in df.columns:
- msg = f"Column '{col_name}' not found in the DataFrame."
+ msg = f"Column '{col_name}' not found in the DataFrame. Available columns: {', '.join(df.columns)}"
raise ValueError(msg)
- # Convert the specified column to a list of strings
- user_texts = df[col_name].astype(str).tolist()
+ try:
+ # Convert the specified column to a list of strings
+ user_texts = df[col_name].astype(str).tolist()
+ total_rows = len(user_texts)
- # Prepare the batch of conversations
- conversations = [
- [{"role": "system", "content": system_msg}, {"role": "user", "content": text}]
- if system_msg
- else [{"role": "user", "content": text}]
- for text in user_texts
- ]
- model = model.with_config(
- {
- "run_name": self.display_name,
- "project_name": self.get_project_name(),
- "callbacks": self.get_langchain_callbacks(),
- }
- )
+ logger.info(f"Processing {total_rows} rows with batch run")
- responses = await model.abatch(conversations)
+ # Prepare the batch of conversations
+ conversations = [
+ [{"role": "system", "content": system_msg}, {"role": "user", "content": text}]
+ if system_msg
+ else [{"role": "user", "content": text}]
+ for text in user_texts
+ ]
- # Build the final data, each row has 'text_input' + 'model_response'
- rows = []
- for original_text, response in zip(user_texts, responses, strict=False):
- resp_text = response.content if hasattr(response, "content") else str(response)
+ # Configure the model with project info and callbacks
+ model = model.with_config(
+ {
+ "run_name": self.display_name,
+ "project_name": self.get_project_name(),
+ "callbacks": self.get_langchain_callbacks(),
+ }
+ )
- row = {"text_input": original_text, "model_response": resp_text}
- rows.append(row)
+ # Process batches and track progress
+ responses_with_idx = [
+ (idx, response)
+ for idx, response in zip(
+ range(len(conversations)), await model.abatch(list(conversations)), strict=True
+ )
+ ]
- # Convert to a new DataFrame
- return DataFrame(rows) # Langflow DataFrame from a list of dicts
+ # Sort by index to maintain order
+ responses_with_idx.sort(key=lambda x: x[0])
+
+ # Build the final data with enhanced metadata
+ rows: list[dict[str, Any]] = []
+ for idx, response in responses_with_idx:
+ resp_text = response.content if hasattr(response, "content") else str(response)
+ row = self._create_base_row(
+ text_input=user_texts[idx],
+ model_response=resp_text,
+ batch_index=idx,
+ )
+ self._add_metadata(row, success=True, system_msg=system_msg)
+ rows.append(row)
+
+ # Log progress
+ if (idx + 1) % max(1, total_rows // 10) == 0:
+ logger.info(f"Processed {idx + 1}/{total_rows} rows")
+
+ logger.info("Batch processing completed successfully")
+ return DataFrame(rows)
+
+ except (KeyError, AttributeError) as e:
+ # Handle data structure and attribute access errors
+ logger.error(f"Data processing error: {e!s}")
+ error_row = self._create_base_row()
+ self._add_metadata(error_row, success=False, error=str(e))
+ return DataFrame([error_row])
diff --git a/src/backend/base/langflow/components/helpers/store_message.py b/src/backend/base/langflow/components/helpers/store_message.py
index ae779b399e..18fea64e64 100644
--- a/src/backend/base/langflow/components/helpers/store_message.py
+++ b/src/backend/base/langflow/components/helpers/store_message.py
@@ -61,10 +61,10 @@ class MessageStoreComponent(Component):
self.memory.session_id = message.session_id
lc_message = message.to_lc_message()
await self.memory.aadd_messages([lc_message])
- stored_message = await self.memory.aget_messages()
- stored_message = [Message.from_lc_message(m) for m in stored_message]
+ stored_messages = await self.memory.aget_messages()
+ stored_messages = [Message.from_lc_message(m) for m in stored_messages]
if message.sender:
- stored_message = [m for m in stored_message if m.sender == message.sender]
+ stored_messages = [m for m in stored_messages if m.sender == message.sender]
else:
await astore_message(message, flow_id=self.graph.flow_id)
stored_messages = await aget_messages(
diff --git a/src/backend/base/langflow/components/olivya/__init__.py b/src/backend/base/langflow/components/olivya/__init__.py
new file mode 100644
index 0000000000..8aa987f5d1
--- /dev/null
+++ b/src/backend/base/langflow/components/olivya/__init__.py
@@ -0,0 +1,3 @@
+from .olivya import OlivyaComponent
+
+__all__ = ["OlivyaComponent"]
diff --git a/src/backend/base/langflow/components/olivya/olivya.py b/src/backend/base/langflow/components/olivya/olivya.py
new file mode 100644
index 0000000000..1604df9be1
--- /dev/null
+++ b/src/backend/base/langflow/components/olivya/olivya.py
@@ -0,0 +1,116 @@
+import json
+
+import httpx
+from loguru import logger
+
+from langflow.custom import Component
+from langflow.io import MessageTextInput, Output
+from langflow.schema import Data
+
+
+class OlivyaComponent(Component):
+ display_name = "Place Call"
+ description = "A component to create an outbound call request from Olivya's platform."
+ documentation: str = "http://docs.langflow.org/components/olivya"
+ icon = "Olivya"
+ name = "OlivyaComponent"
+
+ inputs = [
+ MessageTextInput(
+ name="api_key",
+ display_name="API Key",
+ info="Your API key for authentication",
+ value="",
+ required=True,
+ ),
+ MessageTextInput(
+ name="from_number",
+ display_name="From Number",
+ info="The Agent's phone number",
+ value="",
+ required=True,
+ ),
+ MessageTextInput(
+ name="to_number",
+ display_name="To Number",
+ info="The recipient's phone number",
+ value="",
+ required=True,
+ ),
+ MessageTextInput(
+ name="first_message",
+ display_name="First Message",
+ info="The Agent's introductory message",
+ value="",
+ required=False,
+ tool_mode=True,
+ ),
+ MessageTextInput(
+ name="system_prompt",
+ display_name="System Prompt",
+ info="The system prompt to guide the interaction",
+ value="",
+ required=False,
+ ),
+ MessageTextInput(
+ name="conversation_history",
+ display_name="Conversation History",
+ info="The summary of the conversation",
+ value="",
+ required=False,
+ tool_mode=True,
+ ),
+ ]
+
+ outputs = [
+ Output(display_name="Output", name="output", method="build_output"),
+ ]
+
+ async def build_output(self) -> Data:
+ try:
+ payload = {
+ "variables": {
+ "first_message": self.first_message.strip() if self.first_message else None,
+ "system_prompt": self.system_prompt.strip() if self.system_prompt else None,
+ "conversation_history": self.conversation_history.strip() if self.conversation_history else None,
+ },
+ "from_number": self.from_number.strip(),
+ "to_number": self.to_number.strip(),
+ }
+
+ headers = {
+ "Authorization": self.api_key.strip(),
+ "Content-Type": "application/json",
+ }
+
+ logger.info("Sending POST request with payload: %s", payload)
+
+ # Send the POST request with a timeout
+ async with httpx.AsyncClient() as client:
+ response = await client.post(
+ "https://phone.olivya.io/create_zap_call",
+ headers=headers,
+ json=payload,
+ timeout=10.0,
+ )
+ response.raise_for_status()
+
+ # Parse and return the successful response
+ response_data = response.json()
+ logger.info("Request successful: %s", response_data)
+
+ except httpx.HTTPStatusError as http_err:
+ logger.exception("HTTP error occurred")
+ response_data = {"error": f"HTTP error occurred: {http_err}", "response_text": response.text}
+ except httpx.RequestError as req_err:
+ logger.exception("Request failed")
+ response_data = {"error": f"Request failed: {req_err}"}
+ except json.JSONDecodeError as json_err:
+ logger.exception("Response parsing failed")
+ response_data = {"error": f"Response parsing failed: {json_err}", "raw_response": response.text}
+ except Exception as e: # noqa: BLE001
+ logger.exception("An unexpected error occurred")
+ response_data = {"error": f"An unexpected error occurred: {e!s}"}
+
+ # Return the response as part of the output
+ return Data(value=response_data)
diff --git a/src/backend/base/langflow/components/processing/data_to_dataframe.py b/src/backend/base/langflow/components/processing/data_to_dataframe.py
new file mode 100644
index 0000000000..9cd8e4776a
--- /dev/null
+++ b/src/backend/base/langflow/components/processing/data_to_dataframe.py
@@ -0,0 +1,68 @@
+from langflow.custom import Component
+from langflow.io import DataInput, Output
+from langflow.schema import Data, DataFrame
+
+
+class DataToDataFrameComponent(Component):
+ display_name = "Data → DataFrame"
+ description = (
+ "Converts one or multiple Data objects into a DataFrame. "
+ "Each Data object corresponds to one row. Fields from `.data` become columns, "
+ "and the `.text` (if present) is placed in a 'text' column."
+ )
+ icon = "table"
+ name = "DataToDataFrame"
+
+ inputs = [
+ DataInput(
+ name="data_list",
+ display_name="Data or Data List",
+ info="One or multiple Data objects to transform into a DataFrame.",
+ is_list=True,
+ ),
+ ]
+
+ outputs = [
+ Output(
+ display_name="DataFrame",
+ name="dataframe",
+ method="build_dataframe",
+ info="A DataFrame built from each Data object's fields plus a 'text' column.",
+ ),
+ ]
+
+ def build_dataframe(self) -> DataFrame:
+ """Builds a DataFrame from Data objects by combining their fields.
+
+ For each Data object:
+ - Merge item.data (dictionary) as columns
+ - If item.text is present, add 'text' column
+
+ Returns a DataFrame with one row per Data object.
+ """
+ data_input = self.data_list
+
+ # If user passed a single Data, it might come in as a single object rather than a list
+ if not isinstance(data_input, list):
+ data_input = [data_input]
+
+ rows = []
+ for item in data_input:
+ if not isinstance(item, Data):
+ msg = f"Expected Data objects, got {type(item)} instead."
+ raise TypeError(msg)
+
+ # Start with a copy of item.data or an empty dict
+ row_dict = dict(item.data) if item.data else {}
+
+ # If the Data object has text, store it under 'text' col
+ text_val = item.get_text()
+ if text_val:
+ row_dict["text"] = text_val
+
+ rows.append(row_dict)
+
+ # Build a DataFrame from these row dictionaries
+ df_result = DataFrame(rows)
+ self.status = df_result # store in self.status for logs
+ return df_result
diff --git a/src/backend/base/langflow/components/processing/parse_data.py b/src/backend/base/langflow/components/processing/parse_data.py
index 6ca15830f0..f6d865e77e 100644
--- a/src/backend/base/langflow/components/processing/parse_data.py
+++ b/src/backend/base/langflow/components/processing/parse_data.py
@@ -10,9 +10,18 @@ class ParseDataComponent(Component):
description = "Convert Data objects into Messages using any {field_name} from input data."
icon = "message-square"
name = "ParseData"
+ metadata = {
+ "legacy_name": "Parse Data",
+ }
inputs = [
- DataInput(name="data", display_name="Data", info="The data to convert to text.", is_list=True, required=True),
+ DataInput(
+ name="data",
+ display_name="Data",
+ info="The data to convert to text.",
+ is_list=True,
+ required=True,
+ ),
MultilineInput(
name="template",
display_name="Template",
diff --git a/src/backend/base/langflow/components/processing/save_to_file.py b/src/backend/base/langflow/components/processing/save_to_file.py
new file mode 100644
index 0000000000..9494c185de
--- /dev/null
+++ b/src/backend/base/langflow/components/processing/save_to_file.py
@@ -0,0 +1,172 @@
+import json
+from collections.abc import AsyncIterator, Iterator
+from pathlib import Path
+
+import pandas as pd
+
+from langflow.custom import Component
+from langflow.io import (
+ DataFrameInput,
+ DataInput,
+ DropdownInput,
+ MessageInput,
+ Output,
+ StrInput,
+)
+from langflow.schema import Data, DataFrame, Message
+
+
+class SaveToFileComponent(Component):
+ display_name = "Save to File"
+ description = "Save DataFrames, Data, or Messages to various file formats."
+ icon = "save"
+ name = "SaveToFile"
+
+ # File format options for different types
+ DATA_FORMAT_CHOICES = ["csv", "excel", "json", "markdown"]
+ MESSAGE_FORMAT_CHOICES = ["txt", "json", "markdown"]
+
+ inputs = [
+ DropdownInput(
+ name="input_type",
+ display_name="Input Type",
+ options=["DataFrame", "Data", "Message"],
+ info="Select the type of input to save.",
+ value="DataFrame",
+ real_time_refresh=True,
+ ),
+ DataFrameInput(
+ name="df",
+ display_name="DataFrame",
+ info="The DataFrame to save.",
+ dynamic=True,
+ show=True,
+ ),
+ DataInput(
+ name="data",
+ display_name="Data",
+ info="The Data object to save.",
+ dynamic=True,
+ show=False,
+ ),
+ MessageInput(
+ name="message",
+ display_name="Message",
+ info="The Message to save.",
+ dynamic=True,
+ show=False,
+ ),
+ DropdownInput(
+ name="file_format",
+ display_name="File Format",
+ options=DATA_FORMAT_CHOICES,
+ info="Select the file format to save the input.",
+ real_time_refresh=True,
+ ),
+ StrInput(
+ name="file_path",
+ display_name="File Path (including filename)",
+ info="The full file path (including filename and extension).",
+ value="./output",
+ ),
+ ]
+
+ outputs = [
+ Output(
+ name="confirmation",
+ display_name="Confirmation",
+ method="save_to_file",
+ info="Confirmation message after saving the file.",
+ ),
+ ]
+
+ def update_build_config(self, build_config, field_value, field_name=None):
+ # Hide/show dynamic fields based on the selected input type
+ if field_name == "input_type":
+ build_config["df"]["show"] = field_value == "DataFrame"
+ build_config["data"]["show"] = field_value == "Data"
+ build_config["message"]["show"] = field_value == "Message"
+
+ if field_value in ["DataFrame", "Data"]:
+ build_config["file_format"]["options"] = self.DATA_FORMAT_CHOICES
+ elif field_value == "Message":
+ build_config["file_format"]["options"] = self.MESSAGE_FORMAT_CHOICES
+
+ return build_config
+
+ def save_to_file(self) -> str:
+ input_type = self.input_type
+ file_format = self.file_format
+ file_path = Path(self.file_path).expanduser()
+
+ # Ensure the directory exists
+ if not file_path.parent.exists():
+ file_path.parent.mkdir(parents=True, exist_ok=True)
+
+ if input_type == "DataFrame":
+ dataframe = self.df
+ return self._save_dataframe(dataframe, file_path, file_format)
+ if input_type == "Data":
+ data = self.data
+ return self._save_data(data, file_path, file_format)
+ if input_type == "Message":
+ message = self.message
+ return self._save_message(message, file_path, file_format)
+
+ error_msg = f"Unsupported input type: {input_type}"
+ raise ValueError(error_msg)
+
+ def _save_dataframe(self, dataframe: DataFrame, path: Path, fmt: str) -> str:
+ if fmt == "csv":
+ dataframe.to_csv(path, index=False)
+ elif fmt == "excel":
+ dataframe.to_excel(path, index=False, engine="openpyxl")
+ elif fmt == "json":
+ dataframe.to_json(path, orient="records", indent=2)
+ elif fmt == "markdown":
+ path.write_text(dataframe.to_markdown(index=False), encoding="utf-8")
+ else:
+ error_msg = f"Unsupported DataFrame format: {fmt}"
+ raise ValueError(error_msg)
+
+ return f"DataFrame saved successfully as '{path}'"
+
+ def _save_data(self, data: Data, path: Path, fmt: str) -> str:
+ if fmt == "csv":
+ pd.DataFrame(data.data).to_csv(path, index=False)
+ elif fmt == "excel":
+ pd.DataFrame(data.data).to_excel(path, index=False, engine="openpyxl")
+ elif fmt == "json":
+ path.write_text(json.dumps(data.data, indent=2), encoding="utf-8")
+ elif fmt == "markdown":
+ path.write_text(pd.DataFrame(data.data).to_markdown(index=False), encoding="utf-8")
+ else:
+ error_msg = f"Unsupported Data format: {fmt}"
+ raise ValueError(error_msg)
+
+ return f"Data saved successfully as '{path}'"
+
+ def _save_message(self, message: Message, path: Path, fmt: str) -> str:
+ if message.text is None:
+ content = ""
+ elif isinstance(message.text, AsyncIterator):
+ # AsyncIterator needs to be handled differently
+ error_msg = "AsyncIterator not supported"
+ raise ValueError(error_msg)
+ elif isinstance(message.text, Iterator):
+ # Convert iterator to string
+ content = " ".join(str(item) for item in message.text)
+ else:
+ content = str(message.text)
+
+ if fmt == "txt":
+ path.write_text(content, encoding="utf-8")
+ elif fmt == "json":
+ path.write_text(json.dumps({"message": content}, indent=2), encoding="utf-8")
+ elif fmt == "markdown":
+ path.write_text(f"**Message:**\n\n{content}", encoding="utf-8")
+ else:
+ error_msg = f"Unsupported Message format: {fmt}"
+ raise ValueError(error_msg)
+
+ return f"Message saved successfully as '{path}'"
diff --git a/src/backend/base/langflow/components/vectorstores/astradb.py b/src/backend/base/langflow/components/vectorstores/astradb.py
index 83a4d46f62..2f19e94617 100644
--- a/src/backend/base/langflow/components/vectorstores/astradb.py
+++ b/src/backend/base/langflow/components/vectorstores/astradb.py
@@ -1,8 +1,8 @@
-import os
from collections import defaultdict
-from dataclasses import dataclass, field
+from dataclasses import asdict, dataclass, field
from astrapy import AstraDBAdmin, DataAPIClient, Database
+from astrapy.info import CollectionDescriptor
from langchain_astradb import AstraDBVectorStore, CollectionVectorServiceOptions
from langflow.base.vectorstores.model import LCVectorStoreComponent, check_cached_vector_store
@@ -36,22 +36,24 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
default_factory=lambda: {
"data": {
"node": {
- "description": "Create a new database in Astra DB.",
- "display_name": "Create New Database",
+ "name": "create_database",
+ "description": "",
+ "display_name": "Create new database",
"field_order": ["new_database_name", "cloud_provider", "region"],
"template": {
"new_database_name": StrInput(
name="new_database_name",
- display_name="New Database Name",
+ display_name="Name",
info="Name of the new database to create in Astra DB.",
required=True,
),
"cloud_provider": DropdownInput(
name="cloud_provider",
- display_name="Cloud Provider",
+ display_name="Cloud provider",
info="Cloud provider for the new database.",
options=["Amazon Web Services", "Google Cloud Platform", "Microsoft Azure"],
required=True,
+ real_time_refresh=True,
),
"region": DropdownInput(
name="region",
@@ -73,8 +75,9 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
default_factory=lambda: {
"data": {
"node": {
- "description": "Create a new collection in Astra DB.",
- "display_name": "Create New Collection",
+ "name": "create_collection",
+ "description": "",
+ "display_name": "Create new collection",
"field_order": [
"new_collection_name",
"embedding_generation_provider",
@@ -83,23 +86,31 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
"template": {
"new_collection_name": StrInput(
name="new_collection_name",
- display_name="New Collection Name",
+ display_name="Name",
info="Name of the new collection to create in Astra DB.",
required=True,
),
"embedding_generation_provider": DropdownInput(
name="embedding_generation_provider",
- display_name="Embedding Generation Provider",
+ display_name="Embedding generation method",
info="Provider to use for generating embeddings.",
- options=[],
+ real_time_refresh=True,
required=True,
+ options=["Bring your own", "Nvidia"],
),
"embedding_generation_model": DropdownInput(
name="embedding_generation_model",
- display_name="Embedding Generation Model",
+ display_name="Embedding model",
info="Model to use for generating embeddings.",
- options=[],
required=True,
+ options=[],
+ ),
+ "dimension": IntInput(
+ name="dimension",
+ display_name="Dimensions (Required only for `Bring your own`)",
+ info="Dimensions of the embeddings to generate.",
+ required=False,
+ value=1024,
),
},
},
@@ -125,17 +136,18 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
real_time_refresh=True,
),
DropdownInput(
- name="api_endpoint",
+ name="database_name",
display_name="Database",
- info="The Database / API Endpoint for the Astra DB instance.",
+ info="The Database name for the Astra DB instance.",
required=True,
refresh_button=True,
real_time_refresh=True,
+ dialog_inputs=asdict(NewDatabaseInput()),
combobox=True,
),
StrInput(
- name="d_api_endpoint",
- display_name="Database API Endpoint",
+ name="api_endpoint",
+ display_name="Astra DB API Endpoint",
info="The API Endpoint for the Astra DB instance. Supercedes database selection.",
advanced=True,
),
@@ -146,8 +158,9 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
required=True,
refresh_button=True,
real_time_refresh=True,
- # dialog_inputs=asdict(NewCollectionInput()),
+ dialog_inputs=asdict(NewCollectionInput()),
combobox=True,
+ advanced=True,
),
StrInput(
name="keyspace",
@@ -238,6 +251,7 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
@classmethod
def map_cloud_providers(cls):
+ # TODO: Programmatically fetch the regions for each cloud provider
return {
"Amazon Web Services": {
"id": "aws",
@@ -254,54 +268,87 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
}
@classmethod
- def create_database_api(
+ def get_vectorize_providers(cls, token: str, environment: str | None = None, api_endpoint: str | None = None):
+ try:
+ # Get the admin object
+ admin = AstraDBAdmin(token=token, environment=environment)
+ db_admin = admin.get_database_admin(api_endpoint=api_endpoint)
+
+ # Get the list of embedding providers
+ embedding_providers = db_admin.find_embedding_providers().as_dict()
+
+ vectorize_providers_mapping = {}
+ # Map the provider display name to the provider key and models
+ for provider_key, provider_data in embedding_providers["embeddingProviders"].items():
+ # Get the provider display name and models
+ display_name = provider_data["displayName"]
+ models = [model["name"] for model in provider_data["models"]]
+
+ # Build our mapping
+ vectorize_providers_mapping[display_name] = [provider_key, models]
+
+ # Sort the resulting dictionary
+ return defaultdict(list, dict(sorted(vectorize_providers_mapping.items())))
+ except Exception as e:
+ msg = f"Error fetching vectorize providers: {e}"
+ raise ValueError(msg) from e
+
+ @classmethod
+ async def create_database_api(
cls,
- token: str,
new_database_name: str,
cloud_provider: str,
region: str,
+ token: str,
+ environment: str | None = None,
+ keyspace: str | None = None,
):
- client = DataAPIClient(token=token)
+ client = DataAPIClient(token=token, environment=environment)
# Get the admin object
admin_client = client.get_admin(token=token)
# Call the create database function
- return admin_client.create_database(
+ return await admin_client.async_create_database(
name=new_database_name,
- cloud_provider=cloud_provider,
+ cloud_provider=cls.map_cloud_providers()[cloud_provider]["id"],
region=region,
+ keyspace=keyspace,
+ wait_until_active=False,
)
@classmethod
- def create_collection_api(
+ async def create_collection_api(
cls,
- token: str,
- database_name: str,
new_collection_name: str,
+ token: str,
+ api_endpoint: str,
+ environment: str | None = None,
+ keyspace: str | None = None,
dimension: int | None = None,
embedding_generation_provider: str | None = None,
embedding_generation_model: str | None = None,
):
+ # Create the data API client
client = DataAPIClient(token=token)
- api_endpoint = cls.get_api_endpoint_static(token=token, database_name=database_name)
# Get the database object
- database = client.get_database(api_endpoint=api_endpoint, token=token)
+ database = client.get_async_database(api_endpoint=api_endpoint, token=token)
# Build vectorize options, if needed
vectorize_options = None
if not dimension:
vectorize_options = CollectionVectorServiceOptions(
- provider=embedding_generation_provider,
+ provider=cls.get_vectorize_providers(
+ token=token, environment=environment, api_endpoint=api_endpoint
+ ).get(embedding_generation_provider, [None, []])[0],
model_name=embedding_generation_model,
- authentication=None,
- parameters=None,
)
# Create the collection
- return database.create_collection(
+ return await database.create_collection(
name=new_collection_name,
+ keyspace=keyspace,
dimension=dimension,
service=vectorize_options,
)
@@ -325,16 +372,28 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
db_info_dict = {}
for db in db_list:
try:
+ # Get the API endpoint for the database
api_endpoint = f"https://{db.info.id}-{db.info.region}.apps.astra{env_string}.datastax.com"
- db_info_dict[db.info.name] = {
- "api_endpoint": api_endpoint,
- "collections": len(
+
+ # Get the number of collections
+ try:
+ num_collections = len(
list(
client.get_database(
api_endpoint=api_endpoint, token=token, keyspace=db.info.keyspace
).list_collection_names(keyspace=db.info.keyspace)
)
- ),
+ )
+ except Exception: # noqa: BLE001
+ num_collections = 0
+ if db.status != "PENDING":
+ continue
+
+ # Add the database to the dictionary
+ db_info_dict[db.info.name] = {
+ "api_endpoint": api_endpoint,
+ "collections": num_collections,
+ "status": db.status if db.status != "ACTIVE" else None,
}
except Exception: # noqa: BLE001, S110
pass
@@ -364,15 +423,20 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
if not database_name:
return None
- # Otherwise, get the URL from the database list
- return cls.get_database_list_static(token=token, environment=environment).get(database_name).get("api_endpoint")
+ # Grab the database object
+ db = cls.get_database_list_static(token=token, environment=environment).get(database_name)
+ if not db:
+ return None
- def get_api_endpoint(self, *, api_endpoint: str | None = None):
+ # Otherwise, get the URL from the database list
+ return db.get("api_endpoint")
+
+ def get_api_endpoint(self):
return self.get_api_endpoint_static(
token=self.token,
environment=self.environment,
- api_endpoint=api_endpoint or self.d_api_endpoint,
- database_name=self.api_endpoint,
+ api_endpoint=self.api_endpoint,
+ database_name=self.database_name,
)
def get_keyspace(self):
@@ -388,7 +452,7 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
client = DataAPIClient(token=self.token, environment=self.environment)
return client.get_database(
- api_endpoint=self.get_api_endpoint(api_endpoint=api_endpoint),
+ api_endpoint=api_endpoint or self.get_api_endpoint(),
token=self.token,
keyspace=self.get_keyspace(),
)
@@ -415,40 +479,15 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
return None
- def get_vectorize_providers(self):
- try:
- self.log("Dynamically updating list of Vectorize providers.")
-
- # Get the admin object
- admin = AstraDBAdmin(token=self.token)
- db_admin = admin.get_database_admin(api_endpoint=self.get_api_endpoint())
-
- # Get the list of embedding providers
- embedding_providers = db_admin.find_embedding_providers().as_dict()
-
- vectorize_providers_mapping = {}
- # Map the provider display name to the provider key and models
- for provider_key, provider_data in embedding_providers["embeddingProviders"].items():
- display_name = provider_data["displayName"]
- models = [model["name"] for model in provider_data["models"]]
-
- # TODO: https://astra.datastax.com/api/v2/graphql
- vectorize_providers_mapping[display_name] = [provider_key, models]
-
- # Sort the resulting dictionary
- return defaultdict(list, dict(sorted(vectorize_providers_mapping.items())))
- except Exception as e: # noqa: BLE001
- self.log(f"Error fetching Vectorize providers: {e}")
-
- return {}
-
def _initialize_database_options(self):
try:
return [
{
"name": name,
+ "status": info["status"],
"collections": info["collections"],
"api_endpoint": info["api_endpoint"],
+ "icon": "data",
}
for name, info in self.get_database_list().items()
]
@@ -456,7 +495,35 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
msg = f"Error fetching database options: {e}"
raise ValueError(msg) from e
+ @classmethod
+ def get_provider_icon(cls, collection: CollectionDescriptor | None = None, provider_name: str | None = None) -> str:
+ # Get the provider name from the collection
+ provider_name = provider_name or (
+ collection.options.vector.service.provider
+ if collection and collection.options and collection.options.vector and collection.options.vector.service
+ else None
+ )
+
+ # If there is no provider, use the vector store icon
+ if not provider_name or provider_name == "bring your own":
+ return "vectorstores"
+
+ # Special case for certain models
+ # TODO: Add more icons
+ if provider_name == "nvidia":
+ return "NVIDIA"
+ if provider_name == "openai":
+ return "OpenAI"
+
+ # Title case on the provider for the icon if no special case
+ return provider_name.title()
+
def _initialize_collection_options(self, api_endpoint: str | None = None):
+ # Nothing to generate if we don't have an API endpoint yet
+ api_endpoint = api_endpoint or self.get_api_endpoint()
+ if not api_endpoint:
+ return []
+
# Retrieve the database object
database = self.get_database_object(api_endpoint=api_endpoint)
@@ -471,7 +538,7 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
"provider": (
col.options.vector.service.provider if col.options.vector and col.options.vector.service else None
),
- "icon": "",
+ "icon": self.get_provider_icon(collection=col),
"model": (
col.options.vector.service.model_name if col.options.vector and col.options.vector.service else None
),
@@ -479,9 +546,53 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
for col in collection_list
]
+ def reset_provider_options(self, build_config: dict):
+ # Get the list of vectorize providers
+ vectorize_providers = self.get_vectorize_providers(
+ token=self.token,
+ environment=self.environment,
+ api_endpoint=build_config["api_endpoint"]["value"],
+ )
+
+ # If the collection is set, allow user to see embedding options
+ build_config["collection_name"]["dialog_inputs"]["fields"]["data"]["node"]["template"][
+ "embedding_generation_provider"
+ ]["options"] = ["Bring your own", "Nvidia", *[key for key in vectorize_providers if key != "Nvidia"]]
+
+ # For all not Bring your own or Nvidia providers, add metadata saying configure in Astra DB Portal
+ provider_options = build_config["collection_name"]["dialog_inputs"]["fields"]["data"]["node"]["template"][
+ "embedding_generation_provider"
+ ]["options"]
+
+ # Go over each possible provider and add metadata to configure in Astra DB Portal
+ for provider in provider_options:
+ # Skip Bring your own and Nvidia, automatically configured
+ if provider in ["Bring your own", "Nvidia"]:
+ build_config["collection_name"]["dialog_inputs"]["fields"]["data"]["node"]["template"][
+ "embedding_generation_provider"
+ ]["options_metadata"].append({"icon": self.get_provider_icon(provider_name=provider.lower())})
+ continue
+
+ # Add metadata to configure in Astra DB Portal
+ build_config["collection_name"]["dialog_inputs"]["fields"]["data"]["node"]["template"][
+ "embedding_generation_provider"
+ ]["options_metadata"].append({" ": "Configure in Astra DB Portal"})
+
+ # And allow the user to see the models based on a selected provider
+ embedding_provider = build_config["collection_name"]["dialog_inputs"]["fields"]["data"]["node"]["template"][
+ "embedding_generation_provider"
+ ]["value"]
+
+ # Set the options for the embedding model based on the provider
+ build_config["collection_name"]["dialog_inputs"]["fields"]["data"]["node"]["template"][
+ "embedding_generation_model"
+ ]["options"] = vectorize_providers.get(embedding_provider, [[], []])[1]
+
+ return build_config
+
def reset_collection_list(self, build_config: dict):
# Get the list of options we have based on the token provided
- collection_options = self._initialize_collection_options()
+ collection_options = self._initialize_collection_options(api_endpoint=build_config["api_endpoint"]["value"])
# If we retrieved options based on the token, show the dropdown
build_config["collection_name"]["options"] = [col["name"] for col in collection_options]
@@ -490,7 +601,11 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
]
# Reset the selected collection
- build_config["collection_name"]["value"] = ""
+ if build_config["collection_name"]["value"] not in build_config["collection_name"]["options"]:
+ build_config["collection_name"]["value"] = ""
+
+ # If we have a database, collection name should not be advanced
+ build_config["collection_name"]["advanced"] = not build_config["database_name"]["value"]
return build_config
@@ -499,84 +614,171 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
database_options = self._initialize_database_options()
# If we retrieved options based on the token, show the dropdown
- build_config["api_endpoint"]["options"] = [db["name"] for db in database_options]
- build_config["api_endpoint"]["options_metadata"] = [
+ build_config["database_name"]["options"] = [db["name"] for db in database_options]
+ build_config["database_name"]["options_metadata"] = [
{k: v for k, v in db.items() if k not in ["name"]} for db in database_options
]
# Reset the selected database
- build_config["api_endpoint"]["value"] = ""
+ if build_config["database_name"]["value"] not in build_config["database_name"]["options"]:
+ build_config["database_name"]["value"] = ""
+ build_config["api_endpoint"]["value"] = ""
+ build_config["collection_name"]["advanced"] = True
+
+ # If we have a token, database name should not be advanced
+ build_config["database_name"]["advanced"] = not build_config["token"]["value"]
return build_config
def reset_build_config(self, build_config: dict):
# Reset the list of databases we have based on the token provided
- build_config["api_endpoint"]["options"] = []
- build_config["api_endpoint"]["options_metadata"] = []
+ build_config["database_name"]["options"] = []
+ build_config["database_name"]["options_metadata"] = []
+ build_config["database_name"]["value"] = ""
+ build_config["database_name"]["advanced"] = True
build_config["api_endpoint"]["value"] = ""
- build_config["api_endpoint"]["name"] = "Database"
# Reset the list of collections and metadata associated
build_config["collection_name"]["options"] = []
build_config["collection_name"]["options_metadata"] = []
build_config["collection_name"]["value"] = ""
+ build_config["collection_name"]["advanced"] = True
return build_config
- def update_build_config(self, build_config: dict, field_value: str, field_name: str | None = None):
- # When the component first executes, this is the update refresh call
- first_run = field_name == "collection_name" and not field_value and not build_config["api_endpoint"]["options"]
+ async def update_build_config(self, build_config: dict, field_value: str, field_name: str | None = None):
+ # Callback for database creation
+ if field_name == "database_name" and isinstance(field_value, dict) and "new_database_name" in field_value:
+ try:
+ await self.create_database_api(
+ new_database_name=field_value["new_database_name"],
+ token=self.token,
+ keyspace=self.get_keyspace(),
+ environment=self.environment,
+ cloud_provider=field_value["cloud_provider"],
+ region=field_value["region"],
+ )
+ except Exception as e:
+ msg = f"Error creating database: {e}"
+ raise ValueError(msg) from e
- # If the token has not been provided, simply return
+ # Add the new database to the list of options
+ build_config["database_name"]["options"] = build_config["database_name"]["options"] + [
+ field_value["new_database_name"]
+ ]
+ build_config["database_name"]["options_metadata"] = build_config["database_name"]["options_metadata"] + [
+ {"status": "PENDING"}
+ ]
+
+ return self.reset_collection_list(build_config)
+
+ # This is the callback required to update the list of regions for a cloud provider
+ if field_name == "database_name" and isinstance(field_value, dict) and "new_database_name" not in field_value:
+ cloud_provider = field_value["cloud_provider"]
+ build_config["database_name"]["dialog_inputs"]["fields"]["data"]["node"]["template"]["region"][
+ "options"
+ ] = self.map_cloud_providers()[cloud_provider]["regions"]
+
+ return build_config
+
+ # Callback for the creation of collections
+ if field_name == "collection_name" and isinstance(field_value, dict) and "new_collection_name" in field_value:
+ try:
+ # Get the dimension if its a BYO provider
+ dimension = (
+ field_value["dimension"]
+ if field_value["embedding_generation_provider"] == "Bring your own"
+ else None
+ )
+
+ # Create the collection
+ await self.create_collection_api(
+ new_collection_name=field_value["new_collection_name"],
+ token=self.token,
+ api_endpoint=build_config["api_endpoint"]["value"],
+ environment=self.environment,
+ keyspace=self.get_keyspace(),
+ dimension=dimension,
+ embedding_generation_provider=field_value["embedding_generation_provider"],
+ embedding_generation_model=field_value["embedding_generation_model"],
+ )
+ except Exception as e:
+ msg = f"Error creating collection: {e}"
+ raise ValueError(msg) from e
+
+ # Add the new collection to the list of options
+ build_config["collection_name"]["value"] = field_value["new_collection_name"]
+ build_config["collection_name"]["options"].append(field_value["new_collection_name"])
+
+ # Get the provider and model for the new collection
+ generation_provider = field_value["embedding_generation_provider"]
+ provider = generation_provider if generation_provider != "Bring your own" else None
+ generation_model = field_value["embedding_generation_model"]
+ model = generation_model if generation_model else None
+
+ # Add the new collection to the list of options
+ icon = "NVIDIA" if provider == "Nvidia" else "vectorstores"
+ build_config["collection_name"]["options_metadata"] = build_config["collection_name"][
+ "options_metadata"
+ ] + [{"records": 0, "provider": provider, "icon": icon, "model": model}]
+
+ return build_config
+
+ # Callback to update the model list based on the embedding provider
+ if (
+ field_name == "collection_name"
+ and isinstance(field_value, dict)
+ and "new_collection_name" not in field_value
+ ):
+ return self.reset_provider_options(build_config)
+
+ # When the component first executes, this is the update refresh call
+ first_run = field_name == "collection_name" and not field_value and not build_config["database_name"]["options"]
+
+ # If the token has not been provided, simply return the empty build config
if not self.token:
return self.reset_build_config(build_config)
# If this is the first execution of the component, reset and build database list
if first_run or field_name in ["token", "environment"]:
- # Reset the build config to ensure we are starting fresh
- build_config = self.reset_build_config(build_config)
- build_config = self.reset_database_list(build_config)
-
- # Get list of regions for a given cloud provider
- """
- cloud_provider = (
- build_config["api_endpoint"]["dialog_inputs"]["fields"]["data"]["node"]["template"]["cloud_provider"][
- "value"
- ]
- or "Amazon Web Services"
- )
- build_config["api_endpoint"]["dialog_inputs"]["fields"]["data"]["node"]["template"]["region"][
- "options"
- ] = self.map_cloud_providers()[cloud_provider]["regions"]
- """
-
- return build_config
+ return self.reset_database_list(build_config)
# Refresh the collection name options
- if field_name == "api_endpoint":
+ if field_name == "database_name" and not isinstance(field_value, dict):
# If missing, refresh the database options
- if not build_config["api_endpoint"]["options"] or not field_value:
- return self.update_build_config(build_config, field_value=self.token, field_name="token")
+ if field_value not in build_config["database_name"]["options"]:
+ build_config = await self.update_build_config(build_config, field_value=self.token, field_name="token")
+ build_config["database_name"]["value"] = ""
+ else:
+ # Find the position of the selected database to align with metadata
+ index_of_name = build_config["database_name"]["options"].index(field_value)
- # Set the underlying api endpoint value of the database
- if field_value in build_config["api_endpoint"]["options"]:
- index_of_name = build_config["api_endpoint"]["options"].index(field_value)
- build_config["d_api_endpoint"]["value"] = build_config["api_endpoint"]["options_metadata"][
+ # Initializing database condition
+ pending = build_config["database_name"]["options_metadata"][index_of_name]["status"] == "PENDING"
+ if pending:
+ return self.update_build_config(build_config, field_value=self.token, field_name="token")
+
+ # Set the API endpoint based on the selected database
+ build_config["api_endpoint"]["value"] = build_config["database_name"]["options_metadata"][
index_of_name
]["api_endpoint"]
- else:
- build_config["d_api_endpoint"]["value"] = ""
+
+ # Reset the provider options
+ build_config = self.reset_provider_options(build_config)
# Reset the list of collections we have based on the token provided
return self.reset_collection_list(build_config)
# Hide embedding model option if opriona_metadata provider is not null
- if field_name == "collection_name" and field_value:
+ if field_name == "collection_name" and not isinstance(field_value, dict):
# Assume we will be autodetecting the collection:
build_config["autodetect_collection"]["value"] = True
+ # Reload the collection list
+ build_config = self.reset_collection_list(build_config)
+
# Set the options for collection name to be the field value if its a new collection
- if field_value not in build_config["collection_name"]["options"]:
+ if field_value and field_value not in build_config["collection_name"]["options"]:
# Add the new collection to the list of options
build_config["collection_name"]["options"].append(field_value)
build_config["collection_name"]["options_metadata"].append(
@@ -598,36 +800,8 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
build_config["embedding_model"]["advanced"] = False
build_config["embedding_choice"]["value"] = "Embedding Model"
- # For the final step, get the list of vectorize providers
- """
- vectorize_providers = self.get_vectorize_providers()
- if not vectorize_providers:
return build_config
- # Allow the user to see the embedding provider options
- provider_options = build_config["collection_name"]["dialog_inputs"]["fields"]["data"]["node"]["template"][
- "embedding_generation_provider"
- ]["options"]
- if not provider_options:
- # If the collection is set, allow user to see embedding options
- build_config["collection_name"]["dialog_inputs"]["fields"]["data"]["node"]["template"][
- "embedding_generation_provider"
- ]["options"] = ["Bring your own", "Nvidia", *[key for key in vectorize_providers if key != "Nvidia"]]
-
- # And allow the user to see the models based on a selected provider
- model_options = build_config["collection_name"]["dialog_inputs"]["fields"]["data"]["node"]["template"][
- "embedding_generation_model"
- ]["options"]
- if not model_options:
- embedding_provider = build_config["collection_name"]["dialog_inputs"]["fields"]["data"]["node"]["template"][
- "embedding_generation_provider"
- ]["value"]
-
- build_config["collection_name"]["dialog_inputs"]["fields"]["data"]["node"]["template"][
- "embedding_generation_model"
- ]["options"] = vectorize_providers.get(embedding_provider, [[], []])[1]
- """
-
return build_config
@check_cached_vector_store
@@ -654,11 +828,11 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
# Get Langflow version and platform information
__version__ = get_version_info()["version"]
langflow_prefix = ""
- if os.getenv("AWS_EXECUTION_ENV") == "AWS_ECS_FARGATE": # TODO: More precise way of detecting
- langflow_prefix = "ds-"
+ # if os.getenv("AWS_EXECUTION_ENV") == "AWS_ECS_FARGATE": # TODO: More precise way of detecting
+ # langflow_prefix = "ds-"
# Get the database object
- database = self.get_database_object(api_endpoint=self.d_api_endpoint)
+ database = self.get_database_object()
autodetect = self.collection_name in database.list_collection_names() and self.autodetect_collection
# Bundle up the auto-detect parameters
@@ -714,7 +888,7 @@ class AstraDBVectorStoreComponent(LCVectorStoreComponent):
if documents and self.deletion_field:
self.log(f"Deleting documents where {self.deletion_field}")
try:
- database = self.get_database_object(api_endpoint=self.d_api_endpoint)
+ database = self.get_database_object()
collection = database.get_collection(self.collection_name, keyspace=database.keyspace)
delete_values = list({doc.metadata[self.deletion_field] for doc in documents})
self.log(f"Deleting documents where {self.deletion_field} matches {delete_values}.")
diff --git a/src/backend/base/langflow/custom/custom_component/component.py b/src/backend/base/langflow/custom/custom_component/component.py
index 1c502eaea8..44e7a3ef2c 100644
--- a/src/backend/base/langflow/custom/custom_component/component.py
+++ b/src/backend/base/langflow/custom/custom_component/component.py
@@ -981,9 +981,6 @@ class Component(CustomComponent):
return {"repr": custom_repr, "raw": raw, "type": artifact_type}
def _process_raw_result(self, result):
- """Process the raw result of the component."""
- if len(self.outputs) == 1:
- return self.status or self.extract_data(result)
return self.extract_data(result)
def extract_data(self, result):
diff --git a/src/backend/base/langflow/events/event_manager.py b/src/backend/base/langflow/events/event_manager.py
index 9ae4e91728..e499030d93 100644
--- a/src/backend/base/langflow/events/event_manager.py
+++ b/src/backend/base/langflow/events/event_manager.py
@@ -1,21 +1,26 @@
-import asyncio
+from __future__ import annotations
+
import inspect
import json
import time
import uuid
from functools import partial
-from typing import Literal
+from typing import TYPE_CHECKING, Literal
from fastapi.encoders import jsonable_encoder
from loguru import logger
from typing_extensions import Protocol
-from langflow.schema.log import LoggableType
from langflow.schema.playground_events import create_event_by_type
+if TYPE_CHECKING:
+ import asyncio
+
+ from langflow.schema.log import LoggableType
+
class EventCallback(Protocol):
- def __call__(self, *, manager: "EventManager", event_type: str, data: LoggableType): ...
+ def __call__(self, *, manager: EventManager, event_type: str, data: LoggableType): ...
class PartialEventCallback(Protocol):
diff --git a/src/backend/base/langflow/graph/graph/base.py b/src/backend/base/langflow/graph/graph/base.py
index 557f0d373f..6a6a4b4220 100644
--- a/src/backend/base/langflow/graph/graph/base.py
+++ b/src/backend/base/langflow/graph/graph/base.py
@@ -635,6 +635,15 @@ class Graph:
raise ValueError(msg)
return self._run_id
+ def set_tracing_session_id(self) -> None:
+ """Sets the ID of the current session.
+
+ Args:
+ session_id (str): The session ID.
+ """
+ if self.tracing_service:
+ self.tracing_service.set_session_id(self._session_id)
+
def set_run_id(self, run_id: uuid.UUID | None = None) -> None:
"""Sets the ID of the current run.
@@ -647,6 +656,8 @@ class Graph:
self._run_id = str(run_id)
if self.tracing_service:
self.tracing_service.set_run_id(run_id)
+ if self._session_id and self.tracing_service is not None:
+ self.tracing_service.set_session_id(self.session_id)
def set_run_name(self) -> None:
# Given a flow name, flow_id
diff --git a/src/backend/base/langflow/graph/utils.py b/src/backend/base/langflow/graph/utils.py
index e75e4f7b17..47ef56dcef 100644
--- a/src/backend/base/langflow/graph/utils.py
+++ b/src/backend/base/langflow/graph/utils.py
@@ -135,10 +135,12 @@ async def log_transaction(
flow_id=flow_id if isinstance(flow_id, UUID) else UUID(flow_id),
)
async with session_getter(get_db_service()) as session:
- inserted = await crud_log_transaction(session, transaction)
- logger.debug(f"Logged transaction: {inserted.id}")
+ with session.no_autoflush:
+ inserted = await crud_log_transaction(session, transaction)
+ if inserted:
+ logger.debug(f"Logged transaction: {inserted.id}")
except Exception: # noqa: BLE001
- logger.exception("Error logging transaction")
+ logger.error("Error logging transaction")
async def log_vertex_build(
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting.json b/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting.json
index 092985a91a..c8a810d89b 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting.json
@@ -8,16 +8,12 @@
"dataType": "ChatInput",
"id": "ChatInput-jFwUm",
"name": "message",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "OpenAIModel-OcXkl",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -34,16 +30,12 @@
"dataType": "Prompt",
"id": "Prompt-3SM2g",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "system_message",
"id": "OpenAIModel-OcXkl",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -60,16 +52,12 @@
"dataType": "OpenAIModel",
"id": "OpenAIModel-OcXkl",
"name": "text_output",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "ChatOutput-gDYiJ",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -87,9 +75,7 @@
"display_name": "Chat Input",
"id": "ChatInput-jFwUm",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -120,9 +106,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -135,9 +119,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -156,9 +138,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -255,10 +235,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -272,9 +249,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -292,9 +267,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -329,9 +302,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -373,9 +344,7 @@
"display_name": "Prompt",
"id": "Prompt-3SM2g",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
@@ -385,9 +354,7 @@
"display_name": "Prompt",
"documentation": "",
"edited": false,
- "field_order": [
- "template"
- ],
+ "field_order": ["template"],
"frozen": false,
"icon": "prompts",
"legacy": false,
@@ -402,9 +369,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -453,9 +418,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -570,9 +533,7 @@
"data": {
"id": "ChatOutput-gDYiJ",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -605,9 +566,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -620,9 +579,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -642,9 +599,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -682,9 +637,7 @@
"display_name": "Data Template",
"dynamic": false,
"info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "data_template",
@@ -704,9 +657,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Message to be passed as output.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -727,10 +678,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -746,9 +694,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -768,9 +714,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -806,9 +750,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -850,10 +792,7 @@
"data": {
"id": "OpenAIModel-OcXkl",
"node": {
- "base_classes": [
- "LanguageModel",
- "Message"
- ],
+ "base_classes": ["LanguageModel", "Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -892,9 +831,7 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -903,14 +840,10 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
- "required_inputs": [
- "api_key"
- ],
+ "required_inputs": ["api_key"],
"selected": "LanguageModel",
"tool_mode": true,
- "types": [
- "LanguageModel"
- ],
+ "types": ["LanguageModel"],
"value": "__UNDEFINED__"
}
],
@@ -923,10 +856,8 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
- "load_from_db": false,
+ "input_types": ["Message"],
+ "load_from_db": true,
"name": "api_key",
"password": true,
"placeholder": "",
@@ -934,7 +865,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"code": {
"advanced": true,
@@ -960,9 +891,7 @@
"display_name": "Input",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1144,9 +1073,7 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1243,7 +1170,5 @@
"is_component": false,
"last_tested_version": "1.0.19.post2",
"name": "Basic Prompting",
- "tags": [
- "chatbots"
- ]
-}
\ No newline at end of file
+ "tags": ["chatbots"]
+}
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json b/src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json
index 94e4cf5bed..c84d6013fd 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json
@@ -9,17 +9,12 @@
"dataType": "ParseData",
"id": "ParseData-4Sckw",
"name": "text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "references",
"id": "Prompt-65R68",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
@@ -37,17 +32,12 @@
"dataType": "TextInput",
"id": "TextInput-t88FI",
"name": "text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "instructions",
"id": "Prompt-65R68",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
@@ -64,16 +54,12 @@
"dataType": "Prompt",
"id": "Prompt-65R68",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "OpenAIModel-MyAsQ",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -90,16 +76,12 @@
"dataType": "OpenAIModel",
"id": "OpenAIModel-MyAsQ",
"name": "text_output",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "ChatOutput-BE4YI",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -116,16 +98,12 @@
"dataType": "URL",
"id": "URL-EPEnt",
"name": "data",
- "output_types": [
- "Data"
- ]
+ "output_types": ["Data"]
},
"targetHandle": {
"fieldName": "data",
"id": "ParseData-4Sckw",
- "inputTypes": [
- "Data"
- ],
+ "inputTypes": ["Data"],
"type": "other"
}
},
@@ -143,9 +121,7 @@
"display_name": "Parse Data",
"id": "ParseData-4Sckw",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -153,16 +129,14 @@
"display_name": "Parse Data",
"documentation": "",
"edited": false,
- "field_order": [
- "data",
- "template",
- "sep"
- ],
+ "field_order": ["data", "template", "sep"],
"frozen": false,
"icon": "message-square",
"legacy": false,
"lf_version": "1.0.19.post2",
- "metadata": {},
+ "metadata": {
+ "legacy_name": "Parse Data"
+ },
"output_types": [],
"outputs": [
{
@@ -173,9 +147,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -186,9 +158,7 @@
"name": "data_list",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -211,16 +181,14 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\", is_list=True, required=True),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
+ "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n metadata = {\n \"legacy_name\": \"Parse Data\",\n }\n\n inputs = [\n DataInput(\n name=\"data\",\n display_name=\"Data\",\n info=\"The data to convert to text.\",\n is_list=True,\n required=True,\n ),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
},
"data": {
"advanced": false,
"display_name": "Data",
"dynamic": false,
"info": "The data to convert to text.",
- "input_types": [
- "Data"
- ],
+ "input_types": ["Data"],
"list": true,
"name": "data",
"placeholder": "",
@@ -253,9 +221,7 @@
"display_name": "Template",
"dynamic": false,
"info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -298,24 +264,17 @@
"display_name": "Prompt",
"id": "Prompt-65R68",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
- "template": [
- "references",
- "instructions"
- ]
+ "template": ["references", "instructions"]
},
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
"documentation": "",
"edited": false,
- "field_order": [
- "template"
- ],
+ "field_order": ["template"],
"frozen": false,
"icon": "prompts",
"legacy": false,
@@ -331,9 +290,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -366,10 +323,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -390,10 +344,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -428,9 +379,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -473,9 +422,7 @@
"display_name": "Instructions",
"id": "TextInput-t88FI",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -483,9 +430,7 @@
"display_name": "Instructions",
"documentation": "",
"edited": false,
- "field_order": [
- "input_value"
- ],
+ "field_order": ["input_value"],
"frozen": false,
"icon": "type",
"legacy": false,
@@ -501,9 +446,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -534,9 +477,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Text to be passed as input.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -579,9 +520,7 @@
"display_name": "Chat Output",
"id": "ChatOutput-BE4YI",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -612,9 +551,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -627,9 +564,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -648,9 +583,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -686,9 +619,7 @@
"display_name": "Data Template",
"dynamic": false,
"info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "data_template",
@@ -706,9 +637,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Message to be passed as output.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -727,10 +656,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -744,9 +670,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -764,9 +688,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -801,9 +723,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -952,10 +872,7 @@
"data": {
"id": "OpenAIModel-MyAsQ",
"node": {
- "base_classes": [
- "LanguageModel",
- "Message"
- ],
+ "base_classes": ["LanguageModel", "Message"],
"beta": false,
"category": "models",
"conditional_paths": [],
@@ -994,9 +911,7 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -1005,14 +920,10 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
- "required_inputs": [
- "api_key"
- ],
+ "required_inputs": ["api_key"],
"selected": "LanguageModel",
"tool_mode": true,
- "types": [
- "LanguageModel"
- ],
+ "types": ["LanguageModel"],
"value": "__UNDEFINED__"
}
],
@@ -1026,9 +937,7 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -1037,7 +946,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"code": {
"advanced": true,
@@ -1063,9 +972,7 @@
"display_name": "Input",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1247,9 +1154,7 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1334,11 +1239,7 @@
"data": {
"id": "URL-EPEnt",
"node": {
- "base_classes": [
- "Data",
- "DataFrame",
- "Message"
- ],
+ "base_classes": ["Data", "DataFrame", "Message"],
"beta": false,
"category": "data",
"conditional_paths": [],
@@ -1347,10 +1248,7 @@
"display_name": "URL",
"documentation": "",
"edited": false,
- "field_order": [
- "urls",
- "format"
- ],
+ "field_order": ["urls", "format"],
"frozen": false,
"icon": "layout-template",
"key": "URL",
@@ -1367,9 +1265,7 @@
"name": "data",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
},
{
@@ -1380,9 +1276,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -1393,9 +1287,7 @@
"name": "dataframe",
"selected": "DataFrame",
"tool_mode": true,
- "types": [
- "DataFrame"
- ],
+ "types": ["DataFrame"],
"value": "__UNDEFINED__"
}
],
@@ -1430,10 +1322,7 @@
"dynamic": false,
"info": "Output Format. Use 'Text' to extract the text from the HTML or 'Raw HTML' for the raw HTML content.",
"name": "format",
- "options": [
- "Text",
- "Raw HTML"
- ],
+ "options": ["Text", "Raw HTML"],
"options_metadata": [],
"placeholder": "",
"required": false,
@@ -1450,9 +1339,7 @@
"display_name": "URLs",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": true,
"list_add_label": "Add URL",
"load_from_db": false,
@@ -1465,10 +1352,7 @@
"trace_as_input": true,
"trace_as_metadata": true,
"type": "str",
- "value": [
- "https://langflow.org/",
- "https://docs.langflow.org/"
- ]
+ "value": ["https://langflow.org/", "https://docs.langflow.org/"]
}
},
"tool_mode": false
@@ -1504,8 +1388,5 @@
"is_component": false,
"last_tested_version": "1.0.19.post2",
"name": "Blog Writer",
- "tags": [
- "chatbots",
- "content-generation"
- ]
-}
\ No newline at end of file
+ "tags": ["chatbots", "content-generation"]
+}
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Custom Component Maker.json b/src/backend/base/langflow/initial_setup/starter_projects/Custom Component Maker.json
index aca4871b04..a5259b58e3 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Custom Component Maker.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Custom Component Maker.json
@@ -204,9 +204,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -490,9 +488,7 @@
"name": "messages",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
},
{
@@ -503,9 +499,7 @@
"name": "messages_text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -722,9 +716,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -950,9 +942,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1267,9 +1257,7 @@
"name": "data",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
},
{
@@ -1280,9 +1268,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -1293,9 +1279,7 @@
"name": "dataframe",
"selected": "DataFrame",
"tool_mode": true,
- "types": [
- "DataFrame"
- ],
+ "types": ["DataFrame"],
"value": "__UNDEFINED__"
}
],
@@ -1412,9 +1396,7 @@
"name": "data",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
},
{
@@ -1425,9 +1407,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -1438,9 +1418,7 @@
"name": "dataframe",
"selected": "DataFrame",
"tool_mode": true,
- "types": [
- "DataFrame"
- ],
+ "types": ["DataFrame"],
"value": "__UNDEFINED__"
}
],
@@ -1563,9 +1541,7 @@
"name": "data",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
},
{
@@ -1576,9 +1552,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -1589,9 +1563,7 @@
"name": "dataframe",
"selected": "DataFrame",
"tool_mode": true,
- "types": [
- "DataFrame"
- ],
+ "types": ["DataFrame"],
"value": "__UNDEFINED__"
}
],
@@ -1722,9 +1694,7 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -1736,9 +1706,7 @@
"required_inputs": ["api_key"],
"selected": "LanguageModel",
"tool_mode": true,
- "types": [
- "LanguageModel"
- ],
+ "types": ["LanguageModel"],
"value": "__UNDEFINED__"
}
],
@@ -1753,7 +1721,7 @@
"dynamic": false,
"info": "Your Anthropic API key.",
"input_types": ["Message"],
- "load_from_db": false,
+ "load_from_db": true,
"name": "api_key",
"password": true,
"placeholder": "",
@@ -1762,7 +1730,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "ANTHROPIC_API_KEY"
},
"base_url": {
"_input_type": "MessageTextInput",
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Document Q&A.json b/src/backend/base/langflow/initial_setup/starter_projects/Document Q&A.json
index 708d5c9aca..17a41abdde 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Document Q&A.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Document Q&A.json
@@ -8,16 +8,12 @@
"dataType": "File",
"id": "File-GwJQZ",
"name": "data",
- "output_types": [
- "Data"
- ]
+ "output_types": ["Data"]
},
"targetHandle": {
"fieldName": "data",
"id": "ParseData-BbvKb",
- "inputTypes": [
- "Data"
- ],
+ "inputTypes": ["Data"],
"type": "other"
}
},
@@ -35,17 +31,12 @@
"dataType": "ParseData",
"id": "ParseData-BbvKb",
"name": "text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "Document",
"id": "Prompt-yvZHT",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
@@ -63,16 +54,12 @@
"dataType": "ChatInput",
"id": "ChatInput-li477",
"name": "message",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "OpenAIModel-atkmo",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -90,16 +77,12 @@
"dataType": "Prompt",
"id": "Prompt-yvZHT",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "system_message",
"id": "OpenAIModel-atkmo",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -117,16 +100,12 @@
"dataType": "OpenAIModel",
"id": "OpenAIModel-atkmo",
"name": "text_output",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "ChatOutput-8pgwS",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -145,9 +124,7 @@
"display_name": "Chat Input",
"id": "ChatInput-li477",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -178,9 +155,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -193,9 +168,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -214,9 +187,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -313,10 +284,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -330,9 +298,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -350,9 +316,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -387,9 +351,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -431,9 +393,7 @@
"display_name": "Chat Output",
"id": "ChatOutput-8pgwS",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -467,9 +427,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -482,9 +440,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -504,9 +460,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -544,9 +498,7 @@
"display_name": "Data Template",
"dynamic": false,
"info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "data_template",
@@ -566,9 +518,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Message to be passed as output.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -589,10 +539,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -608,9 +555,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -630,9 +575,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -668,9 +611,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -714,9 +655,7 @@
"display_name": "Parse Data",
"id": "ParseData-BbvKb",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -724,16 +663,14 @@
"display_name": "Parse Data",
"documentation": "",
"edited": false,
- "field_order": [
- "data",
- "template",
- "sep"
- ],
+ "field_order": ["data", "template", "sep"],
"frozen": false,
"icon": "message-square",
"legacy": false,
"lf_version": "1.0.19.post2",
- "metadata": {},
+ "metadata": {
+ "legacy_name": "Parse Data"
+ },
"output_types": [],
"outputs": [
{
@@ -744,9 +681,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -757,9 +692,7 @@
"name": "data_list",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -782,16 +715,14 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\", is_list=True, required=True),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
+ "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n metadata = {\n \"legacy_name\": \"Parse Data\",\n }\n\n inputs = [\n DataInput(\n name=\"data\",\n display_name=\"Data\",\n info=\"The data to convert to text.\",\n is_list=True,\n required=True,\n ),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
},
"data": {
"advanced": false,
"display_name": "Data",
"dynamic": false,
"info": "The data to convert to text.",
- "input_types": [
- "Data"
- ],
+ "input_types": ["Data"],
"list": true,
"name": "data",
"placeholder": "",
@@ -824,9 +755,7 @@
"display_name": "Template",
"dynamic": false,
"info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -934,9 +863,7 @@
"data": {
"id": "File-GwJQZ",
"node": {
- "base_classes": [
- "Data"
- ],
+ "base_classes": ["Data"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -965,9 +892,7 @@
"required_inputs": [],
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -1030,10 +955,7 @@
"display_name": "Server File Path",
"dynamic": false,
"info": "Data object with a 'file_path' property pointing to server file or a Message object with a path to the file. Supercedes 'Path' but supports same file types.",
- "input_types": [
- "Data",
- "Message"
- ],
+ "input_types": ["Data", "Message"],
"list": true,
"name": "file_path",
"placeholder": "",
@@ -1180,24 +1102,18 @@
"display_name": "Prompt",
"id": "Prompt-yvZHT",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
- "template": [
- "Document"
- ]
+ "template": ["Document"]
},
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
"documentation": "",
"edited": false,
"error": null,
- "field_order": [
- "template"
- ],
+ "field_order": ["template"],
"frozen": false,
"full_path": null,
"icon": "prompts",
@@ -1218,9 +1134,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1234,10 +1148,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1290,9 +1201,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -1334,10 +1243,7 @@
"data": {
"id": "OpenAIModel-atkmo",
"node": {
- "base_classes": [
- "LanguageModel",
- "Message"
- ],
+ "base_classes": ["LanguageModel", "Message"],
"beta": false,
"category": "models",
"conditional_paths": [],
@@ -1376,9 +1282,7 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -1387,14 +1291,10 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
- "required_inputs": [
- "api_key"
- ],
+ "required_inputs": ["api_key"],
"selected": "LanguageModel",
"tool_mode": true,
- "types": [
- "LanguageModel"
- ],
+ "types": ["LanguageModel"],
"value": "__UNDEFINED__"
}
],
@@ -1408,9 +1308,7 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -1419,7 +1317,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"code": {
"advanced": true,
@@ -1445,9 +1343,7 @@
"display_name": "Input",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1629,9 +1525,7 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1727,9 +1621,5 @@
"is_component": false,
"last_tested_version": "1.0.19.post2",
"name": "Document Q&A",
- "tags": [
- "rag",
- "q-a",
- "openai"
- ]
-}
\ No newline at end of file
+ "tags": ["rag", "q-a", "openai"]
+}
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Financial Report Parser.json b/src/backend/base/langflow/initial_setup/starter_projects/Financial Report Parser.json
new file mode 100644
index 0000000000..2c281e27a3
--- /dev/null
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Financial Report Parser.json
@@ -0,0 +1,1773 @@
+{
+ "data": {
+ "edges": [
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "Prompt",
+ "id": "Prompt-BfPBI",
+ "name": "prompt",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "input_value",
+ "id": "StructuredOutput-gauqw",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "reactflow__edge-Prompt-BfPBI{œdataTypeœ:œPromptœ,œidœ:œPrompt-BfPBIœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-StructuredOutput-gauqw{œfieldNameœ:œinput_valueœ,œidœ:œStructuredOutput-gauqwœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "Prompt-BfPBI",
+ "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-BfPBIœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "StructuredOutput-gauqw",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œStructuredOutput-gauqwœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "OpenAIModel",
+ "id": "OpenAIModel-9iAH4",
+ "name": "model_output",
+ "output_types": [
+ "LanguageModel"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "llm",
+ "id": "StructuredOutput-gauqw",
+ "inputTypes": [
+ "LanguageModel"
+ ],
+ "type": "other"
+ }
+ },
+ "id": "reactflow__edge-OpenAIModel-9iAH4{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-9iAH4œ,œnameœ:œmodel_outputœ,œoutput_typesœ:[œLanguageModelœ]}-StructuredOutput-gauqw{œfieldNameœ:œllmœ,œidœ:œStructuredOutput-gauqwœ,œinputTypesœ:[œLanguageModelœ],œtypeœ:œotherœ}",
+ "source": "OpenAIModel-9iAH4",
+ "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-9iAH4œ, œnameœ: œmodel_outputœ, œoutput_typesœ: [œLanguageModelœ]}",
+ "target": "StructuredOutput-gauqw",
+ "targetHandle": "{œfieldNameœ: œllmœ, œidœ: œStructuredOutput-gauqwœ, œinputTypesœ: [œLanguageModelœ], œtypeœ: œotherœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "StructuredOutput",
+ "id": "StructuredOutput-gauqw",
+ "name": "structured_output",
+ "output_types": [
+ "Data"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "data",
+ "id": "ParseData-hLbU0",
+ "inputTypes": [
+ "Data"
+ ],
+ "type": "other"
+ }
+ },
+ "id": "xy-edge__StructuredOutput-gauqw{œdataTypeœ:œStructuredOutputœ,œidœ:œStructuredOutput-gauqwœ,œnameœ:œstructured_outputœ,œoutput_typesœ:[œDataœ]}-ParseData-hLbU0{œfieldNameœ:œdataœ,œidœ:œParseData-hLbU0œ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}",
+ "source": "StructuredOutput-gauqw",
+ "sourceHandle": "{œdataTypeœ: œStructuredOutputœ, œidœ: œStructuredOutput-gauqwœ, œnameœ: œstructured_outputœ, œoutput_typesœ: [œDataœ]}",
+ "target": "ParseData-hLbU0",
+ "targetHandle": "{œfieldNameœ: œdataœ, œidœ: œParseData-hLbU0œ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "ParseData",
+ "id": "ParseData-hLbU0",
+ "name": "text",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "input_value",
+ "id": "ChatOutput-ZtLkt",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "xy-edge__ParseData-hLbU0{œdataTypeœ:œParseDataœ,œidœ:œParseData-hLbU0œ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-ZtLkt{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-ZtLktœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "ParseData-hLbU0",
+ "sourceHandle": "{œdataTypeœ: œParseDataœ, œidœ: œParseData-hLbU0œ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "ChatOutput-ZtLkt",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-ZtLktœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "ChatInput",
+ "id": "ChatInput-h90IX",
+ "name": "message",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "report_section",
+ "id": "Prompt-BfPBI",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "xy-edge__ChatInput-h90IX{œdataTypeœ:œChatInputœ,œidœ:œChatInput-h90IXœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-BfPBI{œfieldNameœ:œreport_sectionœ,œidœ:œPrompt-BfPBIœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "ChatInput-h90IX",
+ "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-h90IXœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Prompt-BfPBI",
+ "targetHandle": "{œfieldNameœ: œreport_sectionœ, œidœ: œPrompt-BfPBIœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ }
+ ],
+ "nodes": [
+ {
+ "data": {
+ "id": "Prompt-BfPBI",
+ "node": {
+ "base_classes": [
+ "Message"
+ ],
+ "beta": false,
+ "conditional_paths": [],
+ "custom_fields": {
+ "template": [
+ "report_section"
+ ]
+ },
+ "description": "Create a prompt template with dynamic variables.",
+ "display_name": "Prompt",
+ "documentation": "",
+ "edited": false,
+ "error": null,
+ "field_order": [
+ "template",
+ "tool_placeholder"
+ ],
+ "frozen": false,
+ "full_path": null,
+ "icon": "prompts",
+ "is_composition": null,
+ "is_input": null,
+ "is_output": null,
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": false,
+ "name": "",
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Prompt Message",
+ "method": "build_prompt",
+ "name": "prompt",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "template": {
+ "_type": "Component",
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import MessageTextInput, Output, PromptInput\nfrom langflow.schema.message import Message\nfrom langflow.template.utils import update_template_values\n\n\nclass PromptComponent(Component):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n MessageTextInput(\n name=\"tool_placeholder\",\n display_name=\"Tool Placeholder\",\n tool_mode=True,\n advanced=True,\n info=\"A placeholder input for tool mode.\",\n ),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(self) -> Message:\n prompt = Message.from_template(**self._attributes)\n self.status = prompt.text\n return prompt\n\n def _update_template(self, frontend_node: dict):\n prompt_template = frontend_node[\"template\"][\"template\"][\"value\"]\n custom_fields = frontend_node[\"custom_fields\"]\n frontend_node_template = frontend_node[\"template\"]\n _ = process_prompt_template(\n template=prompt_template,\n name=\"template\",\n custom_fields=custom_fields,\n frontend_node_template=frontend_node_template,\n )\n return frontend_node\n\n async def update_frontend_node(self, new_frontend_node: dict, current_frontend_node: dict):\n \"\"\"This function is called after the code validation is done.\"\"\"\n frontend_node = await super().update_frontend_node(new_frontend_node, current_frontend_node)\n template = frontend_node[\"template\"][\"template\"][\"value\"]\n # Kept it duplicated for backwards compatibility\n _ = process_prompt_template(\n template=template,\n name=\"template\",\n custom_fields=frontend_node[\"custom_fields\"],\n frontend_node_template=frontend_node[\"template\"],\n )\n # Now that template is updated, we need to grab any values that were set in the current_frontend_node\n # and update the frontend_node with those values\n update_template_values(new_template=frontend_node, previous_template=current_frontend_node[\"template\"])\n return frontend_node\n\n def _get_fallback_input(self, **kwargs):\n return DefaultPromptField(**kwargs)\n"
+ },
+ "report_section": {
+ "advanced": false,
+ "display_name": "report_section",
+ "dynamic": false,
+ "field_type": "str",
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "report_section",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "type": "str",
+ "value": ""
+ },
+ "template": {
+ "_input_type": "PromptInput",
+ "advanced": false,
+ "display_name": "Template",
+ "dynamic": false,
+ "info": "",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "template",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "type": "prompt",
+ "value": "You are an AI system that extracts financial metrics. Given the report_section, please return a JSON with keys: 'gross_profit', 'ebitda', 'net_income'. Provide values as floats in millions. If a metric is missing, set it to a default (e.g., 0).\n\nReport Section:\n{report_section}"
+ },
+ "tool_placeholder": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Tool Placeholder",
+ "dynamic": false,
+ "info": "A placeholder input for tool mode.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "tool_placeholder",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": true,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": true,
+ "type": "Prompt"
+ },
+ "dragging": false,
+ "id": "Prompt-BfPBI",
+ "measured": {
+ "height": 339,
+ "width": 320
+ },
+ "position": {
+ "x": 931.4124024526345,
+ "y": 477.38330332537384
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "StructuredOutput-gauqw",
+ "node": {
+ "base_classes": [
+ "Data"
+ ],
+ "beta": false,
+ "category": "helpers",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Transforms LLM responses into **structured data formats**. Ideal for extracting specific information or creating consistent outputs.",
+ "display_name": "Structured Output",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "llm",
+ "input_value",
+ "schema_name",
+ "output_schema",
+ "multiple"
+ ],
+ "frozen": false,
+ "icon": "braces",
+ "key": "StructuredOutput",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": false,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Structured Output",
+ "method": "build_structured_output",
+ "name": "structured_output",
+ "selected": "Data",
+ "tool_mode": true,
+ "types": [
+ "Data"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 0.007568328950209746,
+ "template": {
+ "_type": "Component",
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from typing import TYPE_CHECKING, cast\n\nfrom pydantic import BaseModel, Field, create_model\n\nfrom langflow.base.models.chat_result import get_chat_result\nfrom langflow.custom import Component\nfrom langflow.helpers.base_model import build_model_from_schema\nfrom langflow.io import BoolInput, HandleInput, MessageTextInput, Output, StrInput, TableInput\nfrom langflow.schema.data import Data\n\nif TYPE_CHECKING:\n from langflow.field_typing.constants import LanguageModel\n\n\nclass StructuredOutputComponent(Component):\n display_name = \"Structured Output\"\n description = (\n \"Transforms LLM responses into **structured data formats**. Ideal for extracting specific information \"\n \"or creating consistent outputs.\"\n )\n name = \"StructuredOutput\"\n icon = \"braces\"\n\n inputs = [\n HandleInput(\n name=\"llm\",\n display_name=\"Language Model\",\n info=\"The language model to use to generate the structured output.\",\n input_types=[\"LanguageModel\"],\n required=True,\n ),\n MessageTextInput(\n name=\"input_value\",\n display_name=\"Input Message\",\n info=\"The input message to the language model.\",\n tool_mode=True,\n required=True,\n ),\n StrInput(\n name=\"schema_name\",\n display_name=\"Schema Name\",\n info=\"Provide a name for the output data schema.\",\n advanced=True,\n ),\n TableInput(\n name=\"output_schema\",\n display_name=\"Output Schema\",\n info=\"Define the structure and data types for the model's output.\",\n required=True,\n table_schema=[\n {\n \"name\": \"name\",\n \"display_name\": \"Name\",\n \"type\": \"str\",\n \"description\": \"Specify the name of the output field.\",\n \"default\": \"field\",\n },\n {\n \"name\": \"description\",\n \"display_name\": \"Description\",\n \"type\": \"str\",\n \"description\": \"Describe the purpose of the output field.\",\n \"default\": \"description of field\",\n },\n {\n \"name\": \"type\",\n \"display_name\": \"Type\",\n \"type\": \"str\",\n \"description\": (\n \"Indicate the data type of the output field (e.g., str, int, float, bool, list, dict).\"\n ),\n \"default\": \"text\",\n },\n {\n \"name\": \"multiple\",\n \"display_name\": \"Multiple\",\n \"type\": \"boolean\",\n \"description\": \"Set to True if this output field should be a list of the specified type.\",\n \"default\": \"False\",\n },\n ],\n value=[{\"name\": \"field\", \"description\": \"description of field\", \"type\": \"text\", \"multiple\": \"False\"}],\n ),\n BoolInput(\n name=\"multiple\",\n advanced=True,\n display_name=\"Generate Multiple\",\n info=\"Set to True if the model should generate a list of outputs instead of a single output.\",\n ),\n ]\n\n outputs = [\n Output(name=\"structured_output\", display_name=\"Structured Output\", method=\"build_structured_output\"),\n ]\n\n def build_structured_output(self) -> Data:\n schema_name = self.schema_name or \"OutputModel\"\n\n if not hasattr(self.llm, \"with_structured_output\"):\n msg = \"Language model does not support structured output.\"\n raise TypeError(msg)\n if not self.output_schema:\n msg = \"Output schema cannot be empty\"\n raise ValueError(msg)\n\n output_model_ = build_model_from_schema(self.output_schema)\n if self.multiple:\n output_model = create_model(\n schema_name,\n objects=(list[output_model_], Field(description=f\"A list of {schema_name}.\")), # type: ignore[valid-type]\n )\n else:\n output_model = output_model_\n try:\n llm_with_structured_output = cast(\"LanguageModel\", self.llm).with_structured_output(schema=output_model) # type: ignore[valid-type, attr-defined]\n\n except NotImplementedError as exc:\n msg = f\"{self.llm.__class__.__name__} does not support structured output.\"\n raise TypeError(msg) from exc\n config_dict = {\n \"run_name\": self.display_name,\n \"project_name\": self.get_project_name(),\n \"callbacks\": self.get_langchain_callbacks(),\n }\n output = get_chat_result(runnable=llm_with_structured_output, input_value=self.input_value, config=config_dict)\n if isinstance(output, BaseModel):\n output_dict = output.model_dump()\n else:\n msg = f\"Output should be a Pydantic BaseModel, got {type(output)} ({output})\"\n raise TypeError(msg)\n return Data(data=output_dict)\n"
+ },
+ "input_value": {
+ "_input_type": "MessageTextInput",
+ "advanced": false,
+ "display_name": "Input Message",
+ "dynamic": false,
+ "info": "The input message to the language model.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "input_value",
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": true,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "llm": {
+ "_input_type": "HandleInput",
+ "advanced": false,
+ "display_name": "Language Model",
+ "dynamic": false,
+ "info": "The language model to use to generate the structured output.",
+ "input_types": [
+ "LanguageModel"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "llm",
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "trace_as_metadata": true,
+ "type": "other",
+ "value": ""
+ },
+ "multiple": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Generate Multiple",
+ "dynamic": false,
+ "info": "Set to True if the model should generate a list of outputs instead of a single output.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "multiple",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": false
+ },
+ "output_schema": {
+ "_input_type": "TableInput",
+ "advanced": false,
+ "display_name": "Output Schema",
+ "dynamic": false,
+ "info": "Define the structure and data types for the model's output.",
+ "is_list": true,
+ "list_add_label": "Add More",
+ "name": "output_schema",
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "table_icon": "Table",
+ "table_schema": {
+ "columns": [
+ {
+ "default": "field",
+ "description": "Specify the name of the output field.",
+ "disable_edit": false,
+ "display_name": "Name",
+ "edit_mode": "modal",
+ "filterable": true,
+ "formatter": "text",
+ "name": "name",
+ "sortable": true,
+ "type": "text"
+ },
+ {
+ "default": "description of field",
+ "description": "Describe the purpose of the output field.",
+ "disable_edit": false,
+ "display_name": "Description",
+ "edit_mode": "modal",
+ "filterable": true,
+ "formatter": "text",
+ "name": "description",
+ "sortable": true,
+ "type": "text"
+ },
+ {
+ "default": "text",
+ "description": "Indicate the data type of the output field (e.g., str, int, float, bool, list, dict).",
+ "disable_edit": false,
+ "display_name": "Type",
+ "edit_mode": "modal",
+ "filterable": true,
+ "formatter": "text",
+ "name": "type",
+ "sortable": true,
+ "type": "text"
+ },
+ {
+ "default": "False",
+ "description": "Set to True if this output field should be a list of the specified type.",
+ "disable_edit": false,
+ "display_name": "Multiple",
+ "edit_mode": "modal",
+ "filterable": true,
+ "formatter": "text",
+ "name": "multiple",
+ "sortable": true,
+ "type": "boolean"
+ }
+ ]
+ },
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "trigger_icon": "Table",
+ "trigger_text": "Open table",
+ "type": "table",
+ "value": [
+ {
+ "description": "description of field",
+ "multiple": "False",
+ "name": "EBITIDA",
+ "type": "float"
+ },
+ {
+ "description": "description of field",
+ "multiple": "False",
+ "name": "NET_INCOME",
+ "type": "float"
+ },
+ {
+ "description": "description of field",
+ "multiple": "False",
+ "name": "GROSS_PROFIT",
+ "type": "float"
+ }
+ ]
+ },
+ "schema_name": {
+ "_input_type": "StrInput",
+ "advanced": true,
+ "display_name": "Schema Name",
+ "dynamic": false,
+ "info": "Provide a name for the output data schema.",
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "schema_name",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": true,
+ "type": "StructuredOutput"
+ },
+ "id": "StructuredOutput-gauqw",
+ "measured": {
+ "height": 399,
+ "width": 320
+ },
+ "position": {
+ "x": 1375.6987904830316,
+ "y": 234.0515425962535
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "OpenAIModel-9iAH4",
+ "node": {
+ "base_classes": [
+ "LanguageModel",
+ "Message"
+ ],
+ "beta": false,
+ "category": "models",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Generates text using OpenAI LLMs.",
+ "display_name": "OpenAI",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "input_value",
+ "system_message",
+ "stream",
+ "max_tokens",
+ "model_kwargs",
+ "json_mode",
+ "model_name",
+ "openai_api_base",
+ "api_key",
+ "temperature",
+ "seed",
+ "max_retries",
+ "timeout"
+ ],
+ "frozen": false,
+ "icon": "OpenAI",
+ "key": "OpenAIModel",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": false,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Message",
+ "method": "text_response",
+ "name": "text_output",
+ "required_inputs": [],
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ },
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Language Model",
+ "method": "build_model",
+ "name": "model_output",
+ "required_inputs": [
+ "api_key"
+ ],
+ "selected": "LanguageModel",
+ "tool_mode": true,
+ "types": [
+ "LanguageModel"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 0.001,
+ "template": {
+ "_type": "Component",
+ "api_key": {
+ "_input_type": "SecretStrInput",
+ "advanced": false,
+ "display_name": "OpenAI API Key",
+ "dynamic": false,
+ "info": "The OpenAI API Key to use for the OpenAI model.",
+ "input_types": [
+ "Message"
+ ],
+ "load_from_db": true,
+ "name": "api_key",
+ "password": true,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "str",
+ "value": "OPENAI_API_KEY"
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import OPENAI_MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs import BoolInput, DictInput, DropdownInput, IntInput, SecretStrInput, SliderInput, StrInput\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n name = \"OpenAIModel\"\n\n inputs = [\n *LCModelComponent._base_inputs,\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n range_spec=RangeSpec(min=0, max=128000),\n ),\n DictInput(\n name=\"model_kwargs\",\n display_name=\"Model Kwargs\",\n advanced=True,\n info=\"Additional keyword arguments to pass to the model.\",\n ),\n BoolInput(\n name=\"json_mode\",\n display_name=\"JSON Mode\",\n advanced=True,\n info=\"If True, it will output JSON regardless of passing a schema.\",\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n advanced=False,\n options=OPENAI_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[0],\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. \"\n \"Defaults to https://api.openai.com/v1. \"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n required=True,\n ),\n SliderInput(\n name=\"temperature\", display_name=\"Temperature\", value=0.1, range_spec=RangeSpec(min=0, max=1, step=0.01)\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n IntInput(\n name=\"max_retries\",\n display_name=\"Max Retries\",\n info=\"The maximum number of retries to make when generating.\",\n advanced=True,\n value=5,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"The timeout for requests to OpenAI completion API.\",\n advanced=True,\n value=700,\n ),\n ]\n\n def build_model(self) -> LanguageModel: # type: ignore[type-var]\n openai_api_key = self.api_key\n temperature = self.temperature\n model_name: str = self.model_name\n max_tokens = self.max_tokens\n model_kwargs = self.model_kwargs or {}\n openai_api_base = self.openai_api_base or \"https://api.openai.com/v1\"\n json_mode = self.json_mode\n seed = self.seed\n max_retries = self.max_retries\n timeout = self.timeout\n\n api_key = SecretStr(openai_api_key).get_secret_value() if openai_api_key else None\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature if temperature is not None else 0.1,\n seed=seed,\n max_retries=max_retries,\n request_timeout=timeout,\n )\n if json_mode:\n output = output.bind(response_format={\"type\": \"json_object\"})\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"Get a message from an OpenAI exception.\n\n Args:\n e (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n try:\n from openai import BadRequestError\n except ImportError:\n return None\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\")\n if message:\n return message\n return None\n"
+ },
+ "input_value": {
+ "_input_type": "MessageInput",
+ "advanced": false,
+ "display_name": "Input",
+ "dynamic": false,
+ "info": "",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "input_value",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "json_mode": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "JSON Mode",
+ "dynamic": false,
+ "info": "If True, it will output JSON regardless of passing a schema.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "json_mode",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": false
+ },
+ "max_retries": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Max Retries",
+ "dynamic": false,
+ "info": "The maximum number of retries to make when generating.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "max_retries",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 5
+ },
+ "max_tokens": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Max Tokens",
+ "dynamic": false,
+ "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "max_tokens",
+ "placeholder": "",
+ "range_spec": {
+ "max": 128000,
+ "min": 0,
+ "step": 0.1,
+ "step_type": "float"
+ },
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": ""
+ },
+ "model_kwargs": {
+ "_input_type": "DictInput",
+ "advanced": true,
+ "display_name": "Model Kwargs",
+ "dynamic": false,
+ "info": "Additional keyword arguments to pass to the model.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "model_kwargs",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "type": "dict",
+ "value": {}
+ },
+ "model_name": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Model Name",
+ "dynamic": false,
+ "info": "",
+ "name": "model_name",
+ "options": [
+ "gpt-4o-mini",
+ "gpt-4o",
+ "gpt-4-turbo",
+ "gpt-4-turbo-preview",
+ "gpt-4",
+ "gpt-3.5-turbo",
+ "gpt-3.5-turbo-0125"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "gpt-4o-mini"
+ },
+ "openai_api_base": {
+ "_input_type": "StrInput",
+ "advanced": true,
+ "display_name": "OpenAI API Base",
+ "dynamic": false,
+ "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.",
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "openai_api_base",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "seed": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Seed",
+ "dynamic": false,
+ "info": "The seed controls the reproducibility of the job.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "seed",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 1
+ },
+ "stream": {
+ "_input_type": "BoolInput",
+ "advanced": false,
+ "display_name": "Stream",
+ "dynamic": false,
+ "info": "Stream the response from the model. Streaming works only in Chat.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "stream",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": false
+ },
+ "system_message": {
+ "_input_type": "MultilineInput",
+ "advanced": false,
+ "display_name": "System Message",
+ "dynamic": false,
+ "info": "System message to pass to the model.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "system_message",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "temperature": {
+ "_input_type": "SliderInput",
+ "advanced": false,
+ "display_name": "Temperature",
+ "dynamic": false,
+ "info": "",
+ "max_label": "",
+ "max_label_icon": "",
+ "min_label": "",
+ "min_label_icon": "",
+ "name": "temperature",
+ "placeholder": "",
+ "range_spec": {
+ "max": 1,
+ "min": 0,
+ "step": 0.01,
+ "step_type": "float"
+ },
+ "required": false,
+ "show": true,
+ "slider_buttons": false,
+ "slider_buttons_options": [],
+ "slider_input": false,
+ "title_case": false,
+ "tool_mode": false,
+ "type": "slider",
+ "value": 0.1
+ },
+ "timeout": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Timeout",
+ "dynamic": false,
+ "info": "The timeout for requests to OpenAI completion API.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "timeout",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 700
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": true,
+ "type": "OpenAIModel"
+ },
+ "dragging": false,
+ "id": "OpenAIModel-9iAH4",
+ "measured": {
+ "height": 656,
+ "width": 320
+ },
+ "position": {
+ "x": 929.32546849971,
+ "y": -379.0571813289482
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "ParseData-hLbU0",
+ "node": {
+ "base_classes": [
+ "Data",
+ "Message"
+ ],
+ "beta": false,
+ "category": "processing",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Convert Data objects into Messages using any {field_name} from input data.",
+ "display_name": "Data to Message",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "data",
+ "template",
+ "sep"
+ ],
+ "frozen": false,
+ "icon": "message-square",
+ "key": "ParseData",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": false,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Message",
+ "method": "parse_data",
+ "name": "text",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ },
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Data List",
+ "method": "parse_data_as_list",
+ "name": "data_list",
+ "selected": "Data",
+ "tool_mode": true,
+ "types": [
+ "Data"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 0.23285358167685585,
+ "template": {
+ "_type": "Component",
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\", is_list=True, required=True),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
+ },
+ "data": {
+ "_input_type": "DataInput",
+ "advanced": false,
+ "display_name": "Data",
+ "dynamic": false,
+ "info": "The data to convert to text.",
+ "input_types": [
+ "Data"
+ ],
+ "list": true,
+ "list_add_label": "Add More",
+ "name": "data",
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "other",
+ "value": ""
+ },
+ "sep": {
+ "_input_type": "StrInput",
+ "advanced": true,
+ "display_name": "Separator",
+ "dynamic": false,
+ "info": "",
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "sep",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "\n"
+ },
+ "template": {
+ "_input_type": "MultilineInput",
+ "advanced": false,
+ "display_name": "Template",
+ "dynamic": false,
+ "info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "template",
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "EBITIDA: {EBITIDA} , \nNet Income: {NET_INCOME} ,\nGROSS_PROFIT: {GROSS_PROFIT}"
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": true,
+ "type": "ParseData"
+ },
+ "dragging": false,
+ "id": "ParseData-hLbU0",
+ "measured": {
+ "height": 342,
+ "width": 320
+ },
+ "position": {
+ "x": 1788.8753184818502,
+ "y": 247.15776278878775
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "ChatOutput-ZtLkt",
+ "node": {
+ "base_classes": [
+ "Message"
+ ],
+ "beta": false,
+ "category": "outputs",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Display a chat message in the Playground.",
+ "display_name": "Chat Output",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "input_value",
+ "should_store_message",
+ "sender",
+ "sender_name",
+ "session_id",
+ "data_template",
+ "background_color",
+ "chat_icon",
+ "text_color"
+ ],
+ "frozen": false,
+ "icon": "MessagesSquare",
+ "key": "ChatOutput",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": true,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Message",
+ "method": "message_response",
+ "name": "message",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 0.003169567463043492,
+ "template": {
+ "_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Source\nfrom langflow.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_AI,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n minimized = True\n\n inputs = [\n MessageInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, id_: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if id_:\n source_dict[\"id\"] = id_\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n source_dict[\"source\"] = source\n return Source(**source_dict)\n\n async def message_response(self) -> Message:\n source, icon, display_name, source_id = self.get_properties_from_source_component()\n background_color = self.background_color\n text_color = self.text_color\n if self.chat_icon:\n icon = self.chat_icon\n message = self.input_value if isinstance(self.input_value, Message) else Message(text=self.input_value)\n message.sender = self.sender\n message.sender_name = self.sender_name\n message.session_id = self.session_id\n message.flow_id = self.graph.flow_id if hasattr(self, \"graph\") else None\n message.properties.source = self._build_source(source_id, display_name, source)\n message.properties.icon = icon\n message.properties.background_color = background_color\n message.properties.text_color = text_color\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = await self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ },
+ "data_template": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Data Template",
+ "dynamic": false,
+ "info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "data_template",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "{text}"
+ },
+ "input_value": {
+ "_input_type": "MessageInput",
+ "advanced": false,
+ "display_name": "Text",
+ "dynamic": false,
+ "info": "Message to be passed as output.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "input_value",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "sender": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Sender Type",
+ "dynamic": false,
+ "info": "Type of sender.",
+ "name": "sender",
+ "options": [
+ "Machine",
+ "User"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "Machine"
+ },
+ "sender_name": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Sender Name",
+ "dynamic": false,
+ "info": "Name of the sender.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "sender_name",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "AI"
+ },
+ "session_id": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Session ID",
+ "dynamic": false,
+ "info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "session_id",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "should_store_message": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Store Messages",
+ "dynamic": false,
+ "info": "Store the message in the history.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "should_store_message",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": false,
+ "type": "ChatOutput"
+ },
+ "id": "ChatOutput-ZtLkt",
+ "measured": {
+ "height": 66,
+ "width": 192
+ },
+ "position": {
+ "x": 2235,
+ "y": 435
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "ChatInput-h90IX",
+ "node": {
+ "base_classes": [
+ "Message"
+ ],
+ "beta": false,
+ "category": "inputs",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Get chat inputs from the Playground.",
+ "display_name": "Chat Input",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "input_value",
+ "should_store_message",
+ "sender",
+ "sender_name",
+ "session_id",
+ "files",
+ "background_color",
+ "chat_icon",
+ "text_color"
+ ],
+ "frozen": false,
+ "icon": "MessagesSquare",
+ "key": "ChatInput",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": true,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Message",
+ "method": "message_response",
+ "name": "message",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 0.0020353564437605998,
+ "template": {
+ "_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import (\n DropdownInput,\n FileInput,\n MessageTextInput,\n MultilineInput,\n Output,\n)\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_USER,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n minimized = True\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n input_types=[],\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n async def message_response(self) -> Message:\n background_color = self.background_color\n text_color = self.text_color\n icon = self.chat_icon\n\n message = await Message.create(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n properties={\n \"background_color\": background_color,\n \"text_color\": text_color,\n \"icon\": icon,\n },\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = await self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ },
+ "files": {
+ "_input_type": "FileInput",
+ "advanced": true,
+ "display_name": "Files",
+ "dynamic": false,
+ "fileTypes": [
+ "txt",
+ "md",
+ "mdx",
+ "csv",
+ "json",
+ "yaml",
+ "yml",
+ "xml",
+ "html",
+ "htm",
+ "pdf",
+ "docx",
+ "py",
+ "sh",
+ "sql",
+ "js",
+ "ts",
+ "tsx",
+ "jpg",
+ "jpeg",
+ "png",
+ "bmp",
+ "image"
+ ],
+ "file_path": "",
+ "info": "Files to be sent with the message.",
+ "list": true,
+ "list_add_label": "Add More",
+ "name": "files",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_metadata": true,
+ "type": "file",
+ "value": ""
+ },
+ "input_value": {
+ "_input_type": "MultilineInput",
+ "advanced": false,
+ "display_name": "Text",
+ "dynamic": false,
+ "info": "Message to be passed as input.",
+ "input_types": [],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "input_value",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "In 2022, the company demonstrated strong financial performance, reporting a gross profit of $1.2 billion, reflecting stable revenue generation and effective cost management. The EBITDA stood at $900 million, highlighting the company’s solid operational efficiency and profitability before interest, taxes, depreciation, and amortization. Despite a slight increase in operating expenses compared to 2021, the company maintained a healthy bottom line, achieving a net income of $500 million. This growth underscores the company’s ability to navigate economic challenges while sustaining profitability, reinforcing its financial stability and competitive position in the market."
+ },
+ "sender": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Sender Type",
+ "dynamic": false,
+ "info": "Type of sender.",
+ "name": "sender",
+ "options": [
+ "Machine",
+ "User"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "User"
+ },
+ "sender_name": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Sender Name",
+ "dynamic": false,
+ "info": "Name of the sender.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "sender_name",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "User"
+ },
+ "session_id": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Session ID",
+ "dynamic": false,
+ "info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "session_id",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "should_store_message": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Store Messages",
+ "dynamic": false,
+ "info": "Store the message in the history.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "should_store_message",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": false,
+ "type": "ChatInput"
+ },
+ "dragging": false,
+ "id": "ChatInput-h90IX",
+ "measured": {
+ "height": 66,
+ "width": 192
+ },
+ "position": {
+ "x": 543.3649234613827,
+ "y": 766.4175864707714
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "note-FyXxe",
+ "node": {
+ "description": "### 💡 Add your OpenAI API key here",
+ "display_name": "",
+ "documentation": "",
+ "template": {
+ "backgroundColor": "transparent"
+ }
+ },
+ "type": "note"
+ },
+ "dragging": false,
+ "id": "note-FyXxe",
+ "measured": {
+ "height": 324,
+ "width": 324
+ },
+ "position": {
+ "x": 903.4968193095694,
+ "y": -432.3984534767629
+ },
+ "selected": false,
+ "type": "noteNode"
+ },
+ {
+ "data": {
+ "id": "note-GnLTb",
+ "node": {
+ "description": "\n# Financial Report Parser\n\nThis template extracts key financial metrics from a given financial report text using OpenAI's GPT-4o-mini model. The extracted data is structured and formatted for chat consumption.\n\n## Prerequisites\n\n- **[OpenAI API Key](https://platform.openai.com/)**\n\n## Quickstart\n\n1. Add your OpenAI API key to the OpenAI model.\n2. To run the flow, click **Playground**.\nThe **Chat Input** component in this template is pre-loaded with a sample financial report for demonstrating how structured data is extracted.\n\n* The **OpenAI** model component identifies and retrieves Gross Profit, EBITDA, Net Income, and Operating Expenses from the financial report.\n* The **Structured Output** component formats extracted data into a structured format for better readability and further processing.\n* The **Data to Message** component converts extracted data into formatted messages for chat consumption.\n\n\n\n\n\n",
+ "display_name": "",
+ "documentation": "",
+ "template": {}
+ },
+ "type": "note"
+ },
+ "dragging": false,
+ "height": 688,
+ "id": "note-GnLTb",
+ "measured": {
+ "height": 688,
+ "width": 620
+ },
+ "position": {
+ "x": 270.9912976390468,
+ "y": -396.43811550696176
+ },
+ "resizing": false,
+ "selected": false,
+ "type": "noteNode",
+ "width": 619
+ }
+ ],
+ "viewport": {
+ "x": 69.28080700198359,
+ "y": 332.86206811007617,
+ "zoom": 0.48921500411648144
+ }
+ },
+ "description": "Extracts key financial metrics like Gross Profit, EBITDA, and Net Income from financial reports and structures them for easy analysis, using Structured Output Component",
+ "endpoint_name": "parse_financial_report",
+ "icon": "receipt",
+ "id": "d8c1fe51-a71f-40b6-afe4-8521cc8e9236",
+ "is_component": false,
+ "last_tested_version": "1.1.5",
+ "name": "Financial Report Parser",
+ "tags": [
+ "chatbots",
+ "content-generation"
+ ]
+}
\ No newline at end of file
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Gmail Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Gmail Agent.json
new file mode 100644
index 0000000000..71b981786b
--- /dev/null
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Gmail Agent.json
@@ -0,0 +1,1802 @@
+{
+ "data": {
+ "edges": [
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "ChatInput",
+ "id": "ChatInput-JDz15",
+ "name": "message",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "input_value",
+ "id": "Agent-jnpdC",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "reactflow__edge-ChatInput-JDz15{œdataTypeœ:œChatInputœ,œidœ:œChatInput-JDz15œ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-jnpdC{œfieldNameœ:œinput_valueœ,œidœ:œAgent-jnpdCœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "ChatInput-JDz15",
+ "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-JDz15œ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Agent-jnpdC",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-jnpdCœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "Agent",
+ "id": "Agent-jnpdC",
+ "name": "response",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "input_value",
+ "id": "ChatOutput-lgshI",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "reactflow__edge-Agent-jnpdC{œdataTypeœ:œAgentœ,œidœ:œAgent-jnpdCœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-lgshI{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-lgshIœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "Agent-jnpdC",
+ "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-jnpdCœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "ChatOutput-lgshI",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-lgshIœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ },
+ {
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "ComposioAPI",
+ "id": "ComposioAPI-ajGtz",
+ "name": "tools",
+ "output_types": [
+ "Tool"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "tools",
+ "id": "Agent-jnpdC",
+ "inputTypes": [
+ "Tool"
+ ],
+ "type": "other"
+ }
+ },
+ "id": "xy-edge__ComposioAPI-ajGtz{œdataTypeœ:œComposioAPIœ,œidœ:œComposioAPI-ajGtzœ,œnameœ:œtoolsœ,œoutput_typesœ:[œToolœ]}-Agent-jnpdC{œfieldNameœ:œtoolsœ,œidœ:œAgent-jnpdCœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}",
+ "source": "ComposioAPI-ajGtz",
+ "sourceHandle": "{œdataTypeœ: œComposioAPIœ, œidœ: œComposioAPI-ajGtzœ, œnameœ: œtoolsœ, œoutput_typesœ: [œToolœ]}",
+ "target": "Agent-jnpdC",
+ "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-jnpdCœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}"
+ }
+ ],
+ "nodes": [
+ {
+ "data": {
+ "id": "Agent-jnpdC",
+ "node": {
+ "base_classes": [
+ "Message"
+ ],
+ "beta": false,
+ "category": "agents",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Define the agent's instructions, then enter a task to complete using tools.",
+ "display_name": "Agent",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "agent_llm",
+ "max_tokens",
+ "model_kwargs",
+ "json_mode",
+ "model_name",
+ "openai_api_base",
+ "api_key",
+ "temperature",
+ "seed",
+ "max_retries",
+ "timeout",
+ "system_prompt",
+ "tools",
+ "input_value",
+ "handle_parsing_errors",
+ "verbose",
+ "max_iterations",
+ "agent_description",
+ "memory",
+ "sender",
+ "sender_name",
+ "n_messages",
+ "session_id",
+ "order",
+ "template",
+ "add_current_date_tool"
+ ],
+ "frozen": false,
+ "icon": "bot",
+ "key": "Agent",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": false,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Response",
+ "method": "message_response",
+ "name": "response",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 1.1732828199964098e-19,
+ "template": {
+ "_type": "Component",
+ "add_current_date_tool": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Current Date",
+ "dynamic": false,
+ "info": "If true, will add a tool to the agent that returns the current date.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "add_current_date_tool",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "agent_description": {
+ "_input_type": "MultilineInput",
+ "advanced": true,
+ "display_name": "Agent Description [Deprecated]",
+ "dynamic": false,
+ "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "agent_description",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "A helpful assistant with access to the following tools:"
+ },
+ "agent_llm": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Model Provider",
+ "dynamic": false,
+ "info": "The provider of the language model that the agent will use to generate responses.",
+ "input_types": [],
+ "name": "agent_llm",
+ "options": [
+ "Amazon Bedrock",
+ "Anthropic",
+ "Azure OpenAI",
+ "Google Generative AI",
+ "Groq",
+ "NVIDIA",
+ "OpenAI",
+ "SambaNova",
+ "Custom"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "real_time_refresh": true,
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "OpenAI"
+ },
+ "api_key": {
+ "_input_type": "SecretStrInput",
+ "advanced": false,
+ "display_name": "OpenAI API Key",
+ "dynamic": false,
+ "info": "The OpenAI API Key to use for the OpenAI model.",
+ "input_types": [
+ "Message"
+ ],
+ "load_from_db": false,
+ "name": "api_key",
+ "password": true,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS_DICT,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS_DICT.keys()), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n\n # Validate tools\n if not self.tools:\n msg = \"Tools are required to run the agent. Please add at least one tool.\"\n raise ValueError(msg)\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools,\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS_DICT.keys()), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def to_toolkit(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=self.get_tool_name(), tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n"
+ },
+ "handle_parsing_errors": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Handle Parse Errors",
+ "dynamic": false,
+ "info": "Should the Agent fix errors when reading user input for better processing?",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "handle_parsing_errors",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "input_value": {
+ "_input_type": "MessageTextInput",
+ "advanced": false,
+ "display_name": "Input",
+ "dynamic": false,
+ "info": "The input provided by the user for the agent to process.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "input_value",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": true,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "json_mode": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "JSON Mode",
+ "dynamic": false,
+ "info": "If True, it will output JSON regardless of passing a schema.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "json_mode",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": false
+ },
+ "max_iterations": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Max Iterations",
+ "dynamic": false,
+ "info": "The maximum number of attempts the agent can make to complete its task before it stops.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "max_iterations",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 15
+ },
+ "max_retries": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Max Retries",
+ "dynamic": false,
+ "info": "The maximum number of retries to make when generating.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "max_retries",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 5
+ },
+ "max_tokens": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Max Tokens",
+ "dynamic": false,
+ "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "max_tokens",
+ "placeholder": "",
+ "range_spec": {
+ "max": 128000,
+ "min": 0,
+ "step": 0.1,
+ "step_type": "float"
+ },
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": ""
+ },
+ "memory": {
+ "_input_type": "HandleInput",
+ "advanced": true,
+ "display_name": "External Memory",
+ "dynamic": false,
+ "info": "Retrieve messages from an external memory. If empty, it will use the Langflow tables.",
+ "input_types": [
+ "Memory"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "memory",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_metadata": true,
+ "type": "other",
+ "value": ""
+ },
+ "model_kwargs": {
+ "_input_type": "DictInput",
+ "advanced": true,
+ "display_name": "Model Kwargs",
+ "dynamic": false,
+ "info": "Additional keyword arguments to pass to the model.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "model_kwargs",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "type": "dict",
+ "value": {}
+ },
+ "model_name": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": true,
+ "dialog_inputs": {},
+ "display_name": "Model Name",
+ "dynamic": false,
+ "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.",
+ "name": "model_name",
+ "options": [
+ "gpt-4o-mini",
+ "gpt-4o",
+ "gpt-4-turbo",
+ "gpt-4-turbo-preview",
+ "gpt-4",
+ "gpt-3.5-turbo",
+ "gpt-3.5-turbo-0125"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "real_time_refresh": false,
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "gpt-4o"
+ },
+ "n_messages": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Number of Messages",
+ "dynamic": false,
+ "info": "Number of messages to retrieve.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "n_messages",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 100
+ },
+ "openai_api_base": {
+ "_input_type": "StrInput",
+ "advanced": true,
+ "display_name": "OpenAI API Base",
+ "dynamic": false,
+ "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.",
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "openai_api_base",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "order": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Order",
+ "dynamic": false,
+ "info": "Order of the messages.",
+ "name": "order",
+ "options": [
+ "Ascending",
+ "Descending"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "Ascending"
+ },
+ "seed": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Seed",
+ "dynamic": false,
+ "info": "The seed controls the reproducibility of the job.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "seed",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 1
+ },
+ "sender": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Sender Type",
+ "dynamic": false,
+ "info": "Filter by sender type.",
+ "name": "sender",
+ "options": [
+ "Machine",
+ "User",
+ "Machine and User"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "Machine and User"
+ },
+ "sender_name": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Sender Name",
+ "dynamic": false,
+ "info": "Filter by sender name.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "sender_name",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "session_id": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Session ID",
+ "dynamic": false,
+ "info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "session_id",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "system_prompt": {
+ "_input_type": "MultilineInput",
+ "advanced": false,
+ "display_name": "Agent Instructions",
+ "dynamic": false,
+ "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "system_prompt",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "You are a helpful assistant that can use tools to answer questions and perform tasks."
+ },
+ "temperature": {
+ "_input_type": "SliderInput",
+ "advanced": true,
+ "display_name": "Temperature",
+ "dynamic": false,
+ "info": "",
+ "max_label": "",
+ "max_label_icon": "",
+ "min_label": "",
+ "min_label_icon": "",
+ "name": "temperature",
+ "placeholder": "",
+ "range_spec": {
+ "max": 1,
+ "min": 0,
+ "step": 0.01,
+ "step_type": "float"
+ },
+ "required": false,
+ "show": true,
+ "slider_buttons": false,
+ "slider_buttons_options": [],
+ "slider_input": false,
+ "title_case": false,
+ "tool_mode": false,
+ "type": "slider",
+ "value": 0.1
+ },
+ "template": {
+ "_input_type": "MultilineInput",
+ "advanced": true,
+ "display_name": "Template",
+ "dynamic": false,
+ "info": "The template to use for formatting the data. It can contain the keys {text}, {sender} or any other key in the message data.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "template",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "{sender_name}: {text}"
+ },
+ "timeout": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Timeout",
+ "dynamic": false,
+ "info": "The timeout for requests to OpenAI completion API.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "timeout",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 700
+ },
+ "tools": {
+ "_input_type": "HandleInput",
+ "advanced": false,
+ "display_name": "Tools",
+ "dynamic": false,
+ "info": "These are the tools that the agent can use to help with tasks.",
+ "input_types": [
+ "Tool"
+ ],
+ "list": true,
+ "list_add_label": "Add More",
+ "name": "tools",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_metadata": true,
+ "type": "other",
+ "value": ""
+ },
+ "verbose": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Verbose",
+ "dynamic": false,
+ "info": "",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "verbose",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": true,
+ "type": "Agent"
+ },
+ "dragging": false,
+ "id": "Agent-jnpdC",
+ "measured": {
+ "height": 624,
+ "width": 320
+ },
+ "position": {
+ "x": 246.2965482704007,
+ "y": 49.54798016575572
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "ChatInput-JDz15",
+ "node": {
+ "base_classes": [
+ "Message"
+ ],
+ "beta": false,
+ "category": "inputs",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Get chat inputs from the Playground.",
+ "display_name": "Chat Input",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "input_value",
+ "should_store_message",
+ "sender",
+ "sender_name",
+ "session_id",
+ "files",
+ "background_color",
+ "chat_icon",
+ "text_color"
+ ],
+ "frozen": false,
+ "icon": "MessagesSquare",
+ "key": "ChatInput",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": true,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Message",
+ "method": "message_response",
+ "name": "message",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 0.0020353564437605998,
+ "template": {
+ "_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import (\n DropdownInput,\n FileInput,\n MessageTextInput,\n MultilineInput,\n Output,\n)\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_USER,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n minimized = True\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n input_types=[],\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n async def message_response(self) -> Message:\n background_color = self.background_color\n text_color = self.text_color\n icon = self.chat_icon\n\n message = await Message.create(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n properties={\n \"background_color\": background_color,\n \"text_color\": text_color,\n \"icon\": icon,\n },\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = await self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ },
+ "files": {
+ "_input_type": "FileInput",
+ "advanced": true,
+ "display_name": "Files",
+ "dynamic": false,
+ "fileTypes": [
+ "txt",
+ "md",
+ "mdx",
+ "csv",
+ "json",
+ "yaml",
+ "yml",
+ "xml",
+ "html",
+ "htm",
+ "pdf",
+ "docx",
+ "py",
+ "sh",
+ "sql",
+ "js",
+ "ts",
+ "tsx",
+ "jpg",
+ "jpeg",
+ "png",
+ "bmp",
+ "image"
+ ],
+ "file_path": "",
+ "info": "Files to be sent with the message.",
+ "list": true,
+ "list_add_label": "Add More",
+ "name": "files",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_metadata": true,
+ "type": "file",
+ "value": ""
+ },
+ "input_value": {
+ "_input_type": "MultilineInput",
+ "advanced": false,
+ "display_name": "Text",
+ "dynamic": false,
+ "info": "Message to be passed as input.",
+ "input_types": [],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "input_value",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "sender": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Sender Type",
+ "dynamic": false,
+ "info": "Type of sender.",
+ "name": "sender",
+ "options": [
+ "Machine",
+ "User"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "User"
+ },
+ "sender_name": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Sender Name",
+ "dynamic": false,
+ "info": "Name of the sender.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "sender_name",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "User"
+ },
+ "session_id": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Session ID",
+ "dynamic": false,
+ "info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "session_id",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "should_store_message": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Store Messages",
+ "dynamic": false,
+ "info": "Store the message in the history.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "should_store_message",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": false,
+ "type": "ChatInput"
+ },
+ "dragging": false,
+ "id": "ChatInput-JDz15",
+ "measured": {
+ "height": 66,
+ "width": 192
+ },
+ "position": {
+ "x": -74.59464648081578,
+ "y": 605.4102099043162
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "ChatOutput-lgshI",
+ "node": {
+ "base_classes": [
+ "Message"
+ ],
+ "beta": false,
+ "category": "outputs",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Display a chat message in the Playground.",
+ "display_name": "Chat Output",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "input_value",
+ "should_store_message",
+ "sender",
+ "sender_name",
+ "session_id",
+ "data_template",
+ "background_color",
+ "chat_icon",
+ "text_color"
+ ],
+ "frozen": false,
+ "icon": "MessagesSquare",
+ "key": "ChatOutput",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": true,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Message",
+ "method": "message_response",
+ "name": "message",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 0.003169567463043492,
+ "template": {
+ "_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Source\nfrom langflow.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_AI,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n minimized = True\n\n inputs = [\n MessageInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, id_: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if id_:\n source_dict[\"id\"] = id_\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n source_dict[\"source\"] = source\n return Source(**source_dict)\n\n async def message_response(self) -> Message:\n source, icon, display_name, source_id = self.get_properties_from_source_component()\n background_color = self.background_color\n text_color = self.text_color\n if self.chat_icon:\n icon = self.chat_icon\n message = self.input_value if isinstance(self.input_value, Message) else Message(text=self.input_value)\n message.sender = self.sender\n message.sender_name = self.sender_name\n message.session_id = self.session_id\n message.flow_id = self.graph.flow_id if hasattr(self, \"graph\") else None\n message.properties.source = self._build_source(source_id, display_name, source)\n message.properties.icon = icon\n message.properties.background_color = background_color\n message.properties.text_color = text_color\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = await self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ },
+ "data_template": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Data Template",
+ "dynamic": false,
+ "info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "data_template",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "{text}"
+ },
+ "input_value": {
+ "_input_type": "MessageInput",
+ "advanced": false,
+ "display_name": "Text",
+ "dynamic": false,
+ "info": "Message to be passed as output.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "input_value",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "sender": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Sender Type",
+ "dynamic": false,
+ "info": "Type of sender.",
+ "name": "sender",
+ "options": [
+ "Machine",
+ "User"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "Machine"
+ },
+ "sender_name": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Sender Name",
+ "dynamic": false,
+ "info": "Name of the sender.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "sender_name",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "AI"
+ },
+ "session_id": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Session ID",
+ "dynamic": false,
+ "info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "session_id",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "should_store_message": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Store Messages",
+ "dynamic": false,
+ "info": "Store the message in the history.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "should_store_message",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": false,
+ "type": "ChatOutput"
+ },
+ "dragging": false,
+ "id": "ChatOutput-lgshI",
+ "measured": {
+ "height": 66,
+ "width": 192
+ },
+ "position": {
+ "x": 641.2349415828351,
+ "y": 617.3336058447763
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "note-t5lD7",
+ "node": {
+ "description": "# Gmail Agent\nUsing this flow you can send emails, create drafts, fetch emails and more\n\n## Instructions\n\n1. Get Composio API Key\n - Visit https://app.composio.dev\n - Enter the key in the \"Composio API Key\" field\n\n2. Authenticate Gmail Account\n - Select Gmail App from the dropdown menu in the App Names field\n - Click the refresh button next to the App Name\n - Follow the Gmail authentication link\n - After authenticating, click refresh again\n - Verify that authentication status shows as successful\n\n3. Select Actions\n - Default actions (pre-selected):\n - GMAIL_SEND_EMAIL: Send emails directly\n - GMAIL_CREATE_EMAIL_DRAFT: Create draft emails\n - Select additional actions based on your needs\n\n4. Configure OpenAI\n - Enter your OpenAI API key in the Agent OpenAI API key field\n\n5. Run Agent\n Example prompts:\n - \"Send an email to johndoe@gmail.com wishing them Happy birthday!\"\n - \"Create a draft email about project updates\"",
+ "display_name": "",
+ "documentation": "",
+ "template": {}
+ },
+ "type": "note"
+ },
+ "dragging": false,
+ "height": 842,
+ "id": "note-t5lD7",
+ "measured": {
+ "height": 842,
+ "width": 395
+ },
+ "position": {
+ "x": -699.0352178208514,
+ "y": -87.30330362954265
+ },
+ "resizing": false,
+ "selected": false,
+ "type": "noteNode",
+ "width": 394
+ },
+ {
+ "data": {
+ "id": "ComposioAPI-ajGtz",
+ "node": {
+ "base_classes": [
+ "Tool"
+ ],
+ "beta": false,
+ "category": "composio",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Use Composio toolset to run actions with your agent",
+ "display_name": "Composio Tools",
+ "documentation": "https://docs.composio.dev",
+ "edited": false,
+ "field_order": [
+ "entity_id",
+ "api_key",
+ "app_names",
+ "app_credentials",
+ "username",
+ "auth_link",
+ "auth_status",
+ "action_names"
+ ],
+ "frozen": false,
+ "icon": "Composio",
+ "key": "ComposioAPI",
+ "legacy": false,
+ "metadata": {},
+ "minimized": false,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Tools",
+ "hidden": null,
+ "method": "build_tool",
+ "name": "tools",
+ "required_inputs": null,
+ "selected": "Tool",
+ "tool_mode": true,
+ "types": [
+ "Tool"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 0.020497501093998755,
+ "template": {
+ "_type": "Component",
+ "action_names": {
+ "_input_type": "MultiselectInput",
+ "advanced": false,
+ "combobox": false,
+ "display_name": "Actions to use",
+ "dynamic": true,
+ "info": "The actions to pass to agent to execute",
+ "list": true,
+ "list_add_label": "Add More",
+ "name": "action_names",
+ "options": [
+ "GMAIL_GET_PEOPLE",
+ "GMAIL_FETCH_EMAILS",
+ "GMAIL_FETCH_MESSAGE_BY_THREAD_ID",
+ "GMAIL_SEARCH_PEOPLE",
+ "GMAIL_SEND_EMAIL",
+ "GMAIL_CREATE_EMAIL_DRAFT",
+ "GMAIL_FETCH_MESSAGE_BY_MESSAGE_ID",
+ "GMAIL_CREATE_LABEL",
+ "GMAIL_GET_ATTACHMENT",
+ "GMAIL_REMOVE_LABEL",
+ "GMAIL_GET_PROFILE",
+ "GMAIL_ADD_LABEL_TO_EMAIL",
+ "GMAIL_GET_CONTACTS",
+ "GMAIL_REPLY_TO_THREAD",
+ "GMAIL_LIST_LABELS",
+ "GMAIL_LIST_THREADS",
+ "GMAIL_MODIFY_THREAD_LABELS"
+ ],
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": [
+ "GMAIL_SEND_EMAIL",
+ "GMAIL_CREATE_EMAIL_DRAFT"
+ ]
+ },
+ "api_key": {
+ "_input_type": "SecretStrInput",
+ "advanced": false,
+ "display_name": "Composio API Key",
+ "dynamic": false,
+ "info": "Refer to https://docs.composio.dev/faq/api_key/api_key",
+ "input_types": [
+ "Message"
+ ],
+ "load_from_db": false,
+ "name": "api_key",
+ "password": true,
+ "placeholder": "",
+ "real_time_refresh": true,
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "str",
+ "value": ""
+ },
+ "app_credentials": {
+ "_input_type": "SecretStrInput",
+ "advanced": true,
+ "display_name": "App Credentials",
+ "dynamic": true,
+ "info": "Credentials for app authentication (API Key, Password, etc)",
+ "input_types": [
+ "Message"
+ ],
+ "load_from_db": false,
+ "name": "app_credentials",
+ "password": true,
+ "placeholder": "",
+ "required": false,
+ "show": false,
+ "title_case": false,
+ "type": "str",
+ "value": ""
+ },
+ "app_names": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "App Name",
+ "dynamic": false,
+ "info": "The app name to use. Please refresh after selecting app name",
+ "name": "app_names",
+ "options": [
+ "ACCELO",
+ "AIRTABLE",
+ "AMAZON",
+ "APALEO",
+ "ASANA",
+ "ATLASSIAN",
+ "ATTIO",
+ "AUTH0",
+ "BATTLENET",
+ "BITBUCKET",
+ "BLACKBAUD",
+ "BLACKBOARD",
+ "BOLDSIGN",
+ "BORNEO",
+ "BOX",
+ "BRAINTREE",
+ "BREX",
+ "BREX_STAGING",
+ "BRIGHTPEARL",
+ "CALENDLY",
+ "CANVA",
+ "CANVAS",
+ "CHATWORK",
+ "CLICKUP",
+ "CONTENTFUL",
+ "D2LBRIGHTSPACE",
+ "DEEL",
+ "DISCORD",
+ "DISCORDBOT",
+ "DOCUSIGN",
+ "DROPBOX",
+ "DROPBOX_SIGN",
+ "DYNAMICS365",
+ "EPIC_GAMES",
+ "EVENTBRITE",
+ "EXIST",
+ "FACEBOOK",
+ "FIGMA",
+ "FITBIT",
+ "FRESHBOOKS",
+ "FRONT",
+ "GITHUB",
+ "GMAIL",
+ "GMAIL_BETA",
+ "GO_TO_WEBINAR",
+ "GOOGLE_ANALYTICS",
+ "GOOGLE_DRIVE_BETA",
+ "GOOGLE_MAPS",
+ "GOOGLECALENDAR",
+ "GOOGLEDOCS",
+ "GOOGLEDRIVE",
+ "GOOGLEMEET",
+ "GOOGLEPHOTOS",
+ "GOOGLESHEETS",
+ "GOOGLETASKS",
+ "GORGIAS",
+ "GUMROAD",
+ "HARVEST",
+ "HIGHLEVEL",
+ "HUBSPOT",
+ "ICIMS_TALENT_CLOUD",
+ "INTERCOM",
+ "JIRA",
+ "KEAP",
+ "KLAVIYO",
+ "LASTPASS",
+ "LEVER",
+ "LEVER_SANDBOX",
+ "LINEAR",
+ "LINKEDIN",
+ "LINKHUT",
+ "MAILCHIMP",
+ "MICROSOFT_TEAMS",
+ "MICROSOFT_TENANT",
+ "MIRO",
+ "MONDAY",
+ "MURAL",
+ "NETSUITE",
+ "NOTION",
+ "ONE_DRIVE",
+ "OUTLOOK",
+ "PAGERDUTY",
+ "PIPEDRIVE",
+ "PRODUCTBOARD",
+ "REDDIT",
+ "RING_CENTRAL",
+ "RIPPLING",
+ "SAGE",
+ "SALESFORCE",
+ "SEISMIC",
+ "SERVICEM8",
+ "SHARE_POINT",
+ "SHOPIFY",
+ "SLACK",
+ "SLACKBOT",
+ "SMARTRECRUITERS",
+ "SPOTIFY",
+ "SQUARE",
+ "STACK_EXCHANGE",
+ "SURVEY_MONKEY",
+ "TIMELY",
+ "TODOIST",
+ "TONEDEN",
+ "TRELLO",
+ "TWITCH",
+ "TWITTER",
+ "TWITTER_MEDIA",
+ "WAKATIME",
+ "WAVE_ACCOUNTING",
+ "WEBEX",
+ "WIZ",
+ "WRIKE",
+ "XERO",
+ "YANDEX",
+ "YNAB",
+ "YOUTUBE",
+ "ZENDESK",
+ "ZOHO",
+ "ZOHO_BIGIN",
+ "ZOHO_BOOKS",
+ "ZOHO_DESK",
+ "ZOHO_INVENTORY",
+ "ZOHO_INVOICE",
+ "ZOHO_MAIL",
+ "ZOOM"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "refresh_button": true,
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "GMAIL"
+ },
+ "auth_link": {
+ "_input_type": "LinkInput",
+ "advanced": true,
+ "display_name": "Authentication Link",
+ "dynamic": true,
+ "info": "Click to authenticate with OAuth2",
+ "load_from_db": false,
+ "name": "auth_link",
+ "placeholder": "Click to authenticate",
+ "required": false,
+ "show": false,
+ "title_case": false,
+ "type": "link",
+ "value": ""
+ },
+ "auth_status": {
+ "_input_type": "StrInput",
+ "advanced": true,
+ "display_name": "Auth Status",
+ "dynamic": true,
+ "info": "Current authentication status",
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "auth_status",
+ "placeholder": "",
+ "required": false,
+ "show": false,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "# Standard library imports\nfrom collections.abc import Sequence\nfrom typing import Any\n\nimport requests\n\n# Third-party imports\nfrom composio.client.collections import AppAuthScheme\nfrom composio.client.exceptions import NoItemsFound\nfrom composio_langchain import Action, ComposioToolSet\nfrom langchain_core.tools import Tool\nfrom loguru import logger\n\n# Local imports\nfrom langflow.base.langchain_utilities.model import LCToolComponent\nfrom langflow.inputs import DropdownInput, LinkInput, MessageTextInput, MultiselectInput, SecretStrInput, StrInput\nfrom langflow.io import Output\n\n\nclass ComposioAPIComponent(LCToolComponent):\n display_name: str = \"Composio Tools\"\n description: str = \"Use Composio toolset to run actions with your agent\"\n name = \"ComposioAPI\"\n icon = \"Composio\"\n documentation: str = \"https://docs.composio.dev\"\n\n inputs = [\n # Basic configuration inputs\n MessageTextInput(name=\"entity_id\", display_name=\"Entity ID\", value=\"default\", advanced=True),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Composio API Key\",\n required=True,\n info=\"Refer to https://docs.composio.dev/faq/api_key/api_key\",\n real_time_refresh=True,\n ),\n DropdownInput(\n name=\"app_names\",\n display_name=\"App Name\",\n options=[],\n value=\"\",\n info=\"The app name to use. Please refresh after selecting app name\",\n refresh_button=True,\n required=True,\n ),\n # Authentication-related inputs (initially hidden)\n SecretStrInput(\n name=\"app_credentials\",\n display_name=\"App Credentials\",\n required=False,\n dynamic=True,\n show=False,\n info=\"Credentials for app authentication (API Key, Password, etc)\",\n load_from_db=False,\n ),\n MessageTextInput(\n name=\"username\",\n display_name=\"Username\",\n required=False,\n dynamic=True,\n show=False,\n info=\"Username for Basic authentication\",\n ),\n LinkInput(\n name=\"auth_link\",\n display_name=\"Authentication Link\",\n value=\"\",\n info=\"Click to authenticate with OAuth2\",\n dynamic=True,\n show=False,\n placeholder=\"Click to authenticate\",\n ),\n StrInput(\n name=\"auth_status\",\n display_name=\"Auth Status\",\n value=\"Not Connected\",\n info=\"Current authentication status\",\n dynamic=True,\n show=False,\n ),\n MultiselectInput(\n name=\"action_names\",\n display_name=\"Actions to use\",\n required=True,\n options=[],\n value=[],\n info=\"The actions to pass to agent to execute\",\n dynamic=True,\n show=False,\n ),\n ]\n\n outputs = [\n Output(name=\"tools\", display_name=\"Tools\", method=\"build_tool\"),\n ]\n\n def _check_for_authorization(self, app: str) -> str:\n \"\"\"Checks if the app is authorized.\n\n Args:\n app (str): The app name to check authorization for.\n\n Returns:\n str: The authorization status or URL.\n \"\"\"\n toolset = self._build_wrapper()\n entity = toolset.client.get_entity(id=self.entity_id)\n try:\n # Check if user is already connected\n entity.get_connection(app=app)\n except NoItemsFound:\n # Get auth scheme for the app\n auth_scheme = self._get_auth_scheme(app)\n return self._handle_auth_by_scheme(entity, app, auth_scheme)\n except Exception: # noqa: BLE001\n logger.exception(\"Authorization error\")\n return \"Error checking authorization\"\n else:\n return f\"{app} CONNECTED\"\n\n def _get_auth_scheme(self, app_name: str) -> AppAuthScheme:\n \"\"\"Get the primary auth scheme for an app.\n\n Args:\n app_name (str): The name of the app to get auth scheme for.\n\n Returns:\n AppAuthScheme: The auth scheme details.\n \"\"\"\n toolset = self._build_wrapper()\n try:\n return toolset.get_auth_scheme_for_app(app=app_name.lower())\n except Exception: # noqa: BLE001\n logger.exception(f\"Error getting auth scheme for {app_name}\")\n return None\n\n def _get_oauth_apps(self, api_key: str) -> list[str]:\n \"\"\"Fetch OAuth-enabled apps from Composio API.\n\n Args:\n api_key (str): The Composio API key.\n\n Returns:\n list[str]: A list containing OAuth-enabled app names.\n \"\"\"\n oauth_apps = []\n try:\n url = \"https://backend.composio.dev/api/v1/apps\"\n headers = {\"x-api-key\": api_key}\n params = {\n \"includeLocal\": \"true\",\n \"additionalFields\": \"auth_schemes\",\n \"sortBy\": \"alphabet\",\n }\n\n response = requests.get(url, headers=headers, params=params, timeout=20)\n data = response.json()\n\n for item in data.get(\"items\", []):\n for auth_scheme in item.get(\"auth_schemes\", []):\n if auth_scheme.get(\"mode\") in [\"OAUTH1\", \"OAUTH2\"]:\n oauth_apps.append(item[\"key\"].upper())\n break\n except requests.RequestException as e:\n logger.error(f\"Error fetching OAuth apps: {e}\")\n return []\n else:\n return oauth_apps\n\n def _handle_auth_by_scheme(self, entity: Any, app: str, auth_scheme: AppAuthScheme) -> str:\n \"\"\"Handle authentication based on the auth scheme.\n\n Args:\n entity (Any): The entity instance.\n app (str): The app name.\n auth_scheme (AppAuthScheme): The auth scheme details.\n\n Returns:\n str: The authentication status or URL.\n \"\"\"\n auth_mode = auth_scheme.auth_mode\n\n try:\n # First check if already connected\n entity.get_connection(app=app)\n except NoItemsFound:\n # If not connected, handle new connection based on auth mode\n if auth_mode == \"API_KEY\":\n if hasattr(self, \"app_credentials\") and self.app_credentials:\n try:\n entity.initiate_connection(\n app_name=app,\n auth_mode=\"API_KEY\",\n auth_config={\"api_key\": self.app_credentials},\n use_composio_auth=False,\n force_new_integration=True,\n )\n except Exception as e: # noqa: BLE001\n logger.error(f\"Error connecting with API Key: {e}\")\n return \"Invalid API Key\"\n else:\n return f\"{app} CONNECTED\"\n return \"Enter API Key\"\n\n if (\n auth_mode == \"BASIC\"\n and hasattr(self, \"username\")\n and hasattr(self, \"app_credentials\")\n and self.username\n and self.app_credentials\n ):\n try:\n entity.initiate_connection(\n app_name=app,\n auth_mode=\"BASIC\",\n auth_config={\"username\": self.username, \"password\": self.app_credentials},\n use_composio_auth=False,\n force_new_integration=True,\n )\n except Exception as e: # noqa: BLE001\n logger.error(f\"Error connecting with Basic Auth: {e}\")\n return \"Invalid credentials\"\n else:\n return f\"{app} CONNECTED\"\n elif auth_mode == \"BASIC\":\n return \"Enter Username and Password\"\n\n if auth_mode == \"OAUTH2\":\n try:\n return self._initiate_default_connection(entity, app)\n except Exception as e: # noqa: BLE001\n logger.error(f\"Error initiating OAuth2: {e}\")\n return \"OAuth2 initialization failed\"\n\n return \"Unsupported auth mode\"\n except Exception as e: # noqa: BLE001\n logger.error(f\"Error checking connection status: {e}\")\n return f\"Error: {e!s}\"\n else:\n return f\"{app} CONNECTED\"\n\n def _initiate_default_connection(self, entity: Any, app: str) -> str:\n connection = entity.initiate_connection(app_name=app, use_composio_auth=True, force_new_integration=True)\n return connection.redirectUrl\n\n def _get_connected_app_names_for_entity(self) -> list[str]:\n toolset = self._build_wrapper()\n connections = toolset.client.get_entity(id=self.entity_id).get_connections()\n return list({connection.appUniqueId for connection in connections})\n\n def _get_normalized_app_name(self) -> str:\n \"\"\"Get app name without connection status suffix.\n\n Returns:\n str: Normalized app name.\n \"\"\"\n return self.app_names.replace(\" ✅\", \"\").replace(\"_connected\", \"\")\n\n def update_build_config(self, build_config: dict, field_value: Any, field_name: str | None = None) -> dict: # noqa: ARG002\n # Update the available apps options from the API\n if hasattr(self, \"api_key\") and self.api_key != \"\":\n toolset = self._build_wrapper()\n build_config[\"app_names\"][\"options\"] = self._get_oauth_apps(api_key=self.api_key)\n\n # First, ensure all dynamic fields are hidden by default\n dynamic_fields = [\"app_credentials\", \"username\", \"auth_link\", \"auth_status\", \"action_names\"]\n for field in dynamic_fields:\n if field in build_config:\n if build_config[field][\"value\"] is None or build_config[field][\"value\"] == \"\":\n build_config[field][\"show\"] = False\n build_config[field][\"advanced\"] = True\n build_config[field][\"load_from_db\"] = False\n else:\n build_config[field][\"show\"] = True\n build_config[field][\"advanced\"] = False\n\n if field_name == \"app_names\" and (not hasattr(self, \"app_names\") or not self.app_names):\n build_config[\"auth_status\"][\"show\"] = True\n build_config[\"auth_status\"][\"value\"] = \"Please select an app first\"\n return build_config\n\n if field_name == \"app_names\" and hasattr(self, \"api_key\") and self.api_key != \"\":\n # app_name = self._get_normalized_app_name()\n app_name = self.app_names\n try:\n toolset = self._build_wrapper()\n entity = toolset.client.get_entity(id=self.entity_id)\n\n # Always show auth_status when app is selected\n build_config[\"auth_status\"][\"show\"] = True\n build_config[\"auth_status\"][\"advanced\"] = False\n\n try:\n # Check if already connected\n entity.get_connection(app=app_name)\n build_config[\"auth_status\"][\"value\"] = \"✅\"\n build_config[\"auth_link\"][\"show\"] = False\n # Show action selection for connected apps\n build_config[\"action_names\"][\"show\"] = True\n build_config[\"action_names\"][\"advanced\"] = False\n\n except NoItemsFound:\n # Get auth scheme and show relevant fields\n auth_scheme = self._get_auth_scheme(app_name)\n auth_mode = auth_scheme.auth_mode\n logger.info(f\"Auth mode for {app_name}: {auth_mode}\")\n\n if auth_mode == \"API_KEY\":\n build_config[\"app_credentials\"][\"show\"] = True\n build_config[\"app_credentials\"][\"advanced\"] = False\n build_config[\"app_credentials\"][\"display_name\"] = \"API Key\"\n build_config[\"auth_status\"][\"value\"] = \"Enter API Key\"\n\n elif auth_mode == \"BASIC\":\n build_config[\"username\"][\"show\"] = True\n build_config[\"username\"][\"advanced\"] = False\n build_config[\"app_credentials\"][\"show\"] = True\n build_config[\"app_credentials\"][\"advanced\"] = False\n build_config[\"app_credentials\"][\"display_name\"] = \"Password\"\n build_config[\"auth_status\"][\"value\"] = \"Enter Username and Password\"\n\n elif auth_mode == \"OAUTH2\":\n build_config[\"auth_link\"][\"show\"] = True\n build_config[\"auth_link\"][\"advanced\"] = False\n auth_url = self._initiate_default_connection(entity, app_name)\n build_config[\"auth_link\"][\"value\"] = auth_url\n build_config[\"auth_status\"][\"value\"] = \"Click link to authenticate\"\n\n else:\n build_config[\"auth_status\"][\"value\"] = \"Unsupported auth mode\"\n\n # Update action names if connected\n if build_config[\"auth_status\"][\"value\"] == \"✅\":\n all_action_names = [str(action).replace(\"Action.\", \"\") for action in Action.all()]\n app_action_names = [\n action_name\n for action_name in all_action_names\n if action_name.lower().startswith(app_name.lower() + \"_\")\n ]\n if build_config[\"action_names\"][\"options\"] != app_action_names:\n build_config[\"action_names\"][\"options\"] = app_action_names\n build_config[\"action_names\"][\"value\"] = [app_action_names[0]] if app_action_names else [\"\"]\n\n except Exception as e: # noqa: BLE001\n logger.error(f\"Error checking auth status: {e}, app: {app_name}\")\n build_config[\"auth_status\"][\"value\"] = f\"Error: {e!s}\"\n\n return build_config\n\n def build_tool(self) -> Sequence[Tool]:\n \"\"\"Build Composio tools based on selected actions.\n\n Returns:\n Sequence[Tool]: List of configured Composio tools.\n \"\"\"\n composio_toolset = self._build_wrapper()\n return composio_toolset.get_tools(actions=self.action_names)\n\n def _build_wrapper(self) -> ComposioToolSet:\n \"\"\"Build the Composio toolset wrapper.\n\n Returns:\n ComposioToolSet: The initialized toolset.\n\n Raises:\n ValueError: If the API key is not found or invalid.\n \"\"\"\n try:\n if not self.api_key:\n msg = \"Composio API Key is required\"\n raise ValueError(msg)\n return ComposioToolSet(api_key=self.api_key)\n except ValueError as e:\n logger.error(f\"Error building Composio wrapper: {e}\")\n msg = \"Please provide a valid Composio API Key in the component settings\"\n raise ValueError(msg) from e\n"
+ },
+ "entity_id": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Entity ID",
+ "dynamic": false,
+ "info": "",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "entity_id",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "default"
+ },
+ "username": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Username",
+ "dynamic": true,
+ "info": "Username for Basic authentication",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "username",
+ "placeholder": "",
+ "required": false,
+ "show": false,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": true,
+ "type": "ComposioAPI"
+ },
+ "dragging": false,
+ "id": "ComposioAPI-ajGtz",
+ "measured": {
+ "height": 415,
+ "width": 320
+ },
+ "position": {
+ "x": -137.53986902236176,
+ "y": 20.325147658297382
+ },
+ "selected": true,
+ "type": "genericNode"
+ }
+ ],
+ "viewport": {
+ "x": 368.95391968218075,
+ "y": 154.58720326423327,
+ "zoom": 0.7309415987294762
+ }
+ },
+ "description": "Interact with Gmail to send emails, create drafts, and fetch messages",
+ "endpoint_name": null,
+ "folder_id": "4599f5b8-0cbe-4a2e-a492-8b3fa6193da4",
+ "gradient": null,
+ "icon": "mail",
+ "icon_bg_color": null,
+ "id": "44cfd75e-0f47-4011-8802-9e124b782c42",
+ "is_component": false,
+ "locked": false,
+ "name": "Gmail Agent",
+ "tags": ["agents"],
+ "updated_at": "2025-02-14T09:35:52+00:00",
+ "user_id": "baa8aaab-c242-4191-b79d-761bdb5a393c",
+ "webhook": false
+}
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Graph Vector Store RAG.json b/src/backend/base/langflow/initial_setup/starter_projects/Graph Vector Store RAG.json
index 9df0e5ff6a..f937d9235b 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Graph Vector Store RAG.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Graph Vector Store RAG.json
@@ -9,16 +9,12 @@
"dataType": "OpenAIEmbeddings",
"id": "OpenAIEmbeddings-jyvkr",
"name": "embeddings",
- "output_types": [
- "Embeddings"
- ]
+ "output_types": ["Embeddings"]
},
"targetHandle": {
"fieldName": "embedding_model",
"id": "AstraDBGraph-jr8pY",
- "inputTypes": [
- "Embeddings"
- ],
+ "inputTypes": ["Embeddings"],
"type": "other"
}
},
@@ -37,16 +33,12 @@
"dataType": "ChatInput",
"id": "ChatInput-ZCSfi",
"name": "message",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "search_query",
"id": "AstraDBGraph-jr8pY",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -65,16 +57,12 @@
"dataType": "AstraDBGraph",
"id": "AstraDBGraph-jr8pY",
"name": "search_results",
- "output_types": [
- "Data"
- ]
+ "output_types": ["Data"]
},
"targetHandle": {
"fieldName": "data",
"id": "ParseData-T6FGT",
- "inputTypes": [
- "Data"
- ],
+ "inputTypes": ["Data"],
"type": "other"
}
},
@@ -93,17 +81,12 @@
"dataType": "ParseData",
"id": "ParseData-T6FGT",
"name": "text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "context",
"id": "Prompt-2M2d5",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
@@ -122,17 +105,12 @@
"dataType": "ChatInput",
"id": "ChatInput-ZCSfi",
"name": "message",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "question",
"id": "Prompt-2M2d5",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
@@ -151,16 +129,12 @@
"dataType": "Prompt",
"id": "Prompt-2M2d5",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "OpenAIModel-a26gL",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -179,16 +153,12 @@
"dataType": "OpenAIModel",
"id": "OpenAIModel-a26gL",
"name": "text_output",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "ChatOutput-XL9ho",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -207,17 +177,12 @@
"dataType": "URL",
"id": "URL-fyWIL",
"name": "data",
- "output_types": [
- "Data"
- ]
+ "output_types": ["Data"]
},
"targetHandle": {
"fieldName": "data_input",
"id": "LanguageRecursiveTextSplitter-jefpx",
- "inputTypes": [
- "Document",
- "Data"
- ],
+ "inputTypes": ["Document", "Data"],
"type": "other"
}
},
@@ -236,17 +201,12 @@
"dataType": "LanguageRecursiveTextSplitter",
"id": "LanguageRecursiveTextSplitter-jefpx",
"name": "data",
- "output_types": [
- "Data"
- ]
+ "output_types": ["Data"]
},
"targetHandle": {
"fieldName": "data_input",
"id": "HtmlLinkExtractor-exHgk",
- "inputTypes": [
- "Document",
- "Data"
- ],
+ "inputTypes": ["Document", "Data"],
"type": "other"
}
},
@@ -265,16 +225,12 @@
"dataType": "HtmlLinkExtractor",
"id": "HtmlLinkExtractor-exHgk",
"name": "data",
- "output_types": [
- "Data"
- ]
+ "output_types": ["Data"]
},
"targetHandle": {
"fieldName": "ingest_data",
"id": "AstraDBGraph-FX0tA",
- "inputTypes": [
- "Data"
- ],
+ "inputTypes": ["Data"],
"type": "other"
}
},
@@ -293,16 +249,12 @@
"dataType": "OpenAIEmbeddings",
"id": "OpenAIEmbeddings-83wEc",
"name": "embeddings",
- "output_types": [
- "Embeddings"
- ]
+ "output_types": ["Embeddings"]
},
"targetHandle": {
"fieldName": "embedding_model",
"id": "AstraDBGraph-FX0tA",
- "inputTypes": [
- "Embeddings"
- ],
+ "inputTypes": ["Embeddings"],
"type": "other"
}
},
@@ -319,9 +271,7 @@
"data": {
"id": "ChatInput-ZCSfi",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -355,9 +305,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -370,9 +318,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -392,9 +338,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -497,10 +441,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -516,9 +457,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -538,9 +477,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -576,9 +513,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -620,9 +555,7 @@
"data": {
"id": "OpenAIEmbeddings-jyvkr",
"node": {
- "base_classes": [
- "Embeddings"
- ],
+ "base_classes": ["Embeddings"],
"beta": false,
"category": "embeddings",
"conditional_paths": [],
@@ -668,14 +601,10 @@
"display_name": "Embeddings",
"method": "build_embeddings",
"name": "embeddings",
- "required_inputs": [
- "openai_api_key"
- ],
+ "required_inputs": ["openai_api_key"],
"selected": "Embeddings",
"tool_mode": true,
- "types": [
- "Embeddings"
- ],
+ "types": ["Embeddings"],
"value": "__UNDEFINED__"
}
],
@@ -705,9 +634,7 @@
"display_name": "Client",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "client",
@@ -777,9 +704,7 @@
"display_name": "Deployment",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "deployment",
@@ -885,9 +810,7 @@
"display_name": "OpenAI API Base",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_api_base",
@@ -907,10 +830,8 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
- "load_from_db": false,
+ "input_types": ["Message"],
+ "load_from_db": true,
"name": "openai_api_key",
"password": true,
"placeholder": "",
@@ -918,7 +839,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"openai_api_type": {
"_input_type": "MessageTextInput",
@@ -926,9 +847,7 @@
"display_name": "OpenAI API Type",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_api_type",
@@ -948,9 +867,7 @@
"display_name": "OpenAI API Version",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_api_version",
@@ -970,9 +887,7 @@
"display_name": "OpenAI Organization",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_organization",
@@ -992,9 +907,7 @@
"display_name": "OpenAI Proxy",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_proxy",
@@ -1078,9 +991,7 @@
"display_name": "TikToken Model Name",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tiktoken_model_name",
@@ -1124,9 +1035,7 @@
"display_name": "Astra DB Graph",
"id": "AstraDBGraph-jr8pY",
"node": {
- "base_classes": [
- "Data"
- ],
+ "base_classes": ["Data"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -1172,16 +1081,10 @@
"display_name": "Search Results",
"method": "search_documents",
"name": "search_results",
- "required_inputs": [
- "api_endpoint",
- "collection_name",
- "token"
- ],
+ "required_inputs": ["api_endpoint", "collection_name", "token"],
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
},
{
@@ -1193,9 +1096,7 @@
"required_inputs": [],
"selected": "DataFrame",
"tool_mode": true,
- "types": [
- "DataFrame"
- ],
+ "types": ["DataFrame"],
"value": "__UNDEFINED__"
}
],
@@ -1208,9 +1109,7 @@
"display_name": "API Endpoint",
"dynamic": false,
"info": "API endpoint URL for the Astra DB service.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": false,
"name": "api_endpoint",
"password": true,
@@ -1349,9 +1248,7 @@
"display_name": "Embedding Model",
"dynamic": false,
"info": "Allows an embedding model configuration.",
- "input_types": [
- "Embeddings"
- ],
+ "input_types": ["Embeddings"],
"list": false,
"name": "embedding_model",
"placeholder": "",
@@ -1368,9 +1265,7 @@
"display_name": "Ingest Data",
"dynamic": false,
"info": "",
- "input_types": [
- "Data"
- ],
+ "input_types": ["Data"],
"list": false,
"name": "ingest_data",
"placeholder": "",
@@ -1435,9 +1330,7 @@
"tool_mode": false,
"trace_as_metadata": true,
"type": "str",
- "value": [
- ""
- ]
+ "value": [""]
},
"metadata_indexing_include": {
"_input_type": "StrInput",
@@ -1465,11 +1358,7 @@
"dynamic": false,
"info": "Optional distance metric for vector comparisons in the vector store.",
"name": "metric",
- "options": [
- "cosine",
- "dot_product",
- "euclidean"
- ],
+ "options": ["cosine", "dot_product", "euclidean"],
"placeholder": "",
"required": false,
"show": true,
@@ -1537,9 +1426,7 @@
"display_name": "Search Query",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1604,10 +1491,7 @@
"dynamic": false,
"info": "Configuration mode for setting up the vector store, with options like 'Sync', or 'Off'.",
"name": "setup_mode",
- "options": [
- "Sync",
- "Off"
- ],
+ "options": ["Sync", "Off"],
"placeholder": "",
"required": false,
"show": true,
@@ -1623,9 +1507,7 @@
"display_name": "Astra DB Application Token",
"dynamic": false,
"info": "Authentication token for accessing Astra DB.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": false,
"name": "token",
"password": true,
@@ -1660,10 +1542,7 @@
"display_name": "Parse Data",
"id": "ParseData-T6FGT",
"node": {
- "base_classes": [
- "Data",
- "Message"
- ],
+ "base_classes": ["Data", "Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -1671,16 +1550,14 @@
"display_name": "Parse Data",
"documentation": "",
"edited": false,
- "field_order": [
- "data",
- "template",
- "sep"
- ],
+ "field_order": ["data", "template", "sep"],
"frozen": false,
"icon": "message-square",
"legacy": false,
"lf_version": "1.1.1",
- "metadata": {},
+ "metadata": {
+ "legacy_name": "Parse Data"
+ },
"minimized": false,
"output_types": [],
"outputs": [
@@ -1692,9 +1569,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -1705,9 +1580,7 @@
"name": "data_list",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -1730,7 +1603,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\", is_list=True, required=True),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
+ "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n metadata = {\n \"legacy_name\": \"Parse Data\",\n }\n\n inputs = [\n DataInput(\n name=\"data\",\n display_name=\"Data\",\n info=\"The data to convert to text.\",\n is_list=True,\n required=True,\n ),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
},
"data": {
"_input_type": "DataInput",
@@ -1738,9 +1611,7 @@
"display_name": "Data",
"dynamic": false,
"info": "The data to convert to text.",
- "input_types": [
- "Data"
- ],
+ "input_types": ["Data"],
"list": true,
"name": "data",
"placeholder": "",
@@ -1777,9 +1648,7 @@
"display_name": "Template",
"dynamic": false,
"info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1816,25 +1685,17 @@
"data": {
"id": "Prompt-2M2d5",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
- "template": [
- "context",
- "question"
- ]
+ "template": ["context", "question"]
},
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
"documentation": "",
"edited": false,
- "field_order": [
- "template",
- "tool_placeholder"
- ],
+ "field_order": ["template", "tool_placeholder"],
"frozen": false,
"icon": "prompts",
"legacy": false,
@@ -1850,9 +1711,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1885,10 +1744,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1908,10 +1764,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1947,9 +1800,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -1985,10 +1836,7 @@
"data": {
"id": "OpenAIModel-a26gL",
"node": {
- "base_classes": [
- "LanguageModel",
- "Message"
- ],
+ "base_classes": ["LanguageModel", "Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -2025,9 +1873,7 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -2036,14 +1882,10 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
- "required_inputs": [
- "api_key"
- ],
+ "required_inputs": ["api_key"],
"selected": "LanguageModel",
"tool_mode": true,
- "types": [
- "LanguageModel"
- ],
+ "types": ["LanguageModel"],
"value": "__UNDEFINED__"
}
],
@@ -2056,10 +1898,8 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
- "load_from_db": false,
+ "input_types": ["Message"],
+ "load_from_db": true,
"name": "api_key",
"password": true,
"placeholder": "",
@@ -2067,7 +1907,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"code": {
"advanced": true,
@@ -2093,9 +1933,7 @@
"display_name": "Input",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -2261,9 +2099,7 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "system_message",
@@ -2344,9 +2180,7 @@
"data": {
"id": "ChatOutput-XL9ho",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -2380,9 +2214,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -2395,9 +2227,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -2417,9 +2247,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -2457,9 +2285,7 @@
"display_name": "Data Template",
"dynamic": false,
"info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "data_template",
@@ -2479,9 +2305,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Message to be passed as output.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -2502,10 +2326,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -2521,9 +2342,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -2543,9 +2362,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -2581,9 +2398,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -2619,10 +2434,7 @@
"data": {
"id": "URL-fyWIL",
"node": {
- "base_classes": [
- "Data",
- "Message"
- ],
+ "base_classes": ["Data", "Message"],
"beta": false,
"category": "data",
"conditional_paths": [],
@@ -2631,10 +2443,7 @@
"display_name": "URL",
"documentation": "",
"edited": false,
- "field_order": [
- "urls",
- "format"
- ],
+ "field_order": ["urls", "format"],
"frozen": false,
"icon": "layout-template",
"key": "URL",
@@ -2652,9 +2461,7 @@
"name": "data",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
},
{
@@ -2665,9 +2472,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -2678,9 +2483,7 @@
"name": "dataframe",
"selected": "DataFrame",
"tool_mode": true,
- "types": [
- "DataFrame"
- ],
+ "types": ["DataFrame"],
"value": "__UNDEFINED__"
}
],
@@ -2714,10 +2517,7 @@
"dynamic": false,
"info": "Output Format. Use 'Text' to extract the text from the HTML or 'Raw HTML' for the raw HTML content.",
"name": "format",
- "options": [
- "Text",
- "Raw HTML"
- ],
+ "options": ["Text", "Raw HTML"],
"placeholder": "",
"required": false,
"show": true,
@@ -2733,9 +2533,7 @@
"display_name": "URLs",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": true,
"load_from_db": false,
"name": "urls",
@@ -2787,9 +2585,7 @@
"data": {
"id": "AstraDBGraph-FX0tA",
"node": {
- "base_classes": [
- "Data"
- ],
+ "base_classes": ["Data"],
"beta": false,
"category": "vectorstores",
"conditional_paths": [],
@@ -2837,16 +2633,10 @@
"display_name": "Search Results",
"method": "search_documents",
"name": "search_results",
- "required_inputs": [
- "api_endpoint",
- "collection_name",
- "token"
- ],
+ "required_inputs": ["api_endpoint", "collection_name", "token"],
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
},
{
@@ -2858,9 +2648,7 @@
"required_inputs": [],
"selected": "DataFrame",
"tool_mode": true,
- "types": [
- "DataFrame"
- ],
+ "types": ["DataFrame"],
"value": "__UNDEFINED__"
}
],
@@ -2874,9 +2662,7 @@
"display_name": "API Endpoint",
"dynamic": false,
"info": "API endpoint URL for the Astra DB service.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": false,
"name": "api_endpoint",
"password": true,
@@ -3015,9 +2801,7 @@
"display_name": "Embedding Model",
"dynamic": false,
"info": "Allows an embedding model configuration.",
- "input_types": [
- "Embeddings"
- ],
+ "input_types": ["Embeddings"],
"list": false,
"name": "embedding_model",
"placeholder": "",
@@ -3034,9 +2818,7 @@
"display_name": "Ingest Data",
"dynamic": false,
"info": "",
- "input_types": [
- "Data"
- ],
+ "input_types": ["Data"],
"list": false,
"name": "ingest_data",
"placeholder": "",
@@ -3129,11 +2911,7 @@
"dynamic": false,
"info": "Optional distance metric for vector comparisons in the vector store.",
"name": "metric",
- "options": [
- "cosine",
- "dot_product",
- "euclidean"
- ],
+ "options": ["cosine", "dot_product", "euclidean"],
"placeholder": "",
"required": false,
"show": true,
@@ -3200,9 +2978,7 @@
"display_name": "Search Query",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -3266,10 +3042,7 @@
"dynamic": false,
"info": "Configuration mode for setting up the vector store, with options like 'Sync', or 'Off'.",
"name": "setup_mode",
- "options": [
- "Sync",
- "Off"
- ],
+ "options": ["Sync", "Off"],
"placeholder": "",
"required": false,
"show": true,
@@ -3285,9 +3058,7 @@
"display_name": "Astra DB Application Token",
"dynamic": false,
"info": "Authentication token for accessing Astra DB.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": false,
"name": "token",
"password": true,
@@ -3321,9 +3092,7 @@
"data": {
"id": "LanguageRecursiveTextSplitter-jefpx",
"node": {
- "base_classes": [
- "Data"
- ],
+ "base_classes": ["Data"],
"beta": false,
"category": "langchain_utilities",
"conditional_paths": [],
@@ -3356,9 +3125,7 @@
"required_inputs": [],
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -3469,10 +3236,7 @@
"display_name": "Input",
"dynamic": false,
"info": "The texts to split.",
- "input_types": [
- "Document",
- "Data"
- ],
+ "input_types": ["Document", "Data"],
"list": false,
"name": "data_input",
"placeholder": "",
@@ -3508,9 +3272,7 @@
"data": {
"id": "HtmlLinkExtractor-exHgk",
"node": {
- "base_classes": [
- "Data"
- ],
+ "base_classes": ["Data"],
"beta": false,
"category": "langchain_utilities",
"conditional_paths": [],
@@ -3519,11 +3281,7 @@
"display_name": "HTML Link Extractor",
"documentation": "https://python.langchain.com/v0.2/api_reference/community/graph_vectorstores/langchain_community.graph_vectorstores.extractors.html_link_extractor.HtmlLinkExtractor.html",
"edited": false,
- "field_order": [
- "kind",
- "drop_fragments",
- "data_input"
- ],
+ "field_order": ["kind", "drop_fragments", "data_input"],
"frozen": false,
"icon": "LangChain",
"key": "HtmlLinkExtractor",
@@ -3542,9 +3300,7 @@
"required_inputs": [],
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -3576,10 +3332,7 @@
"display_name": "Input",
"dynamic": false,
"info": "The texts from which to extract links.",
- "input_types": [
- "Document",
- "Data"
- ],
+ "input_types": ["Document", "Data"],
"list": false,
"name": "data_input",
"placeholder": "",
@@ -3650,9 +3403,7 @@
"data": {
"id": "OpenAIEmbeddings-83wEc",
"node": {
- "base_classes": [
- "Embeddings"
- ],
+ "base_classes": ["Embeddings"],
"beta": false,
"category": "embeddings",
"conditional_paths": [],
@@ -3699,14 +3450,10 @@
"display_name": "Embeddings",
"method": "build_embeddings",
"name": "embeddings",
- "required_inputs": [
- "openai_api_key"
- ],
+ "required_inputs": ["openai_api_key"],
"selected": "Embeddings",
"tool_mode": true,
- "types": [
- "Embeddings"
- ],
+ "types": ["Embeddings"],
"value": "__UNDEFINED__"
}
],
@@ -3737,9 +3484,7 @@
"display_name": "Client",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "client",
@@ -3811,9 +3556,7 @@
"display_name": "Deployment",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "deployment",
@@ -3923,9 +3666,7 @@
"display_name": "OpenAI API Base",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_api_base",
@@ -3945,10 +3686,8 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
- "load_from_db": false,
+ "input_types": ["Message"],
+ "load_from_db": true,
"name": "openai_api_key",
"password": true,
"placeholder": "",
@@ -3956,7 +3695,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"openai_api_type": {
"_input_type": "MessageTextInput",
@@ -3964,9 +3703,7 @@
"display_name": "OpenAI API Type",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_api_type",
@@ -3986,9 +3723,7 @@
"display_name": "OpenAI API Version",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_api_version",
@@ -4008,9 +3743,7 @@
"display_name": "OpenAI Organization",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_organization",
@@ -4030,9 +3763,7 @@
"display_name": "OpenAI Proxy",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_proxy",
@@ -4120,9 +3851,7 @@
"display_name": "TikToken Model Name",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tiktoken_model_name",
@@ -4247,8 +3976,5 @@
"is_component": false,
"last_tested_version": "1.1.1",
"name": "Graph RAG",
- "tags": [
- "rag",
- "q-a"
- ]
-}
\ No newline at end of file
+ "tags": ["rag", "q-a"]
+}
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Image Sentiment Analysis.json b/src/backend/base/langflow/initial_setup/starter_projects/Image Sentiment Analysis.json
index e989d5d2d0..5848ada195 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Image Sentiment Analysis.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Image Sentiment Analysis.json
@@ -9,16 +9,12 @@
"dataType": "StructuredOutputComponent",
"id": "StructuredOutputComponent-XYoUc",
"name": "structured_output",
- "output_types": [
- "Data"
- ]
+ "output_types": ["Data"]
},
"targetHandle": {
"fieldName": "data",
"id": "ParseData-HzweJ",
- "inputTypes": [
- "Data"
- ],
+ "inputTypes": ["Data"],
"type": "other"
}
},
@@ -37,16 +33,12 @@
"dataType": "ParseData",
"id": "ParseData-HzweJ",
"name": "text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "ChatOutput-xQxLm",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -64,16 +56,12 @@
"dataType": "ChatInput",
"id": "ChatInput-rAWlE",
"name": "message",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "OpenAIModel-cqeNw",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -91,16 +79,12 @@
"dataType": "Prompt",
"id": "Prompt-AzK6t",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "system_message",
"id": "OpenAIModel-cqeNw",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -118,16 +102,12 @@
"dataType": "OpenAIModel",
"id": "OpenAIModel-cqeNw",
"name": "text_output",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "StructuredOutputComponent-XYoUc",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -145,16 +125,12 @@
"dataType": "OpenAIModel",
"id": "OpenAIModel-cqeNw",
"name": "model_output",
- "output_types": [
- "LanguageModel"
- ]
+ "output_types": ["LanguageModel"]
},
"targetHandle": {
"fieldName": "llm",
"id": "StructuredOutputComponent-XYoUc",
- "inputTypes": [
- "LanguageModel"
- ],
+ "inputTypes": ["LanguageModel"],
"type": "other"
}
},
@@ -173,9 +149,7 @@
"display_name": "Chat Input",
"id": "ChatInput-rAWlE",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -209,9 +183,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -224,9 +196,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -246,9 +216,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -351,10 +319,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -370,9 +335,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -392,9 +355,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -430,9 +391,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -476,9 +435,7 @@
"display_name": "Chat Output",
"id": "ChatOutput-xQxLm",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -512,9 +469,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -527,9 +482,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -549,9 +502,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -589,9 +540,7 @@
"display_name": "Data Template",
"dynamic": false,
"info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "data_template",
@@ -611,9 +560,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Message to be passed as output.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -634,10 +581,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -653,9 +597,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -675,9 +617,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -713,9 +653,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -794,9 +732,7 @@
"display_name": "Structured Output",
"id": "StructuredOutputComponent-XYoUc",
"node": {
- "base_classes": [
- "Data"
- ],
+ "base_classes": ["Data"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -824,9 +760,7 @@
"method": "build_structured_output",
"name": "structured_output",
"selected": "Data",
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -857,9 +791,7 @@
"display_name": "Input message",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -879,9 +811,7 @@
"display_name": "Language Model",
"dynamic": false,
"info": "The language model to use to generate the structured output.",
- "input_types": [
- "LanguageModel"
- ],
+ "input_types": ["LanguageModel"],
"list": false,
"name": "llm",
"placeholder": "",
@@ -1025,9 +955,7 @@
"data": {
"id": "ParseData-HzweJ",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -1035,16 +963,14 @@
"display_name": "Parse Data",
"documentation": "",
"edited": false,
- "field_order": [
- "data",
- "template",
- "sep"
- ],
+ "field_order": ["data", "template", "sep"],
"frozen": false,
"icon": "message-square",
"legacy": false,
"lf_version": "1.0.19.post2",
- "metadata": {},
+ "metadata": {
+ "legacy_name": "Parse Data"
+ },
"output_types": [],
"outputs": [
{
@@ -1055,9 +981,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -1068,9 +992,7 @@
"name": "data_list",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -1093,7 +1015,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\", is_list=True, required=True),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
+ "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n metadata = {\n \"legacy_name\": \"Parse Data\",\n }\n\n inputs = [\n DataInput(\n name=\"data\",\n display_name=\"Data\",\n info=\"The data to convert to text.\",\n is_list=True,\n required=True,\n ),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
},
"data": {
"_input_type": "DataInput",
@@ -1101,9 +1023,7 @@
"display_name": "Data",
"dynamic": false,
"info": "The data to convert to text.",
- "input_types": [
- "Data"
- ],
+ "input_types": ["Data"],
"list": true,
"name": "data",
"placeholder": "",
@@ -1139,9 +1059,7 @@
"display_name": "Template",
"dynamic": false,
"info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1186,9 +1104,7 @@
"display_name": "Prompt",
"id": "Prompt-AzK6t",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
@@ -1198,9 +1114,7 @@
"display_name": "Prompt",
"documentation": "",
"edited": false,
- "field_order": [
- "template"
- ],
+ "field_order": ["template"],
"frozen": false,
"icon": "prompts",
"legacy": false,
@@ -1216,9 +1130,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1267,9 +1179,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -1311,10 +1221,7 @@
"data": {
"id": "OpenAIModel-cqeNw",
"node": {
- "base_classes": [
- "LanguageModel",
- "Message"
- ],
+ "base_classes": ["LanguageModel", "Message"],
"beta": false,
"category": "models",
"conditional_paths": [],
@@ -1353,9 +1260,7 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -1364,14 +1269,10 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
- "required_inputs": [
- "api_key"
- ],
+ "required_inputs": ["api_key"],
"selected": "LanguageModel",
"tool_mode": true,
- "types": [
- "LanguageModel"
- ],
+ "types": ["LanguageModel"],
"value": "__UNDEFINED__"
}
],
@@ -1385,9 +1286,7 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -1396,7 +1295,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"code": {
"advanced": true,
@@ -1422,9 +1321,7 @@
"display_name": "Input",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1606,9 +1503,7 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1704,7 +1599,5 @@
"is_component": false,
"last_tested_version": "1.0.19.post2",
"name": "Image Sentiment Analysis",
- "tags": [
- "classification"
- ]
-}
\ No newline at end of file
+ "tags": ["classification"]
+}
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json b/src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json
index acd12fb9a6..b1e90ea21a 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json
@@ -7,27 +7,22 @@
"data": {
"sourceHandle": {
"dataType": "TextInput",
- "id": "TextInput-Uonj7",
+ "id": "TextInput-OSpmP",
"name": "text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "guidelines",
- "id": "Prompt-DfQRZ",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "id": "Prompt-jlObO",
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
- "id": "reactflow__edge-TextInput-Uonj7{œdataTypeœ:œTextInputœ,œidœ:œTextInput-Uonj7œ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-DfQRZ{œfieldNameœ:œguidelinesœ,œidœ:œPrompt-DfQRZœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
- "source": "TextInput-Uonj7",
- "sourceHandle": "{œdataTypeœ: œTextInputœ, œidœ: œTextInput-Uonj7œ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Prompt-DfQRZ",
- "targetHandle": "{œfieldNameœ: œguidelinesœ, œidœ: œPrompt-DfQRZœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-TextInput-OSpmP{œdataTypeœ:œTextInputœ,œidœ:œTextInput-OSpmPœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-jlObO{œfieldNameœ:œguidelinesœ,œidœ:œPrompt-jlObOœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
+ "source": "TextInput-OSpmP",
+ "sourceHandle": "{œdataTypeœ: œTextInputœ, œidœ: œTextInput-OSpmPœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Prompt-jlObO",
+ "targetHandle": "{œfieldNameœ: œguidelinesœ, œidœ: œPrompt-jlObOœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
},
{
"animated": false,
@@ -35,26 +30,22 @@
"data": {
"sourceHandle": {
"dataType": "ChatInput",
- "id": "ChatInput-ferrV",
+ "id": "ChatInput-jogsq",
"name": "message",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
- "id": "Agent-pNUOq",
- "inputTypes": [
- "Message"
- ],
+ "id": "Agent-NNcr1",
+ "inputTypes": ["Message"],
"type": "str"
}
},
- "id": "reactflow__edge-ChatInput-ferrV{œdataTypeœ:œChatInputœ,œidœ:œChatInput-ferrVœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-pNUOq{œfieldNameœ:œinput_valueœ,œidœ:œAgent-pNUOqœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
- "source": "ChatInput-ferrV",
- "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-ferrVœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Agent-pNUOq",
- "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-pNUOqœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-ChatInput-jogsq{œdataTypeœ:œChatInputœ,œidœ:œChatInput-jogsqœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-NNcr1{œfieldNameœ:œinput_valueœ,œidœ:œAgent-NNcr1œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "ChatInput-jogsq",
+ "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-jogsqœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Agent-NNcr1",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-NNcr1œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"animated": false,
@@ -62,27 +53,22 @@
"data": {
"sourceHandle": {
"dataType": "Agent",
- "id": "Agent-pNUOq",
+ "id": "Agent-NNcr1",
"name": "response",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "context",
- "id": "Prompt-DfQRZ",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "id": "Prompt-jlObO",
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
- "id": "reactflow__edge-Agent-pNUOq{œdataTypeœ:œAgentœ,œidœ:œAgent-pNUOqœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Prompt-DfQRZ{œfieldNameœ:œcontextœ,œidœ:œPrompt-DfQRZœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
- "source": "Agent-pNUOq",
- "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-pNUOqœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Prompt-DfQRZ",
- "targetHandle": "{œfieldNameœ: œcontextœ, œidœ: œPrompt-DfQRZœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-Agent-NNcr1{œdataTypeœ:œAgentœ,œidœ:œAgent-NNcr1œ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Prompt-jlObO{œfieldNameœ:œcontextœ,œidœ:œPrompt-jlObOœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
+ "source": "Agent-NNcr1",
+ "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-NNcr1œ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Prompt-jlObO",
+ "targetHandle": "{œfieldNameœ: œcontextœ, œidœ: œPrompt-jlObOœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
},
{
"animated": false,
@@ -90,195 +76,162 @@
"data": {
"sourceHandle": {
"dataType": "Prompt",
- "id": "Prompt-R9hC2",
+ "id": "Prompt-HtPaM",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
- "id": "ChatOutput-hU0Qy",
- "inputTypes": [
- "Message"
- ],
+ "id": "ChatOutput-L2u2A",
+ "inputTypes": ["Message"],
"type": "str"
}
},
- "id": "reactflow__edge-Prompt-R9hC2{œdataTypeœ:œPromptœ,œidœ:œPrompt-R9hC2œ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-hU0Qy{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-hU0Qyœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
- "source": "Prompt-R9hC2",
- "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-R9hC2œ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
- "target": "ChatOutput-hU0Qy",
- "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-hU0Qyœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-Prompt-HtPaM{œdataTypeœ:œPromptœ,œidœ:œPrompt-HtPaMœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-L2u2A{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-L2u2Aœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "Prompt-HtPaM",
+ "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-HtPaMœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "ChatOutput-L2u2A",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-L2u2Aœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"className": "",
"data": {
"sourceHandle": {
"dataType": "TavilySearchComponent",
- "id": "TavilySearchComponent-h8yAo",
+ "id": "TavilySearchComponent-mnzRD",
"name": "component_as_tool",
- "output_types": [
- "Tool"
- ]
+ "output_types": ["Tool"]
},
"targetHandle": {
"fieldName": "tools",
- "id": "Agent-pNUOq",
- "inputTypes": [
- "Tool"
- ],
+ "id": "Agent-NNcr1",
+ "inputTypes": ["Tool"],
"type": "other"
}
},
- "id": "reactflow__edge-TavilySearchComponent-h8yAo{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-h8yAoœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-pNUOq{œfieldNameœ:œtoolsœ,œidœ:œAgent-pNUOqœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}",
- "source": "TavilySearchComponent-h8yAo",
- "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-h8yAoœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}",
- "target": "Agent-pNUOq",
- "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-pNUOqœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}"
+ "id": "reactflow__edge-TavilySearchComponent-mnzRD{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-mnzRDœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-NNcr1{œfieldNameœ:œtoolsœ,œidœ:œAgent-NNcr1œ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}",
+ "source": "TavilySearchComponent-mnzRD",
+ "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-mnzRDœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}",
+ "target": "Agent-NNcr1",
+ "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-NNcr1œ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}"
},
{
"className": "",
"data": {
"sourceHandle": {
"dataType": "Prompt",
- "id": "Prompt-DfQRZ",
+ "id": "Prompt-jlObO",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
- "id": "OpenAIModel-N7jW7",
- "inputTypes": [
- "Message"
- ],
+ "id": "OpenAIModel-qQ00F",
+ "inputTypes": ["Message"],
"type": "str"
}
},
- "id": "reactflow__edge-Prompt-DfQRZ{œdataTypeœ:œPromptœ,œidœ:œPrompt-DfQRZœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-N7jW7{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-N7jW7œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
- "source": "Prompt-DfQRZ",
- "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-DfQRZœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
- "target": "OpenAIModel-N7jW7",
- "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-N7jW7œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-Prompt-jlObO{œdataTypeœ:œPromptœ,œidœ:œPrompt-jlObOœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-qQ00F{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-qQ00Fœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "Prompt-jlObO",
+ "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-jlObOœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "OpenAIModel-qQ00F",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-qQ00Fœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"className": "",
"data": {
"sourceHandle": {
"dataType": "OpenAIModel",
- "id": "OpenAIModel-N7jW7",
+ "id": "OpenAIModel-qQ00F",
"name": "text_output",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "post",
- "id": "Prompt-OcCWU",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "id": "Prompt-qF4uD",
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
- "id": "reactflow__edge-OpenAIModel-N7jW7{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-N7jW7œ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-OcCWU{œfieldNameœ:œpostœ,œidœ:œPrompt-OcCWUœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
- "source": "OpenAIModel-N7jW7",
- "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-N7jW7œ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Prompt-OcCWU",
- "targetHandle": "{œfieldNameœ: œpostœ, œidœ: œPrompt-OcCWUœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-OpenAIModel-qQ00F{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-qQ00Fœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-qF4uD{œfieldNameœ:œpostœ,œidœ:œPrompt-qF4uDœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
+ "source": "OpenAIModel-qQ00F",
+ "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-qQ00Fœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Prompt-qF4uD",
+ "targetHandle": "{œfieldNameœ: œpostœ, œidœ: œPrompt-qF4uDœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
},
{
"className": "",
"data": {
"sourceHandle": {
"dataType": "OpenAIModel",
- "id": "OpenAIModel-N7jW7",
+ "id": "OpenAIModel-qQ00F",
"name": "text_output",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "post",
- "id": "Prompt-R9hC2",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "id": "Prompt-HtPaM",
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
- "id": "reactflow__edge-OpenAIModel-N7jW7{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-N7jW7œ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-R9hC2{œfieldNameœ:œpostœ,œidœ:œPrompt-R9hC2œ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
- "source": "OpenAIModel-N7jW7",
- "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-N7jW7œ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Prompt-R9hC2",
- "targetHandle": "{œfieldNameœ: œpostœ, œidœ: œPrompt-R9hC2œ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-OpenAIModel-qQ00F{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-qQ00Fœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-HtPaM{œfieldNameœ:œpostœ,œidœ:œPrompt-HtPaMœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
+ "source": "OpenAIModel-qQ00F",
+ "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-qQ00Fœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Prompt-HtPaM",
+ "targetHandle": "{œfieldNameœ: œpostœ, œidœ: œPrompt-HtPaMœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
},
{
"className": "",
"data": {
"sourceHandle": {
"dataType": "Prompt",
- "id": "Prompt-OcCWU",
+ "id": "Prompt-qF4uD",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
- "id": "OpenAIModel-DdNth",
- "inputTypes": [
- "Message"
- ],
+ "id": "OpenAIModel-vHqv4",
+ "inputTypes": ["Message"],
"type": "str"
}
},
- "id": "reactflow__edge-Prompt-OcCWU{œdataTypeœ:œPromptœ,œidœ:œPrompt-OcCWUœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-DdNth{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-DdNthœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
- "source": "Prompt-OcCWU",
- "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-OcCWUœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
- "target": "OpenAIModel-DdNth",
- "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-DdNthœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-Prompt-qF4uD{œdataTypeœ:œPromptœ,œidœ:œPrompt-qF4uDœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-vHqv4{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-vHqv4œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "Prompt-qF4uD",
+ "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-qF4uDœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "OpenAIModel-vHqv4",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-vHqv4œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"className": "",
"data": {
"sourceHandle": {
"dataType": "OpenAIModel",
- "id": "OpenAIModel-DdNth",
+ "id": "OpenAIModel-vHqv4",
"name": "text_output",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "image_description",
- "id": "Prompt-R9hC2",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "id": "Prompt-HtPaM",
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
- "id": "reactflow__edge-OpenAIModel-DdNth{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-DdNthœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-R9hC2{œfieldNameœ:œimage_descriptionœ,œidœ:œPrompt-R9hC2œ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
- "source": "OpenAIModel-DdNth",
- "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-DdNthœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Prompt-R9hC2",
- "targetHandle": "{œfieldNameœ: œimage_descriptionœ, œidœ: œPrompt-R9hC2œ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-OpenAIModel-vHqv4{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-vHqv4œ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-HtPaM{œfieldNameœ:œimage_descriptionœ,œidœ:œPrompt-HtPaMœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
+ "source": "OpenAIModel-vHqv4",
+ "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-vHqv4œ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Prompt-HtPaM",
+ "targetHandle": "{œfieldNameœ: œimage_descriptionœ, œidœ: œPrompt-HtPaMœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
}
],
"nodes": [
{
"data": {
- "id": "ChatInput-ferrV",
+ "id": "ChatInput-jogsq",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -312,9 +265,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -327,9 +278,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -348,9 +297,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -451,10 +398,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -469,9 +413,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -490,9 +432,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -527,9 +467,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -548,10 +486,10 @@
},
"dragging": false,
"height": 234,
- "id": "ChatInput-ferrV",
+ "id": "ChatInput-jogsq",
"measured": {
"height": 234,
- "width": 360
+ "width": 320
},
"position": {
"x": 5183.264962599111,
@@ -569,26 +507,19 @@
"data": {
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
- "id": "Prompt-DfQRZ",
+ "id": "Prompt-jlObO",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
- "template": [
- "context",
- "guidelines"
- ]
+ "template": ["context", "guidelines"]
},
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
"documentation": "",
"edited": false,
- "field_order": [
- "template"
- ],
+ "field_order": ["template"],
"frozen": false,
"icon": "prompts",
"legacy": false,
@@ -604,9 +535,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -639,10 +568,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -662,10 +588,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -701,9 +624,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -724,10 +645,10 @@
},
"dragging": false,
"height": 433,
- "id": "Prompt-DfQRZ",
+ "id": "Prompt-jlObO",
"measured": {
"height": 433,
- "width": 360
+ "width": 320
},
"position": {
"x": 6044.447585613556,
@@ -743,11 +664,9 @@
},
{
"data": {
- "id": "TextInput-Uonj7",
+ "id": "TextInput-OSpmP",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -755,9 +674,7 @@
"display_name": "Text Input",
"documentation": "",
"edited": false,
- "field_order": [
- "input_value"
- ],
+ "field_order": ["input_value"],
"frozen": false,
"icon": "type",
"legacy": false,
@@ -773,9 +690,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -806,9 +721,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Text to be passed as input.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -828,10 +741,10 @@
},
"dragging": false,
"height": 234,
- "id": "TextInput-Uonj7",
+ "id": "TextInput-OSpmP",
"measured": {
"height": 234,
- "width": 360
+ "width": 320
},
"position": {
"x": 5672.768365094557,
@@ -849,25 +762,19 @@
"data": {
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
- "id": "Prompt-OcCWU",
+ "id": "Prompt-qF4uD",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
- "template": [
- "post"
- ]
+ "template": ["post"]
},
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
"documentation": "",
"edited": false,
- "field_order": [
- "template"
- ],
+ "field_order": ["template"],
"frozen": false,
"icon": "prompts",
"legacy": false,
@@ -883,9 +790,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -918,10 +823,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -957,9 +859,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -980,10 +880,10 @@
},
"dragging": false,
"height": 347,
- "id": "Prompt-OcCWU",
+ "id": "Prompt-qF4uD",
"measured": {
"height": 347,
- "width": 360
+ "width": 320
},
"position": {
"x": 6818.9410289594325,
@@ -1001,11 +901,9 @@
"data": {
"description": "Display a chat message in the Playground.",
"display_name": "Chat Output",
- "id": "ChatOutput-hU0Qy",
+ "id": "ChatOutput-L2u2A",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -1038,9 +936,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1053,9 +949,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -1075,9 +969,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -1115,9 +1007,7 @@
"display_name": "Data Template",
"dynamic": false,
"info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "data_template",
@@ -1137,9 +1027,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Message to be passed as output.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -1160,10 +1048,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -1179,9 +1064,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -1201,9 +1084,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -1239,9 +1120,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -1262,10 +1141,10 @@
},
"dragging": false,
"height": 234,
- "id": "ChatOutput-hU0Qy",
+ "id": "ChatOutput-L2u2A",
"measured": {
"height": 234,
- "width": 360
+ "width": 320
},
"position": {
"x": 7980.617825443558,
@@ -1283,11 +1162,9 @@
"data": {
"description": "Define the agent's instructions, then enter a task to complete using tools.",
"display_name": "Agent",
- "id": "Agent-pNUOq",
+ "id": "Agent-NNcr1",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -1337,9 +1214,7 @@
"name": "response",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1368,9 +1243,7 @@
"display_name": "Agent Description [Deprecated]",
"dynamic": false,
"info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1421,9 +1294,7 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -1474,9 +1345,7 @@
"display_name": "Input",
"dynamic": false,
"info": "The input provided by the user for the agent to process.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -1568,9 +1437,7 @@
"display_name": "External Memory",
"dynamic": false,
"info": "Retrieve messages from an external memory. If empty, it will use the Langflow tables.",
- "input_types": [
- "Memory"
- ],
+ "input_types": ["Memory"],
"list": false,
"name": "memory",
"placeholder": "",
@@ -1664,10 +1531,7 @@
"dynamic": false,
"info": "Order of the messages.",
"name": "order",
- "options": [
- "Ascending",
- "Descending"
- ],
+ "options": ["Ascending", "Descending"],
"placeholder": "",
"required": false,
"show": true,
@@ -1701,11 +1565,7 @@
"dynamic": false,
"info": "Filter by sender type.",
"name": "sender",
- "options": [
- "Machine",
- "User",
- "Machine and User"
- ],
+ "options": ["Machine", "User", "Machine and User"],
"placeholder": "",
"required": false,
"show": true,
@@ -1721,9 +1581,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Filter by sender name.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -1743,9 +1601,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -1765,9 +1621,7 @@
"display_name": "Agent Instructions",
"dynamic": false,
"info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1804,9 +1658,7 @@
"display_name": "Template",
"dynamic": false,
"info": "The template to use for formatting the data. It can contain the keys {text}, {sender} or any other key in the message data.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1845,9 +1697,7 @@
"display_name": "Tools",
"dynamic": false,
"info": "These are the tools that the agent can use to help with tasks.",
- "input_types": [
- "Tool"
- ],
+ "input_types": ["Tool"],
"list": true,
"name": "tools",
"placeholder": "",
@@ -1881,10 +1731,10 @@
},
"dragging": false,
"height": 650,
- "id": "Agent-pNUOq",
+ "id": "Agent-NNcr1",
"measured": {
"height": 650,
- "width": 360
+ "width": 320
},
"position": {
"x": 5665.465212822881,
@@ -1902,26 +1752,19 @@
"data": {
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
- "id": "Prompt-R9hC2",
+ "id": "Prompt-HtPaM",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
- "template": [
- "post",
- "image_description"
- ]
+ "template": ["post", "image_description"]
},
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
"documentation": "",
"edited": false,
- "field_order": [
- "template"
- ],
+ "field_order": ["template"],
"frozen": false,
"icon": "prompts",
"legacy": false,
@@ -1937,9 +1780,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1972,10 +1813,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1995,10 +1833,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -2034,9 +1869,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -2057,10 +1890,10 @@
},
"dragging": false,
"height": 433,
- "id": "Prompt-R9hC2",
+ "id": "Prompt-HtPaM",
"measured": {
"height": 433,
- "width": 360
+ "width": 320
},
"position": {
"x": 7613.837241084599,
@@ -2076,7 +1909,7 @@
},
{
"data": {
- "id": "note-grPkG",
+ "id": "note-8p0Lz",
"node": {
"description": "# Instagram Copywriter \n\nWelcome to the Instagram Copywriter! This flow helps you create compelling Instagram posts with AI-generated content and image prompts.\n\n## Instructions\n1. Enter Your Topic\n - In the Chat Input, enter a brief description of the topic you want to post about.\n - Example: \"Create a post about meditation and its benefits\"\n\n2. Review the Generated Content\n - The flow will use AI to research your topic and generate a formatted Instagram post.\n - The post will include an opening line, main content, emojis, a call-to-action, and hashtags.\n\n3. Check the Image Prompt\n - The flow will also generate a detailed image prompt based on your post content.\n - This prompt can be used with image generation tools to create a matching visual.\n\n4. Copy the Final Output\n - The Chat Output will display the complete Instagram post text followed by the image generation prompt.\n - Copy this output to use in your Instagram content creation process.\n\n5. Refine if Needed\n - If you're not satisfied with the result, you can adjust the input or modify the OpenAI model settings for different outputs.\n\nRemember: Keep your initial topic input clear and concise for best results! 🎨✨",
"display_name": "",
@@ -2089,10 +1922,10 @@
},
"dragging": false,
"height": 648,
- "id": "note-grPkG",
+ "id": "note-8p0Lz",
"measured": {
"height": 648,
- "width": 328
+ "width": 555
},
"position": {
"x": 4492.051129290571,
@@ -2113,7 +1946,7 @@
},
{
"data": {
- "id": "note-motsF",
+ "id": "note-yOL03",
"node": {
"description": "**Text Input (Guidelines Prompt)**\n - NOTE: \"Contains Instagram post formatting rules. Don't modify this component as it maintains format consistency.\"\n - Maintains fixed guidelines for:\n * Opening structure\n * Main content\n * Emoji usage\n * Call to Action (CTA)\n * Hashtags\n\n4. **First Prompt + OpenAI Sequence**\n - NOTE: \"Generates initial post content following Instagram guidelines\"\n - Settings:\n * Temperature: 0.7 (good balance between creativity and consistency)\n * Input: Receives research context\n * Output: Generates formatted post text\n\n",
"display_name": "",
@@ -2126,10 +1959,10 @@
},
"dragging": false,
"height": 325,
- "id": "note-motsF",
+ "id": "note-yOL03",
"measured": {
"height": 325,
- "width": 328
+ "width": 326
},
"position": {
"x": 5666.120349284508,
@@ -2146,7 +1979,7 @@
},
{
"data": {
- "id": "note-nnYl4",
+ "id": "note-FH7oq",
"node": {
"description": "**Second Prompt + OpenAI Sequence**\n - NOTE: \"Transforms the generated post into a prompt for image generation\"\n - Settings:\n * Temperature: 0.7\n * Input: Receives generated post\n * Output: Creates detailed description for image generation\n\n",
"display_name": "",
@@ -2159,10 +1992,10 @@
},
"dragging": false,
"height": 325,
- "id": "note-nnYl4",
+ "id": "note-FH7oq",
"measured": {
"height": 325,
- "width": 328
+ "width": 326
},
"position": {
"x": 6786.375917286389,
@@ -2178,7 +2011,7 @@
},
{
"data": {
- "id": "note-Bw2uq",
+ "id": "note-wvs7l",
"node": {
"description": "**Final Prompt**\n - NOTE: \"Combines Instagram post with image prompt in a final format\"\n - Structure:\n * First part: Complete Instagram post\n * Second part: Image generation prompt\n * Separator: Uses \"**Prompt:**\" to divide sections\n\n7. **Chat Output (Final Output)**\n - NOTE: \"Presents the combined final result that can be copied and used directly\"\n\nGENERAL USAGE TIPS:\n- Keep initial inputs clear and specific\n- Don't modify pre-defined Instagram guidelines\n- If style adjustments are needed, only modify the OpenAI models' temperature\n- Verify all connections are correct before running\n- Final result will always have two parts: post + image prompt\n\nFLOW CONSIDERATIONS:\n- All tools connect only to the Tool Calling Agent\n- The flow is unidirectional (no loops)\n- Each prompt template maintains specific formatting\n- Temperatures are set for optimal creativity/consistency balance\n\nTROUBLESHOOTING NOTES:\n- If output is too creative: Lower temperature",
"display_name": "",
@@ -2191,10 +2024,10 @@
},
"dragging": false,
"height": 325,
- "id": "note-Bw2uq",
+ "id": "note-wvs7l",
"measured": {
"height": 325,
- "width": 328
+ "width": 326
},
"position": {
"x": 7606.419013912975,
@@ -2210,7 +2043,7 @@
},
{
"data": {
- "id": "note-wUxWf",
+ "id": "note-Hj9Ay",
"node": {
"description": "# 🔑 Tavily AI Search Needs API Key\n\nYou can get 1000 searches/month free [here](https://tavily.com/) ",
"display_name": "",
@@ -2223,10 +2056,10 @@
},
"dragging": false,
"height": 325,
- "id": "note-wUxWf",
+ "id": "note-Hj9Ay",
"measured": {
"height": 325,
- "width": 328
+ "width": 326
},
"position": {
"x": 5174.678177457385,
@@ -2242,14 +2075,10 @@
},
{
"data": {
- "id": "TavilySearchComponent-h8yAo",
+ "id": "TavilySearchComponent-mnzRD",
"node": {
- "base_classes": [
- "Data",
- "Message"
- ],
+ "base_classes": ["Data", "Message"],
"beta": false,
- "category": "tools",
"conditional_paths": [],
"custom_fields": {},
"description": "**Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.",
@@ -2261,13 +2090,13 @@
"query",
"search_depth",
"topic",
+ "time_range",
"max_results",
"include_images",
"include_answer"
],
"frozen": false,
"icon": "TavilyIcon",
- "key": "TavilySearchComponent",
"legacy": false,
"metadata": {},
"minimized": false,
@@ -2282,14 +2111,12 @@
"name": "component_as_tool",
"required_inputs": null,
"selected": "Tool",
- "types": [
- "Tool"
- ],
+ "tool_mode": true,
+ "types": ["Tool"],
"value": "__UNDEFINED__"
}
],
"pinned": false,
- "score": 0.0075846556637275304,
"template": {
"_type": "Component",
"api_key": {
@@ -2298,9 +2125,7 @@
"display_name": "Tavily API Key",
"dynamic": false,
"info": "Your Tavily API Key.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -2309,7 +2134,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "TAVILY_API_KEY"
},
"code": {
"advanced": true,
@@ -2327,7 +2152,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily AI Search\"\n description = \"\"\"**Tavily AI** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"fetch_content\"),\n Output(display_name=\"Text\", name=\"text\", method=\"fetch_content_text\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n }\n\n with httpx.Client() as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n data_results.append(\n Data(\n text=content,\n data={\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n },\n )\n )\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_text(self) -> Message:\n data = self.fetch_content()\n result_string = data_to_text(\"{text}\", data)\n self.status = result_string\n return Message(text=result_string)\n"
+ "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily AI Search\"\n description = \"\"\"**Tavily AI** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n DropdownInput(\n name=\"time_range\",\n display_name=\"Time Range\",\n info=\"The time range back from the current date to include in the search results.\",\n options=[\"day\", \"week\", \"month\", \"year\"],\n value=None,\n advanced=True,\n combobox=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"fetch_content\"),\n Output(display_name=\"Text\", name=\"text\", method=\"fetch_content_text\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n \"time_range\": self.time_range,\n }\n\n with httpx.Client() as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n data_results.append(\n Data(\n text=content,\n data={\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n },\n )\n )\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_text(self) -> Message:\n data = self.fetch_content()\n result_string = data_to_text(\"{text}\", data)\n self.status = result_string\n return Message(text=result_string)\n"
},
"include_answer": {
"_input_type": "BoolInput",
@@ -2389,9 +2214,7 @@
"display_name": "Search Query",
"dynamic": false,
"info": "The search query you want to execute with Tavily.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -2410,14 +2233,13 @@
"_input_type": "DropdownInput",
"advanced": true,
"combobox": false,
+ "dialog_inputs": {},
"display_name": "Search Depth",
"dynamic": false,
"info": "The depth of the search.",
"name": "search_depth",
- "options": [
- "basic",
- "advanced"
- ],
+ "options": ["basic", "advanced"],
+ "options_metadata": [],
"placeholder": "",
"required": false,
"show": true,
@@ -2427,6 +2249,25 @@
"type": "str",
"value": "advanced"
},
+ "time_range": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": true,
+ "dialog_inputs": {},
+ "display_name": "Time Range",
+ "dynamic": false,
+ "info": "The time range back from the current date to include in the search results.",
+ "name": "time_range",
+ "options": ["day", "week", "month", "year"],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str"
+ },
"tools_metadata": {
"_input_type": "TableInput",
"advanced": false,
@@ -2452,10 +2293,7 @@
"description": "Modify tool names and descriptions to help agents understand when to use each tool.",
"field_parsers": {
"commands": "commands",
- "name": [
- "snake_case",
- "no_blank"
- ]
+ "name": ["snake_case", "no_blank"]
},
"hide_options": true
},
@@ -2468,6 +2306,7 @@
"edit_mode": "inline",
"filterable": false,
"formatter": "text",
+ "hidden": false,
"name": "name",
"sortable": false,
"type": "text"
@@ -2479,6 +2318,7 @@
"edit_mode": "popover",
"filterable": false,
"formatter": "text",
+ "hidden": false,
"name": "description",
"sortable": false,
"type": "text"
@@ -2490,6 +2330,7 @@
"edit_mode": "inline",
"filterable": false,
"formatter": "text",
+ "hidden": true,
"name": "tags",
"sortable": false,
"type": "text"
@@ -2505,17 +2346,13 @@
"value": [
{
"description": "fetch_content(api_key: Message) - **Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.",
- "name": "None-fetch_content",
- "tags": [
- "None-fetch_content"
- ]
+ "name": "TavilySearchComponent-fetch_content",
+ "tags": ["TavilySearchComponent-fetch_content"]
},
{
"description": "fetch_content_text(api_key: Message) - **Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.",
- "name": "None-fetch_content_text",
- "tags": [
- "None-fetch_content_text"
- ]
+ "name": "TavilySearchComponent-fetch_content_text",
+ "tags": ["TavilySearchComponent-fetch_content_text"]
}
]
},
@@ -2523,14 +2360,13 @@
"_input_type": "DropdownInput",
"advanced": true,
"combobox": false,
+ "dialog_inputs": {},
"display_name": "Search Topic",
"dynamic": false,
"info": "The category of the search.",
"name": "topic",
- "options": [
- "general",
- "news"
- ],
+ "options": ["general", "news"],
+ "options_metadata": [],
"placeholder": "",
"required": false,
"show": true,
@@ -2547,10 +2383,10 @@
"type": "TavilySearchComponent"
},
"dragging": false,
- "id": "TavilySearchComponent-h8yAo",
+ "id": "TavilySearchComponent-mnzRD",
"measured": {
- "height": 489,
- "width": 360
+ "height": 435,
+ "width": 320
},
"position": {
"x": 5176.638828210268,
@@ -2561,12 +2397,9 @@
},
{
"data": {
- "id": "OpenAIModel-N7jW7",
+ "id": "OpenAIModel-qQ00F",
"node": {
- "base_classes": [
- "LanguageModel",
- "Message"
- ],
+ "base_classes": ["LanguageModel", "Message"],
"beta": false,
"category": "models",
"conditional_paths": [],
@@ -2605,9 +2438,7 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -2616,14 +2447,10 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
- "required_inputs": [
- "api_key"
- ],
+ "required_inputs": ["api_key"],
"selected": "LanguageModel",
"tool_mode": true,
- "types": [
- "LanguageModel"
- ],
+ "types": ["LanguageModel"],
"value": "__UNDEFINED__"
}
],
@@ -2637,9 +2464,7 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -2674,9 +2499,7 @@
"display_name": "Input",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -2858,9 +2681,7 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -2929,10 +2750,10 @@
"type": "OpenAIModel"
},
"dragging": false,
- "id": "OpenAIModel-N7jW7",
+ "id": "OpenAIModel-qQ00F",
"measured": {
- "height": 734,
- "width": 360
+ "height": 653,
+ "width": 320
},
"position": {
"x": 6411.984293767987,
@@ -2943,12 +2764,9 @@
},
{
"data": {
- "id": "OpenAIModel-DdNth",
+ "id": "OpenAIModel-vHqv4",
"node": {
- "base_classes": [
- "LanguageModel",
- "Message"
- ],
+ "base_classes": ["LanguageModel", "Message"],
"beta": false,
"category": "models",
"conditional_paths": [],
@@ -2987,9 +2805,7 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -2998,14 +2814,10 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
- "required_inputs": [
- "api_key"
- ],
+ "required_inputs": ["api_key"],
"selected": "LanguageModel",
"tool_mode": true,
- "types": [
- "LanguageModel"
- ],
+ "types": ["LanguageModel"],
"value": "__UNDEFINED__"
}
],
@@ -3019,9 +2831,7 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -3056,9 +2866,7 @@
"display_name": "Input",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -3240,9 +3048,7 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -3311,10 +3117,10 @@
"type": "OpenAIModel"
},
"dragging": false,
- "id": "OpenAIModel-DdNth",
+ "id": "OpenAIModel-vHqv4",
"measured": {
- "height": 734,
- "width": 360
+ "height": 653,
+ "width": 320
},
"position": {
"x": 7206.924894456788,
@@ -3325,9 +3131,9 @@
}
],
"viewport": {
- "x": -3779.2997720436124,
- "y": -2148.895244030505,
- "zoom": 0.7375171608018025
+ "x": -1398.4765287647906,
+ "y": -468.6581744031994,
+ "zoom": 0.3251044072386861
}
},
"description": " Create engaging Instagram posts with AI-generated content and image prompts, streamlining social media content creation.",
@@ -3338,9 +3144,5 @@
"is_component": false,
"last_tested_version": "1.0.19.post2",
"name": "Instagram Copywriter",
- "tags": [
- "content-generation",
- "chatbots",
- "agents"
- ]
-}
\ No newline at end of file
+ "tags": ["content-generation", "chatbots", "agents"]
+}
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/LoopTemplate.json b/src/backend/base/langflow/initial_setup/starter_projects/LoopTemplate.json
index de4abf151a..3e715d038b 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/LoopTemplate.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/LoopTemplate.json
@@ -9,16 +9,12 @@
"dataType": "ArXivComponent",
"id": "ArXivComponent-LChQN",
"name": "papers",
- "output_types": [
- "Data"
- ]
+ "output_types": ["Data"]
},
"targetHandle": {
"fieldName": "data",
"id": "LoopComponent-3vpc1",
- "inputTypes": [
- "Data"
- ],
+ "inputTypes": ["Data"],
"type": "other"
}
},
@@ -36,16 +32,12 @@
"dataType": "LoopComponent",
"id": "LoopComponent-3vpc1",
"name": "item",
- "output_types": [
- "Data"
- ]
+ "output_types": ["Data"]
},
"targetHandle": {
"fieldName": "data",
"id": "ParseData-Pf12J",
- "inputTypes": [
- "Data"
- ],
+ "inputTypes": ["Data"],
"type": "other"
}
},
@@ -63,16 +55,12 @@
"dataType": "ParseData",
"id": "ParseData-Pf12J",
"name": "text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "AnthropicModel-beO6B",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -90,16 +78,12 @@
"dataType": "AnthropicModel",
"id": "AnthropicModel-beO6B",
"name": "text_output",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "message",
"id": "MessagetoData-QRSBb",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -117,17 +101,13 @@
"dataType": "MessagetoData",
"id": "MessagetoData-QRSBb",
"name": "data",
- "output_types": [
- "Data"
- ]
+ "output_types": ["Data"]
},
"targetHandle": {
"dataType": "LoopComponent",
"id": "LoopComponent-3vpc1",
"name": "item",
- "output_types": [
- "Data"
- ]
+ "output_types": ["Data"]
}
},
"id": "xy-edge__MessagetoData-QRSBb{œdataTypeœ:œMessagetoDataœ,œidœ:œMessagetoData-QRSBbœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}-LoopComponent-3vpc1{œdataTypeœ:œLoopComponentœ,œidœ:œLoopComponent-3vpc1œ,œnameœ:œitemœ,œoutput_typesœ:[œDataœ]}",
@@ -144,16 +124,12 @@
"dataType": "LoopComponent",
"id": "LoopComponent-3vpc1",
"name": "done",
- "output_types": [
- "Data"
- ]
+ "output_types": ["Data"]
},
"targetHandle": {
"fieldName": "data",
"id": "ParseData-igEkj",
- "inputTypes": [
- "Data"
- ],
+ "inputTypes": ["Data"],
"type": "other"
}
},
@@ -171,16 +147,12 @@
"dataType": "ParseData",
"id": "ParseData-igEkj",
"name": "text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "ChatOutput-UZgon",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -198,16 +170,12 @@
"dataType": "ChatInput",
"id": "ChatInput-m10vc",
"name": "message",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "search_query",
"id": "ArXivComponent-LChQN",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -223,9 +191,7 @@
"data": {
"id": "ArXivComponent-LChQN",
"node": {
- "base_classes": [
- "Data"
- ],
+ "base_classes": ["Data"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -233,11 +199,7 @@
"display_name": "arXiv",
"documentation": "",
"edited": false,
- "field_order": [
- "search_query",
- "search_type",
- "max_results"
- ],
+ "field_order": ["search_query", "search_type", "max_results"],
"frozen": false,
"icon": "arXiv",
"legacy": false,
@@ -254,9 +216,7 @@
"name": "papers",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -305,9 +265,7 @@
"display_name": "Search Query",
"dynamic": false,
"info": "The search query for arXiv papers (e.g., 'quantum computing')",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -331,13 +289,7 @@
"dynamic": false,
"info": "The field to search in",
"name": "search_type",
- "options": [
- "all",
- "title",
- "abstract",
- "author",
- "cat"
- ],
+ "options": ["all", "title", "abstract", "author", "cat"],
"options_metadata": [],
"placeholder": "",
"required": false,
@@ -371,9 +323,7 @@
"data": {
"id": "LoopComponent-3vpc1",
"node": {
- "base_classes": [
- "Data"
- ],
+ "base_classes": ["Data"],
"beta": false,
"category": "logic",
"conditional_paths": [],
@@ -382,9 +332,7 @@
"display_name": "Loop",
"documentation": "",
"edited": false,
- "field_order": [
- "data"
- ],
+ "field_order": ["data"],
"frozen": false,
"icon": "infinity",
"key": "LoopComponent",
@@ -402,9 +350,7 @@
"name": "item",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
},
{
@@ -415,9 +361,7 @@
"name": "done",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -449,9 +393,7 @@
"display_name": "Data",
"dynamic": false,
"info": "The initial list of Data objects to iterate over.",
- "input_types": [
- "Data"
- ],
+ "input_types": ["Data"],
"list": false,
"list_add_label": "Add More",
"name": "data",
@@ -488,10 +430,7 @@
"data": {
"id": "ParseData-Pf12J",
"node": {
- "base_classes": [
- "Data",
- "Message"
- ],
+ "base_classes": ["Data", "Message"],
"beta": false,
"category": "processing",
"conditional_paths": [],
@@ -500,17 +439,15 @@
"display_name": "Data to Message",
"documentation": "",
"edited": false,
- "field_order": [
- "data",
- "template",
- "sep"
- ],
+ "field_order": ["data", "template", "sep"],
"frozen": false,
"icon": "message-square",
"key": "ParseData",
"legacy": false,
"lf_version": "1.1.5",
- "metadata": {},
+ "metadata": {
+ "legacy_name": "Parse Data"
+ },
"minimized": false,
"output_types": [],
"outputs": [
@@ -522,9 +459,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -535,9 +470,7 @@
"name": "data_list",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -561,7 +494,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\", is_list=True, required=True),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
+ "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n metadata = {\n \"legacy_name\": \"Parse Data\",\n }\n\n inputs = [\n DataInput(\n name=\"data\",\n display_name=\"Data\",\n info=\"The data to convert to text.\",\n is_list=True,\n required=True,\n ),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
},
"data": {
"_input_type": "DataInput",
@@ -569,9 +502,7 @@
"display_name": "Data",
"dynamic": false,
"info": "The data to convert to text.",
- "input_types": [
- "Data"
- ],
+ "input_types": ["Data"],
"list": true,
"list_add_label": "Add More",
"name": "data",
@@ -610,9 +541,7 @@
"display_name": "Template",
"dynamic": false,
"info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -651,10 +580,7 @@
"data": {
"id": "AnthropicModel-beO6B",
"node": {
- "base_classes": [
- "LanguageModel",
- "Message"
- ],
+ "base_classes": ["LanguageModel", "Message"],
"beta": false,
"category": "models",
"conditional_paths": [],
@@ -693,9 +619,7 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -704,14 +628,10 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
- "required_inputs": [
- "api_key"
- ],
+ "required_inputs": ["api_key"],
"selected": "LanguageModel",
"tool_mode": true,
- "types": [
- "LanguageModel"
- ],
+ "types": ["LanguageModel"],
"value": "__UNDEFINED__"
}
],
@@ -725,9 +645,7 @@
"display_name": "Anthropic API Key",
"dynamic": false,
"info": "Your Anthropic API key.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -737,7 +655,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "ANTHROPIC_API_KEY"
},
"base_url": {
"_input_type": "MessageTextInput",
@@ -745,9 +663,7 @@
"display_name": "Anthropic API URL",
"dynamic": false,
"info": "Endpoint of the Anthropic API. Defaults to 'https://api.anthropic.com' if not specified.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -787,9 +703,7 @@
"display_name": "Input",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -858,9 +772,7 @@
"display_name": "Prefill",
"dynamic": false,
"info": "Prefill text to guide the model's response.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -899,9 +811,7 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -987,9 +897,7 @@
"data": {
"id": "MessagetoData-QRSBb",
"node": {
- "base_classes": [
- "Data"
- ],
+ "base_classes": ["Data"],
"beta": true,
"category": "processing",
"conditional_paths": [],
@@ -998,9 +906,7 @@
"display_name": "Message to Data",
"documentation": "",
"edited": false,
- "field_order": [
- "message"
- ],
+ "field_order": ["message"],
"frozen": false,
"icon": "message-square-share",
"key": "MessagetoData",
@@ -1018,9 +924,7 @@
"name": "data",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -1052,9 +956,7 @@
"display_name": "Message",
"dynamic": false,
"info": "The Message object to convert to a Data object",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1092,10 +994,7 @@
"data": {
"id": "ParseData-igEkj",
"node": {
- "base_classes": [
- "Data",
- "Message"
- ],
+ "base_classes": ["Data", "Message"],
"beta": false,
"category": "processing",
"conditional_paths": [],
@@ -1104,17 +1003,15 @@
"display_name": "Data to Message",
"documentation": "",
"edited": false,
- "field_order": [
- "data",
- "template",
- "sep"
- ],
+ "field_order": ["data", "template", "sep"],
"frozen": false,
"icon": "message-square",
"key": "ParseData",
"legacy": false,
"lf_version": "1.1.5",
- "metadata": {},
+ "metadata": {
+ "legacy_name": "Parse Data"
+ },
"minimized": false,
"output_types": [],
"outputs": [
@@ -1126,9 +1023,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -1139,9 +1034,7 @@
"name": "data_list",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -1165,7 +1058,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\", is_list=True, required=True),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
+ "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n metadata = {\n \"legacy_name\": \"Parse Data\",\n }\n\n inputs = [\n DataInput(\n name=\"data\",\n display_name=\"Data\",\n info=\"The data to convert to text.\",\n is_list=True,\n required=True,\n ),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
},
"data": {
"_input_type": "DataInput",
@@ -1173,9 +1066,7 @@
"display_name": "Data",
"dynamic": false,
"info": "The data to convert to text.",
- "input_types": [
- "Data"
- ],
+ "input_types": ["Data"],
"list": true,
"list_add_label": "Add More",
"name": "data",
@@ -1214,9 +1105,7 @@
"display_name": "Template",
"dynamic": false,
"info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1255,9 +1144,7 @@
"data": {
"id": "ChatOutput-UZgon",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -1292,9 +1179,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1307,9 +1192,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1330,9 +1213,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1371,9 +1252,7 @@
"display_name": "Data Template",
"dynamic": false,
"info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1394,9 +1273,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Message to be passed as output.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1420,10 +1297,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"options_metadata": [],
"placeholder": "",
"required": false,
@@ -1440,9 +1314,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1463,9 +1335,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1504,9 +1374,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1544,9 +1412,7 @@
"data": {
"id": "ChatInput-m10vc",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -1581,9 +1447,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1596,9 +1460,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1619,9 +1481,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1728,10 +1588,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"options_metadata": [],
"placeholder": "",
"required": false,
@@ -1748,9 +1605,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1771,9 +1626,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1812,9 +1665,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1919,8 +1770,5 @@
"is_component": false,
"last_tested_version": "1.1.5",
"name": "Research Translation Loop",
- "tags": [
- "chatbots",
- "content-generation"
- ]
-}
\ No newline at end of file
+ "tags": ["chatbots", "content-generation"]
+}
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Market Research.json b/src/backend/base/langflow/initial_setup/starter_projects/Market Research.json
index 8b1255c976..3b4a38c363 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Market Research.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Market Research.json
@@ -3,167 +3,145 @@
"edges": [
{
"animated": false,
- "className": "",
+ "className": "not-running",
"data": {
"sourceHandle": {
"dataType": "StructuredOutputComponent",
- "id": "StructuredOutputComponent-y5YEE",
+ "id": "StructuredOutputComponent-EguHE",
"name": "structured_output",
- "output_types": [
- "Data"
- ]
+ "output_types": ["Data"]
},
"targetHandle": {
"fieldName": "data",
- "id": "ParseData-8KK2E",
- "inputTypes": [
- "Data"
- ],
+ "id": "ParseData-68wKj",
+ "inputTypes": ["Data"],
"type": "other"
}
},
- "id": "reactflow__edge-StructuredOutputComponent-y5YEE{œdataTypeœ:œStructuredOutputComponentœ,œidœ:œStructuredOutputComponent-y5YEEœ,œnameœ:œstructured_outputœ,œoutput_typesœ:[œDataœ]}-ParseData-8KK2E{œfieldNameœ:œdataœ,œidœ:œParseData-8KK2Eœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}",
+ "id": "reactflow__edge-StructuredOutputComponent-EguHE{œdataTypeœ:œStructuredOutputComponentœ,œidœ:œStructuredOutputComponent-EguHEœ,œnameœ:œstructured_outputœ,œoutput_typesœ:[œDataœ]}-ParseData-68wKj{œfieldNameœ:œdataœ,œidœ:œParseData-68wKjœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}",
"selected": false,
- "source": "StructuredOutputComponent-y5YEE",
- "sourceHandle": "{œdataTypeœ: œStructuredOutputComponentœ, œidœ: œStructuredOutputComponent-y5YEEœ, œnameœ: œstructured_outputœ, œoutput_typesœ: [œDataœ]}",
- "target": "ParseData-8KK2E",
- "targetHandle": "{œfieldNameœ: œdataœ, œidœ: œParseData-8KK2Eœ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}"
+ "source": "StructuredOutputComponent-EguHE",
+ "sourceHandle": "{œdataTypeœ: œStructuredOutputComponentœ, œidœ: œStructuredOutputComponent-EguHEœ, œnameœ: œstructured_outputœ, œoutput_typesœ: [œDataœ]}",
+ "target": "ParseData-68wKj",
+ "targetHandle": "{œfieldNameœ: œdataœ, œidœ: œParseData-68wKjœ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}"
},
{
"animated": false,
- "className": "",
+ "className": "not-running",
"data": {
"sourceHandle": {
"dataType": "ParseData",
- "id": "ParseData-8KK2E",
+ "id": "ParseData-68wKj",
"name": "text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
- "id": "ChatOutput-gEsYh",
- "inputTypes": [
- "Message"
- ],
+ "id": "ChatOutput-VA5gt",
+ "inputTypes": ["Message"],
"type": "str"
}
},
- "id": "reactflow__edge-ParseData-8KK2E{œdataTypeœ:œParseDataœ,œidœ:œParseData-8KK2Eœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-gEsYh{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-gEsYhœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "id": "reactflow__edge-ParseData-68wKj{œdataTypeœ:œParseDataœ,œidœ:œParseData-68wKjœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-VA5gt{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-VA5gtœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
"selected": false,
- "source": "ParseData-8KK2E",
- "sourceHandle": "{œdataTypeœ: œParseDataœ, œidœ: œParseData-8KK2Eœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}",
- "target": "ChatOutput-gEsYh",
- "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-gEsYhœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "source": "ParseData-68wKj",
+ "sourceHandle": "{œdataTypeœ: œParseDataœ, œidœ: œParseData-68wKjœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "ChatOutput-VA5gt",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-VA5gtœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"animated": false,
- "className": "",
+ "className": "ran",
"data": {
"sourceHandle": {
"dataType": "ChatInput",
- "id": "ChatInput-vuvZ4",
+ "id": "ChatInput-FDuyL",
"name": "message",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
- "id": "Agent-lyqby",
- "inputTypes": [
- "Message"
- ],
+ "id": "Agent-rqbrW",
+ "inputTypes": ["Message"],
"type": "str"
}
},
- "id": "reactflow__edge-ChatInput-vuvZ4{œdataTypeœ:œChatInputœ,œidœ:œChatInput-vuvZ4œ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-lyqby{œfieldNameœ:œinput_valueœ,œidœ:œAgent-lyqbyœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "id": "reactflow__edge-ChatInput-FDuyL{œdataTypeœ:œChatInputœ,œidœ:œChatInput-FDuyLœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-rqbrW{œfieldNameœ:œinput_valueœ,œidœ:œAgent-rqbrWœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
"selected": false,
- "source": "ChatInput-vuvZ4",
- "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-vuvZ4œ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Agent-lyqby",
- "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-lyqbyœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "source": "ChatInput-FDuyL",
+ "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-FDuyLœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Agent-rqbrW",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-rqbrWœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
- "animated": false,
- "className": "",
+ "animated": true,
+ "className": "running",
"data": {
"sourceHandle": {
"dataType": "Agent",
- "id": "Agent-lyqby",
+ "id": "Agent-rqbrW",
"name": "response",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
- "id": "StructuredOutputComponent-y5YEE",
- "inputTypes": [
- "Message"
- ],
+ "id": "StructuredOutputComponent-EguHE",
+ "inputTypes": ["Message"],
"type": "str"
}
},
- "id": "reactflow__edge-Agent-lyqby{œdataTypeœ:œAgentœ,œidœ:œAgent-lyqbyœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-StructuredOutputComponent-y5YEE{œfieldNameœ:œinput_valueœ,œidœ:œStructuredOutputComponent-y5YEEœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "id": "reactflow__edge-Agent-rqbrW{œdataTypeœ:œAgentœ,œidœ:œAgent-rqbrWœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-StructuredOutputComponent-EguHE{œfieldNameœ:œinput_valueœ,œidœ:œStructuredOutputComponent-EguHEœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
"selected": false,
- "source": "Agent-lyqby",
- "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-lyqbyœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
- "target": "StructuredOutputComponent-y5YEE",
- "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œStructuredOutputComponent-y5YEEœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "source": "Agent-rqbrW",
+ "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-rqbrWœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "StructuredOutputComponent-EguHE",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œStructuredOutputComponent-EguHEœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"animated": false,
- "className": "",
+ "className": "ran",
"data": {
"sourceHandle": {
"dataType": "TavilySearchComponent",
- "id": "TavilySearchComponent-Gv4zn",
+ "id": "TavilySearchComponent-EoHje",
"name": "component_as_tool",
- "output_types": [
- "Tool"
- ]
+ "output_types": ["Tool"]
},
"targetHandle": {
"fieldName": "tools",
- "id": "Agent-lyqby",
- "inputTypes": [
- "Tool"
- ],
+ "id": "Agent-rqbrW",
+ "inputTypes": ["Tool"],
"type": "other"
}
},
- "id": "reactflow__edge-TavilySearchComponent-Gv4zn{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-Gv4znœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-lyqby{œfieldNameœ:œtoolsœ,œidœ:œAgent-lyqbyœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}",
- "source": "TavilySearchComponent-Gv4zn",
- "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-Gv4znœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}",
- "target": "Agent-lyqby",
- "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-lyqbyœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}"
+ "id": "reactflow__edge-TavilySearchComponent-EoHje{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-EoHjeœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-rqbrW{œfieldNameœ:œtoolsœ,œidœ:œAgent-rqbrWœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}",
+ "source": "TavilySearchComponent-EoHje",
+ "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-EoHjeœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}",
+ "target": "Agent-rqbrW",
+ "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-rqbrWœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}"
},
{
+ "animated": false,
+ "className": "not-running",
"data": {
"sourceHandle": {
"dataType": "OpenAIModel",
- "id": "OpenAIModel-Yo7s2",
+ "id": "OpenAIModel-aSzMF",
"name": "model_output",
- "output_types": [
- "LanguageModel"
- ]
+ "output_types": ["LanguageModel"]
},
"targetHandle": {
"fieldName": "llm",
- "id": "StructuredOutputComponent-y5YEE",
- "inputTypes": [
- "LanguageModel"
- ],
+ "id": "StructuredOutputComponent-EguHE",
+ "inputTypes": ["LanguageModel"],
"type": "other"
}
},
- "id": "xy-edge__OpenAIModel-Yo7s2{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-Yo7s2œ,œnameœ:œmodel_outputœ,œoutput_typesœ:[œLanguageModelœ]}-StructuredOutputComponent-y5YEE{œfieldNameœ:œllmœ,œidœ:œStructuredOutputComponent-y5YEEœ,œinputTypesœ:[œLanguageModelœ],œtypeœ:œotherœ}",
- "source": "OpenAIModel-Yo7s2",
- "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-Yo7s2œ, œnameœ: œmodel_outputœ, œoutput_typesœ: [œLanguageModelœ]}",
- "target": "StructuredOutputComponent-y5YEE",
- "targetHandle": "{œfieldNameœ: œllmœ, œidœ: œStructuredOutputComponent-y5YEEœ, œinputTypesœ: [œLanguageModelœ], œtypeœ: œotherœ}"
+ "id": "reactflow__edge-OpenAIModel-aSzMF{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-aSzMFœ,œnameœ:œmodel_outputœ,œoutput_typesœ:[œLanguageModelœ]}-StructuredOutputComponent-EguHE{œfieldNameœ:œllmœ,œidœ:œStructuredOutputComponent-EguHEœ,œinputTypesœ:[œLanguageModelœ],œtypeœ:œotherœ}",
+ "source": "OpenAIModel-aSzMF",
+ "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-aSzMFœ, œnameœ: œmodel_outputœ, œoutput_typesœ: [œLanguageModelœ]}",
+ "target": "StructuredOutputComponent-EguHE",
+ "targetHandle": "{œfieldNameœ: œllmœ, œidœ: œStructuredOutputComponent-EguHEœ, œinputTypesœ: [œLanguageModelœ], œtypeœ: œotherœ}"
}
],
"nodes": [
@@ -171,11 +149,9 @@
"data": {
"description": "Get chat inputs from the Playground.",
"display_name": "Chat Input",
- "id": "ChatInput-vuvZ4",
+ "id": "ChatInput-FDuyL",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -209,9 +185,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -224,9 +198,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -245,9 +217,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -348,10 +318,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -366,9 +333,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -387,9 +352,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -424,9 +387,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -445,10 +406,10 @@
},
"dragging": false,
"height": 234,
- "id": "ChatInput-vuvZ4",
+ "id": "ChatInput-FDuyL",
"measured": {
"height": 234,
- "width": 360
+ "width": 320
},
"position": {
"x": 472.38251755471583,
@@ -466,11 +427,9 @@
"data": {
"description": "Display a chat message in the Playground.",
"display_name": "Chat Output",
- "id": "ChatOutput-gEsYh",
+ "id": "ChatOutput-VA5gt",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -504,9 +463,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -519,9 +476,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -541,9 +496,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -581,9 +534,7 @@
"display_name": "Data Template",
"dynamic": false,
"info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "data_template",
@@ -603,9 +554,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Message to be passed as output.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -626,10 +575,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -645,9 +591,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -667,9 +611,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -705,9 +647,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -728,10 +668,10 @@
},
"dragging": false,
"height": 234,
- "id": "ChatOutput-gEsYh",
+ "id": "ChatOutput-VA5gt",
"measured": {
"height": 234,
- "width": 360
+ "width": 320
},
"position": {
"x": 2518.282039019285,
@@ -747,7 +687,7 @@
},
{
"data": {
- "id": "note-siDHB",
+ "id": "note-nklZw",
"node": {
"description": "The StructuredOutputComponent, when utilized with our company information schema, performs the following functions:\n\n1. Accepts an input query regarding a company.\n2. Employs a Language Model (LLM) to analyze the query.\n3. Instructs the LLM to generate a structured response adhering to the predefined schema:\n - Domain\n - LinkedIn URL\n - Cheapest Plan\n - Has Free Trial\n - Has Enterprise Plan\n - Has API\n - Market\n - Pricing Tiers\n - Key Features\n - Target Industries\n\n4. Validates the LLM output against this schema.\n5. Returns a Data object containing the company information structured according to the schema.\n\nIn essence, this component transforms a free-text query about a company into a structured, consistent dataset, facilitating subsequent analysis and application of the information.",
"display_name": "",
@@ -760,10 +700,10 @@
},
"dragging": false,
"height": 324,
- "id": "note-siDHB",
+ "id": "note-nklZw",
"measured": {
"height": 324,
- "width": 324
+ "width": 325
},
"position": {
"x": 2089.5869930853464,
@@ -784,7 +724,7 @@
},
{
"data": {
- "id": "note-gjsCT",
+ "id": "note-PXFPj",
"node": {
"description": "PURPOSE:\nConverts unstructured company research into standardized JSON format\n\nKEY FUNCTIONS:\n- Extracts specific business data points\n- Validates and formats information\n- Ensures data consistency\n\nINPUT:\n- Raw company research data\n\nOUTPUT:\nStructured JSON with:\n- Domain information\n- Social links\n- Pricing details\n- Feature availability\n- Market classification\n- Product features\n- Industry focus\n\nRULES:\n1. Uses strict boolean values\n2. Standardizes pricing formats\n3. Validates market categories\n4. Handles missing data consistently",
"display_name": "",
@@ -797,10 +737,10 @@
},
"dragging": false,
"height": 324,
- "id": "note-gjsCT",
+ "id": "note-PXFPj",
"measured": {
"height": 324,
- "width": 324
+ "width": 325
},
"position": {
"x": 1237.6627823432912,
@@ -821,7 +761,7 @@
},
{
"data": {
- "id": "note-IftyY",
+ "id": "note-TgJSC",
"node": {
"description": "# Market Research\nThis flow helps you gather comprehensive information about companies for sales and business intelligence purposes.\n\n## Instructions\n\n1. Enter Company Name\n - In the Chat Input node, type the name of the company you want to research\n - Example inputs: \"Salesforce.com\", \"Shopify\", \"Zoom Video Communications\"\n\n2. Initiate Research\n - The Agent will use the Tavily AI Search tool to gather information\n - It will focus on key areas like pricing, features, and market positioning\n\n3. Review Structured Output\n - The flow will generate a structured JSON output with standardized fields\n - This includes domain, LinkedIn URL, pricing details, and key features\n\n4. Examine Formatted Results\n - The Parse Data component will convert the JSON into a readable format\n - You'll see a comprehensive company profile with organized sections\n\n5. Analyze and Use Data\n - Use the generated information for sales prospecting, competitive analysis, or market research\n - The structured format allows for easy comparison between different companies\n\nRemember: Always verify critical information from official sources before making business decisions! 🔍💼",
"display_name": "",
@@ -834,10 +774,10 @@
},
"dragging": false,
"height": 324,
- "id": "note-IftyY",
+ "id": "note-TgJSC",
"measured": {
"height": 324,
- "width": 324
+ "width": 325
},
"position": {
"x": 244.92297036777086,
@@ -860,11 +800,9 @@
"data": {
"description": "Transforms LLM responses into **structured data formats**. Ideal for extracting specific information or creating consistent outputs.",
"display_name": "Structured Output",
- "id": "StructuredOutputComponent-y5YEE",
+ "id": "StructuredOutputComponent-EguHE",
"node": {
- "base_classes": [
- "Data"
- ],
+ "base_classes": ["Data"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -892,9 +830,7 @@
"method": "build_structured_output",
"name": "structured_output",
"selected": "Data",
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -925,9 +861,7 @@
"display_name": "Input message",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -947,9 +881,7 @@
"display_name": "Language Model",
"dynamic": false,
"info": "The language model to use to generate the structured output.",
- "input_types": [
- "LanguageModel"
- ],
+ "input_types": ["LanguageModel"],
"list": false,
"name": "llm",
"placeholder": "",
@@ -1120,10 +1052,10 @@
},
"dragging": false,
"height": 541,
- "id": "StructuredOutputComponent-y5YEE",
+ "id": "StructuredOutputComponent-EguHE",
"measured": {
"height": 541,
- "width": 360
+ "width": 320
},
"position": {
"x": 1716.7237308033855,
@@ -1139,11 +1071,9 @@
},
{
"data": {
- "id": "ParseData-8KK2E",
+ "id": "ParseData-68wKj",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"category": "helpers",
"conditional_paths": [],
@@ -1152,17 +1082,15 @@
"display_name": "Parse Data",
"documentation": "",
"edited": false,
- "field_order": [
- "data",
- "template",
- "sep"
- ],
+ "field_order": ["data", "template", "sep"],
"frozen": false,
"icon": "message-square",
"key": "ParseData",
"legacy": false,
"lf_version": "1.1.1",
- "metadata": {},
+ "metadata": {
+ "legacy_name": "Parse Data"
+ },
"output_types": [],
"outputs": [
{
@@ -1173,9 +1101,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -1186,9 +1112,7 @@
"name": "data_list",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -1211,7 +1135,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\", is_list=True, required=True),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
+ "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n metadata = {\n \"legacy_name\": \"Parse Data\",\n }\n\n inputs = [\n DataInput(\n name=\"data\",\n display_name=\"Data\",\n info=\"The data to convert to text.\",\n is_list=True,\n required=True,\n ),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
},
"data": {
"_input_type": "DataInput",
@@ -1219,9 +1143,7 @@
"display_name": "Data",
"dynamic": false,
"info": "The data to convert to text.",
- "input_types": [
- "Data"
- ],
+ "input_types": ["Data"],
"list": true,
"name": "data",
"placeholder": "",
@@ -1256,9 +1178,7 @@
"display_name": "Template",
"dynamic": false,
"info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1278,10 +1198,10 @@
},
"dragging": false,
"height": 302,
- "id": "ParseData-8KK2E",
+ "id": "ParseData-68wKj",
"measured": {
"height": 302,
- "width": 360
+ "width": 320
},
"position": {
"x": 2139.05558520377,
@@ -1299,11 +1219,9 @@
"data": {
"description": "Define the agent's instructions, then enter a task to complete using tools.",
"display_name": "Agent",
- "id": "Agent-lyqby",
+ "id": "Agent-rqbrW",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -1354,9 +1272,7 @@
"name": "response",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1385,9 +1301,7 @@
"display_name": "Agent Description [Deprecated]",
"dynamic": false,
"info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1438,9 +1352,7 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -1449,7 +1361,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": "OPENAI_API_KEY"
+ "value": "TAVILY_API_KEY"
},
"code": {
"advanced": true,
@@ -1491,9 +1403,7 @@
"display_name": "Input",
"dynamic": false,
"info": "The input provided by the user for the agent to process.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -1585,9 +1495,7 @@
"display_name": "External Memory",
"dynamic": false,
"info": "Retrieve messages from an external memory. If empty, it will use the Langflow tables.",
- "input_types": [
- "Memory"
- ],
+ "input_types": ["Memory"],
"list": false,
"name": "memory",
"placeholder": "",
@@ -1681,10 +1589,7 @@
"dynamic": false,
"info": "Order of the messages.",
"name": "order",
- "options": [
- "Ascending",
- "Descending"
- ],
+ "options": ["Ascending", "Descending"],
"placeholder": "",
"required": false,
"show": true,
@@ -1718,11 +1623,7 @@
"dynamic": false,
"info": "Filter by sender type.",
"name": "sender",
- "options": [
- "Machine",
- "User",
- "Machine and User"
- ],
+ "options": ["Machine", "User", "Machine and User"],
"placeholder": "",
"required": false,
"show": true,
@@ -1738,9 +1639,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Filter by sender name.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -1760,9 +1659,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -1782,9 +1679,7 @@
"display_name": "Agent Instructions",
"dynamic": false,
"info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1821,9 +1716,7 @@
"display_name": "Template",
"dynamic": false,
"info": "The template to use for formatting the data. It can contain the keys {text}, {sender} or any other key in the message data.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1862,9 +1755,7 @@
"display_name": "Tools",
"dynamic": false,
"info": "These are the tools that the agent can use to help with tasks.",
- "input_types": [
- "Tool"
- ],
+ "input_types": ["Tool"],
"list": true,
"name": "tools",
"placeholder": "",
@@ -1898,10 +1789,10 @@
},
"dragging": false,
"height": 650,
- "id": "Agent-lyqby",
+ "id": "Agent-rqbrW",
"measured": {
"height": 650,
- "width": 360
+ "width": 320
},
"position": {
"x": 1287.5681517817056,
@@ -1913,7 +1804,7 @@
},
{
"data": {
- "id": "note-Z3HC2",
+ "id": "note-KpRgA",
"node": {
"description": "# 🔑 Tavily AI Search Needs API Key\n\nYou can get 1000 searches/month free [here](https://tavily.com/) ",
"display_name": "",
@@ -1926,10 +1817,10 @@
},
"dragging": false,
"height": 324,
- "id": "note-Z3HC2",
+ "id": "note-KpRgA",
"measured": {
"height": 324,
- "width": 324
+ "width": 325
},
"position": {
"x": 878.7898510090017,
@@ -1945,14 +1836,12 @@
},
{
"data": {
- "id": "TavilySearchComponent-Gv4zn",
+ "description": "**Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.",
+ "display_name": "Tavily AI Search",
+ "id": "TavilySearchComponent-EoHje",
"node": {
- "base_classes": [
- "Data",
- "Message"
- ],
+ "base_classes": ["Data", "Message"],
"beta": false,
- "category": "tools",
"conditional_paths": [],
"custom_fields": {},
"description": "**Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.",
@@ -1964,15 +1853,14 @@
"query",
"search_depth",
"topic",
+ "time_range",
"max_results",
"include_images",
"include_answer"
],
"frozen": false,
"icon": "TavilyIcon",
- "key": "TavilySearchComponent",
"legacy": false,
- "lf_version": "1.1.1",
"metadata": {},
"minimized": false,
"output_types": [],
@@ -1986,14 +1874,12 @@
"name": "component_as_tool",
"required_inputs": null,
"selected": "Tool",
- "types": [
- "Tool"
- ],
+ "tool_mode": true,
+ "types": ["Tool"],
"value": "__UNDEFINED__"
}
],
"pinned": false,
- "score": 0.0075846556637275304,
"template": {
"_type": "Component",
"api_key": {
@@ -2002,9 +1888,7 @@
"display_name": "Tavily API Key",
"dynamic": false,
"info": "Your Tavily API Key.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -2013,7 +1897,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "TAVILY_API_KEY"
},
"code": {
"advanced": true,
@@ -2031,7 +1915,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily AI Search\"\n description = \"\"\"**Tavily AI** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"fetch_content\"),\n Output(display_name=\"Text\", name=\"text\", method=\"fetch_content_text\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n }\n\n with httpx.Client() as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n data_results.append(\n Data(\n text=content,\n data={\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n },\n )\n )\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_text(self) -> Message:\n data = self.fetch_content()\n result_string = data_to_text(\"{text}\", data)\n self.status = result_string\n return Message(text=result_string)\n"
+ "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily AI Search\"\n description = \"\"\"**Tavily AI** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n DropdownInput(\n name=\"time_range\",\n display_name=\"Time Range\",\n info=\"The time range back from the current date to include in the search results.\",\n options=[\"day\", \"week\", \"month\", \"year\"],\n value=None,\n advanced=True,\n combobox=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"fetch_content\"),\n Output(display_name=\"Text\", name=\"text\", method=\"fetch_content_text\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n \"time_range\": self.time_range,\n }\n\n with httpx.Client() as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n data_results.append(\n Data(\n text=content,\n data={\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n },\n )\n )\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_text(self) -> Message:\n data = self.fetch_content()\n result_string = data_to_text(\"{text}\", data)\n self.status = result_string\n return Message(text=result_string)\n"
},
"include_answer": {
"_input_type": "BoolInput",
@@ -2093,9 +1977,7 @@
"display_name": "Search Query",
"dynamic": false,
"info": "The search query you want to execute with Tavily.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -2114,14 +1996,13 @@
"_input_type": "DropdownInput",
"advanced": true,
"combobox": false,
+ "dialog_inputs": {},
"display_name": "Search Depth",
"dynamic": false,
"info": "The depth of the search.",
"name": "search_depth",
- "options": [
- "basic",
- "advanced"
- ],
+ "options": ["basic", "advanced"],
+ "options_metadata": [],
"placeholder": "",
"required": false,
"show": true,
@@ -2131,6 +2012,25 @@
"type": "str",
"value": "advanced"
},
+ "time_range": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": true,
+ "dialog_inputs": {},
+ "display_name": "Time Range",
+ "dynamic": false,
+ "info": "The time range back from the current date to include in the search results.",
+ "name": "time_range",
+ "options": ["day", "week", "month", "year"],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str"
+ },
"tools_metadata": {
"_input_type": "TableInput",
"advanced": false,
@@ -2156,10 +2056,7 @@
"description": "Modify tool names and descriptions to help agents understand when to use each tool.",
"field_parsers": {
"commands": "commands",
- "name": [
- "snake_case",
- "no_blank"
- ]
+ "name": ["snake_case", "no_blank"]
},
"hide_options": true
},
@@ -2172,6 +2069,7 @@
"edit_mode": "inline",
"filterable": false,
"formatter": "text",
+ "hidden": false,
"name": "name",
"sortable": false,
"type": "text"
@@ -2183,6 +2081,7 @@
"edit_mode": "popover",
"filterable": false,
"formatter": "text",
+ "hidden": false,
"name": "description",
"sortable": false,
"type": "text"
@@ -2194,6 +2093,7 @@
"edit_mode": "inline",
"filterable": false,
"formatter": "text",
+ "hidden": true,
"name": "tags",
"sortable": false,
"type": "text"
@@ -2209,17 +2109,13 @@
"value": [
{
"description": "fetch_content(api_key: Message) - **Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.",
- "name": "None-fetch_content",
- "tags": [
- "None-fetch_content"
- ]
+ "name": "TavilySearchComponent-fetch_content",
+ "tags": ["TavilySearchComponent-fetch_content"]
},
{
"description": "fetch_content_text(api_key: Message) - **Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.",
- "name": "None-fetch_content_text",
- "tags": [
- "None-fetch_content_text"
- ]
+ "name": "TavilySearchComponent-fetch_content_text",
+ "tags": ["TavilySearchComponent-fetch_content_text"]
}
]
},
@@ -2227,14 +2123,13 @@
"_input_type": "DropdownInput",
"advanced": true,
"combobox": false,
+ "dialog_inputs": {},
"display_name": "Search Topic",
"dynamic": false,
"info": "The category of the search.",
"name": "topic",
- "options": [
- "general",
- "news"
- ],
+ "options": ["general", "news"],
+ "options_metadata": [],
"placeholder": "",
"required": false,
"show": true,
@@ -2251,10 +2146,10 @@
"type": "TavilySearchComponent"
},
"dragging": false,
- "id": "TavilySearchComponent-Gv4zn",
+ "id": "TavilySearchComponent-EoHje",
"measured": {
- "height": 489,
- "width": 360
+ "height": 435,
+ "width": 320
},
"position": {
"x": 875.7686789989679,
@@ -2265,12 +2160,9 @@
},
{
"data": {
- "id": "OpenAIModel-Yo7s2",
+ "id": "OpenAIModel-aSzMF",
"node": {
- "base_classes": [
- "LanguageModel",
- "Message"
- ],
+ "base_classes": ["LanguageModel", "Message"],
"beta": false,
"category": "models",
"conditional_paths": [],
@@ -2309,9 +2201,7 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -2320,14 +2210,10 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
- "required_inputs": [
- "api_key"
- ],
+ "required_inputs": ["api_key"],
"selected": "LanguageModel",
"tool_mode": true,
- "types": [
- "LanguageModel"
- ],
+ "types": ["LanguageModel"],
"value": "__UNDEFINED__"
}
],
@@ -2341,9 +2227,7 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -2378,9 +2262,7 @@
"display_name": "Input",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -2562,9 +2444,7 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -2633,23 +2513,23 @@
"type": "OpenAIModel"
},
"dragging": false,
- "id": "OpenAIModel-Yo7s2",
+ "id": "OpenAIModel-aSzMF",
"measured": {
- "height": 734,
- "width": 360
+ "height": 653,
+ "width": 320
},
"position": {
"x": 1718.9581068990763,
"y": 1081.137733422722
},
- "selected": true,
+ "selected": false,
"type": "genericNode"
}
],
"viewport": {
- "x": -84.19731102880883,
- "y": -179.36393502789429,
- "zoom": 0.5492417618766154
+ "x": -55.02773146550817,
+ "y": 192.3971314158145,
+ "zoom": 0.4774432638923554
}
},
"description": "Researches companies, extracts key business data, and presents structured information for efficient analysis. ",
@@ -2660,8 +2540,5 @@
"is_component": false,
"last_tested_version": "1.1.1",
"name": "Market Research",
- "tags": [
- "assistants",
- "agents"
- ]
-}
\ No newline at end of file
+ "tags": ["assistants", "agents"]
+}
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Meeting Summary.json b/src/backend/base/langflow/initial_setup/starter_projects/Meeting Summary.json
new file mode 100644
index 0000000000..b2812a8741
--- /dev/null
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Meeting Summary.json
@@ -0,0 +1,3561 @@
+{
+ "data": {
+ "edges": [
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "AssemblyAITranscriptionJobPoller",
+ "id": "AssemblyAITranscriptionJobPoller-bxKgt",
+ "name": "transcription_result",
+ "output_types": [
+ "Data"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "data",
+ "id": "ParseData-LUfjb",
+ "inputTypes": [
+ "Data"
+ ],
+ "type": "other"
+ }
+ },
+ "id": "reactflow__edge-AssemblyAITranscriptionJobPoller-bxKgt{œdataTypeœ:œAssemblyAITranscriptionJobPollerœ,œidœ:œAssemblyAITranscriptionJobPoller-bxKgtœ,œnameœ:œtranscription_resultœ,œoutput_typesœ:[œDataœ]}-ParseData-LUfjb{œfieldNameœ:œdataœ,œidœ:œParseData-LUfjbœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}",
+ "selected": false,
+ "source": "AssemblyAITranscriptionJobPoller-bxKgt",
+ "sourceHandle": "{œdataTypeœ: œAssemblyAITranscriptionJobPollerœ, œidœ: œAssemblyAITranscriptionJobPoller-bxKgtœ, œnameœ: œtranscription_resultœ, œoutput_typesœ: [œDataœ]}",
+ "target": "ParseData-LUfjb",
+ "targetHandle": "{œfieldNameœ: œdataœ, œidœ: œParseData-LUfjbœ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "ParseData",
+ "id": "ParseData-LUfjb",
+ "name": "text",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "transcript",
+ "id": "Prompt-vYcSa",
+ "inputTypes": [
+ "Message",
+ "Text"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "reactflow__edge-ParseData-LUfjb{œdataTypeœ:œParseDataœ,œidœ:œParseData-LUfjbœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-vYcSa{œfieldNameœ:œtranscriptœ,œidœ:œPrompt-vYcSaœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "ParseData-LUfjb",
+ "sourceHandle": "{œdataTypeœ: œParseDataœ, œidœ: œParseData-LUfjbœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Prompt-vYcSa",
+ "targetHandle": "{œfieldNameœ: œtranscriptœ, œidœ: œPrompt-vYcSaœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "Prompt",
+ "id": "Prompt-vYcSa",
+ "name": "prompt",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "input_value",
+ "id": "OpenAIModel-iudDZ",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "reactflow__edge-Prompt-vYcSa{œdataTypeœ:œPromptœ,œidœ:œPrompt-vYcSaœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-iudDZ{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-iudDZœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "Prompt-vYcSa",
+ "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-vYcSaœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "OpenAIModel-iudDZ",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-iudDZœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "OpenAIModel",
+ "id": "OpenAIModel-iudDZ",
+ "name": "text_output",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "input_value",
+ "id": "ChatOutput-l7B6O",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "reactflow__edge-OpenAIModel-iudDZ{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-iudDZœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-l7B6O{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-l7B6Oœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "OpenAIModel-iudDZ",
+ "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-iudDZœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "ChatOutput-l7B6O",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-l7B6Oœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "ParseData",
+ "id": "ParseData-LUfjb",
+ "name": "text",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "input_value",
+ "id": "ChatOutput-BMxpl",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "reactflow__edge-ParseData-LUfjb{œdataTypeœ:œParseDataœ,œidœ:œParseData-LUfjbœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-BMxpl{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-BMxplœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "ParseData-LUfjb",
+ "sourceHandle": "{œdataTypeœ: œParseDataœ, œidœ: œParseData-LUfjbœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "ChatOutput-BMxpl",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-BMxplœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "OpenAIModel",
+ "id": "OpenAIModel-8fyum",
+ "name": "text_output",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "input_value",
+ "id": "ChatOutput-04Red",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "reactflow__edge-OpenAIModel-8fyum{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-8fyumœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-04Red{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-04Redœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "OpenAIModel-8fyum",
+ "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-8fyumœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "ChatOutput-04Red",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-04Redœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "Memory",
+ "id": "Memory-0odic",
+ "name": "messages_text",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "history",
+ "id": "Prompt-f4vcK",
+ "inputTypes": [
+ "Message",
+ "Text"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "reactflow__edge-Memory-0odic{œdataTypeœ:œMemoryœ,œidœ:œMemory-0odicœ,œnameœ:œmessages_textœ,œoutput_typesœ:[œMessageœ]}-Prompt-f4vcK{œfieldNameœ:œhistoryœ,œidœ:œPrompt-f4vcKœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "Memory-0odic",
+ "sourceHandle": "{œdataTypeœ: œMemoryœ, œidœ: œMemory-0odicœ, œnameœ: œmessages_textœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Prompt-f4vcK",
+ "targetHandle": "{œfieldNameœ: œhistoryœ, œidœ: œPrompt-f4vcKœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "ChatInput",
+ "id": "ChatInput-d3z9H",
+ "name": "message",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "input",
+ "id": "Prompt-f4vcK",
+ "inputTypes": [
+ "Message",
+ "Text"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "reactflow__edge-ChatInput-d3z9H{œdataTypeœ:œChatInputœ,œidœ:œChatInput-d3z9Hœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-f4vcK{œfieldNameœ:œinputœ,œidœ:œPrompt-f4vcKœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "ChatInput-d3z9H",
+ "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-d3z9Hœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Prompt-f4vcK",
+ "targetHandle": "{œfieldNameœ: œinputœ, œidœ: œPrompt-f4vcKœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "Prompt",
+ "id": "Prompt-f4vcK",
+ "name": "prompt",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "input_value",
+ "id": "OpenAIModel-8fyum",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "reactflow__edge-Prompt-f4vcK{œdataTypeœ:œPromptœ,œidœ:œPrompt-f4vcKœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-8fyum{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-8fyumœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "Prompt-f4vcK",
+ "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-f4vcKœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "OpenAIModel-8fyum",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-8fyumœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ },
+ {
+ "data": {
+ "sourceHandle": {
+ "dataType": "AssemblyAITranscriptionJobCreator",
+ "id": "AssemblyAITranscriptionJobCreator-ylQES",
+ "name": "transcript_id",
+ "output_types": [
+ "Data"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "transcript_id",
+ "id": "AssemblyAITranscriptionJobPoller-bxKgt",
+ "inputTypes": [
+ "Data"
+ ],
+ "type": "other"
+ }
+ },
+ "id": "xy-edge__AssemblyAITranscriptionJobCreator-ylQES{œdataTypeœ:œAssemblyAITranscriptionJobCreatorœ,œidœ:œAssemblyAITranscriptionJobCreator-ylQESœ,œnameœ:œtranscript_idœ,œoutput_typesœ:[œDataœ]}-AssemblyAITranscriptionJobPoller-bxKgt{œfieldNameœ:œtranscript_idœ,œidœ:œAssemblyAITranscriptionJobPoller-bxKgtœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}",
+ "source": "AssemblyAITranscriptionJobCreator-ylQES",
+ "sourceHandle": "{œdataTypeœ: œAssemblyAITranscriptionJobCreatorœ, œidœ: œAssemblyAITranscriptionJobCreator-ylQESœ, œnameœ: œtranscript_idœ, œoutput_typesœ: [œDataœ]}",
+ "target": "AssemblyAITranscriptionJobPoller-bxKgt",
+ "targetHandle": "{œfieldNameœ: œtranscript_idœ, œidœ: œAssemblyAITranscriptionJobPoller-bxKgtœ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}"
+ }
+ ],
+ "nodes": [
+ {
+ "data": {
+ "id": "AssemblyAITranscriptionJobPoller-bxKgt",
+ "node": {
+ "base_classes": [
+ "Data"
+ ],
+ "beta": false,
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Poll for the status of a transcription job using AssemblyAI",
+ "display_name": "AssemblyAI Poll Transcript",
+ "documentation": "https://www.assemblyai.com/docs",
+ "edited": false,
+ "field_order": [
+ "api_key",
+ "transcript_id",
+ "polling_interval"
+ ],
+ "frozen": false,
+ "icon": "AssemblyAI",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": false,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Transcription Result",
+ "method": "poll_transcription_job",
+ "name": "transcription_result",
+ "selected": "Data",
+ "tool_mode": true,
+ "types": [
+ "Data"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "template": {
+ "_type": "Component",
+ "api_key": {
+ "_input_type": "SecretStrInput",
+ "advanced": false,
+ "display_name": "Assembly API Key",
+ "dynamic": false,
+ "info": "Your AssemblyAI API key. You can get one from https://www.assemblyai.com/",
+ "input_types": [
+ "Message"
+ ],
+ "load_from_db": false,
+ "name": "api_key",
+ "password": true,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "import assemblyai as aai\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.io import DataInput, FloatInput, Output, SecretStrInput\nfrom langflow.schema import Data\n\n\nclass AssemblyAITranscriptionJobPoller(Component):\n display_name = \"AssemblyAI Poll Transcript\"\n description = \"Poll for the status of a transcription job using AssemblyAI\"\n documentation = \"https://www.assemblyai.com/docs\"\n icon = \"AssemblyAI\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Assembly API Key\",\n info=\"Your AssemblyAI API key. You can get one from https://www.assemblyai.com/\",\n required=True,\n ),\n DataInput(\n name=\"transcript_id\",\n display_name=\"Transcript ID\",\n info=\"The ID of the transcription job to poll\",\n required=True,\n ),\n FloatInput(\n name=\"polling_interval\",\n display_name=\"Polling Interval\",\n value=3.0,\n info=\"The polling interval in seconds\",\n advanced=True,\n range_spec=RangeSpec(min=3, max=30),\n ),\n ]\n\n outputs = [\n Output(display_name=\"Transcription Result\", name=\"transcription_result\", method=\"poll_transcription_job\"),\n ]\n\n def poll_transcription_job(self) -> Data:\n \"\"\"Polls the transcription status until completion and returns the Data.\"\"\"\n aai.settings.api_key = self.api_key\n aai.settings.polling_interval = self.polling_interval\n\n # check if it's an error message from the previous step\n if self.transcript_id.data.get(\"error\"):\n self.status = self.transcript_id.data[\"error\"]\n return self.transcript_id\n\n try:\n transcript = aai.Transcript.get_by_id(self.transcript_id.data[\"transcript_id\"])\n except Exception as e: # noqa: BLE001\n error = f\"Getting transcription failed: {e}\"\n logger.opt(exception=True).debug(error)\n self.status = error\n return Data(data={\"error\": error})\n\n if transcript.status == aai.TranscriptStatus.completed:\n json_response = transcript.json_response\n text = json_response.pop(\"text\", None)\n utterances = json_response.pop(\"utterances\", None)\n transcript_id = json_response.pop(\"id\", None)\n sorted_data = {\"text\": text, \"utterances\": utterances, \"id\": transcript_id}\n sorted_data.update(json_response)\n data = Data(data=sorted_data)\n self.status = data\n return data\n self.status = transcript.error\n return Data(data={\"error\": transcript.error})\n"
+ },
+ "polling_interval": {
+ "_input_type": "FloatInput",
+ "advanced": true,
+ "display_name": "Polling Interval",
+ "dynamic": false,
+ "info": "The polling interval in seconds",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "polling_interval",
+ "placeholder": "",
+ "range_spec": {
+ "max": 30,
+ "min": 3,
+ "step": 0.1,
+ "step_type": "float"
+ },
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "float",
+ "value": 3
+ },
+ "transcript_id": {
+ "_input_type": "DataInput",
+ "advanced": false,
+ "display_name": "Transcript ID",
+ "dynamic": false,
+ "info": "The ID of the transcription job to poll",
+ "input_types": [
+ "Data"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "transcript_id",
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "other",
+ "value": ""
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": true,
+ "type": "AssemblyAITranscriptionJobPoller"
+ },
+ "id": "AssemblyAITranscriptionJobPoller-bxKgt",
+ "measured": {
+ "height": 294,
+ "width": 320
+ },
+ "position": {
+ "x": 943.468098795128,
+ "y": 282.3188316337007
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "ParseData-LUfjb",
+ "node": {
+ "base_classes": [
+ "Data",
+ "Message"
+ ],
+ "beta": false,
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Convert Data objects into Messages using any {field_name} from input data.",
+ "display_name": "Data to Message",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "data",
+ "template",
+ "sep"
+ ],
+ "frozen": false,
+ "icon": "message-square",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": false,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Message",
+ "method": "parse_data",
+ "name": "text",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ },
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Data List",
+ "method": "parse_data_as_list",
+ "name": "data_list",
+ "selected": "Data",
+ "tool_mode": true,
+ "types": [
+ "Data"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "template": {
+ "_type": "Component",
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\", is_list=True, required=True),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
+ },
+ "data": {
+ "_input_type": "DataInput",
+ "advanced": false,
+ "display_name": "Data",
+ "dynamic": false,
+ "info": "The data to convert to text.",
+ "input_types": [
+ "Data"
+ ],
+ "list": true,
+ "list_add_label": "Add More",
+ "name": "data",
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "other",
+ "value": ""
+ },
+ "sep": {
+ "_input_type": "StrInput",
+ "advanced": true,
+ "display_name": "Separator",
+ "dynamic": false,
+ "info": "",
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "sep",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "\n"
+ },
+ "template": {
+ "_input_type": "MultilineInput",
+ "advanced": false,
+ "display_name": "Template",
+ "dynamic": false,
+ "info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "template",
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "{text}"
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": true,
+ "type": "ParseData"
+ },
+ "id": "ParseData-LUfjb",
+ "measured": {
+ "height": 342,
+ "width": 320
+ },
+ "position": {
+ "x": 1330.927281184057,
+ "y": 382.3516758942169
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "OpenAIModel-iudDZ",
+ "node": {
+ "base_classes": [
+ "LanguageModel",
+ "Message"
+ ],
+ "beta": false,
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Generates text using OpenAI LLMs.",
+ "display_name": "OpenAI",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "input_value",
+ "system_message",
+ "stream",
+ "max_tokens",
+ "model_kwargs",
+ "json_mode",
+ "model_name",
+ "openai_api_base",
+ "api_key",
+ "temperature",
+ "seed",
+ "max_retries",
+ "timeout"
+ ],
+ "frozen": false,
+ "icon": "OpenAI",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": false,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Message",
+ "method": "text_response",
+ "name": "text_output",
+ "required_inputs": [],
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ },
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Language Model",
+ "method": "build_model",
+ "name": "model_output",
+ "required_inputs": [
+ "api_key"
+ ],
+ "selected": "LanguageModel",
+ "tool_mode": true,
+ "types": [
+ "LanguageModel"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "template": {
+ "_type": "Component",
+ "api_key": {
+ "_input_type": "SecretStrInput",
+ "advanced": false,
+ "display_name": "OpenAI API Key",
+ "dynamic": false,
+ "info": "The OpenAI API Key to use for the OpenAI model.",
+ "input_types": [
+ "Message"
+ ],
+ "load_from_db": true,
+ "name": "api_key",
+ "password": true,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "str",
+ "value": "OPENAI_API_KEY"
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import OPENAI_MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs import BoolInput, DictInput, DropdownInput, IntInput, SecretStrInput, SliderInput, StrInput\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n name = \"OpenAIModel\"\n\n inputs = [\n *LCModelComponent._base_inputs,\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n range_spec=RangeSpec(min=0, max=128000),\n ),\n DictInput(\n name=\"model_kwargs\",\n display_name=\"Model Kwargs\",\n advanced=True,\n info=\"Additional keyword arguments to pass to the model.\",\n ),\n BoolInput(\n name=\"json_mode\",\n display_name=\"JSON Mode\",\n advanced=True,\n info=\"If True, it will output JSON regardless of passing a schema.\",\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n advanced=False,\n options=OPENAI_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[0],\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. \"\n \"Defaults to https://api.openai.com/v1. \"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n required=True,\n ),\n SliderInput(\n name=\"temperature\", display_name=\"Temperature\", value=0.1, range_spec=RangeSpec(min=0, max=1, step=0.01)\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n IntInput(\n name=\"max_retries\",\n display_name=\"Max Retries\",\n info=\"The maximum number of retries to make when generating.\",\n advanced=True,\n value=5,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"The timeout for requests to OpenAI completion API.\",\n advanced=True,\n value=700,\n ),\n ]\n\n def build_model(self) -> LanguageModel: # type: ignore[type-var]\n openai_api_key = self.api_key\n temperature = self.temperature\n model_name: str = self.model_name\n max_tokens = self.max_tokens\n model_kwargs = self.model_kwargs or {}\n openai_api_base = self.openai_api_base or \"https://api.openai.com/v1\"\n json_mode = self.json_mode\n seed = self.seed\n max_retries = self.max_retries\n timeout = self.timeout\n\n api_key = SecretStr(openai_api_key).get_secret_value() if openai_api_key else None\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature if temperature is not None else 0.1,\n seed=seed,\n max_retries=max_retries,\n request_timeout=timeout,\n )\n if json_mode:\n output = output.bind(response_format={\"type\": \"json_object\"})\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"Get a message from an OpenAI exception.\n\n Args:\n e (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n try:\n from openai import BadRequestError\n except ImportError:\n return None\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\")\n if message:\n return message\n return None\n"
+ },
+ "input_value": {
+ "_input_type": "MessageInput",
+ "advanced": false,
+ "display_name": "Input",
+ "dynamic": false,
+ "info": "",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "input_value",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "json_mode": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "JSON Mode",
+ "dynamic": false,
+ "info": "If True, it will output JSON regardless of passing a schema.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "json_mode",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": false
+ },
+ "max_retries": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Max Retries",
+ "dynamic": false,
+ "info": "The maximum number of retries to make when generating.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "max_retries",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 5
+ },
+ "max_tokens": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Max Tokens",
+ "dynamic": false,
+ "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "max_tokens",
+ "placeholder": "",
+ "range_spec": {
+ "max": 128000,
+ "min": 0,
+ "step": 0.1,
+ "step_type": "float"
+ },
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": ""
+ },
+ "model_kwargs": {
+ "_input_type": "DictInput",
+ "advanced": true,
+ "display_name": "Model Kwargs",
+ "dynamic": false,
+ "info": "Additional keyword arguments to pass to the model.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "model_kwargs",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "type": "dict",
+ "value": {}
+ },
+ "model_name": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Model Name",
+ "dynamic": false,
+ "info": "",
+ "name": "model_name",
+ "options": [
+ "gpt-4o-mini",
+ "gpt-4o",
+ "gpt-4-turbo",
+ "gpt-4-turbo-preview",
+ "gpt-4",
+ "gpt-3.5-turbo",
+ "gpt-3.5-turbo-0125"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "gpt-4o-mini"
+ },
+ "openai_api_base": {
+ "_input_type": "StrInput",
+ "advanced": true,
+ "display_name": "OpenAI API Base",
+ "dynamic": false,
+ "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.",
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "openai_api_base",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "seed": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Seed",
+ "dynamic": false,
+ "info": "The seed controls the reproducibility of the job.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "seed",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 1
+ },
+ "stream": {
+ "_input_type": "BoolInput",
+ "advanced": false,
+ "display_name": "Stream",
+ "dynamic": false,
+ "info": "Stream the response from the model. Streaming works only in Chat.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "stream",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": false
+ },
+ "system_message": {
+ "_input_type": "MultilineInput",
+ "advanced": false,
+ "display_name": "System Message",
+ "dynamic": false,
+ "info": "System message to pass to the model.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "system_message",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "temperature": {
+ "_input_type": "SliderInput",
+ "advanced": false,
+ "display_name": "Temperature",
+ "dynamic": false,
+ "info": "",
+ "max_label": "",
+ "max_label_icon": "",
+ "min_label": "",
+ "min_label_icon": "",
+ "name": "temperature",
+ "placeholder": "",
+ "range_spec": {
+ "max": 1,
+ "min": 0,
+ "step": 0.01,
+ "step_type": "float"
+ },
+ "required": false,
+ "show": true,
+ "slider_buttons": false,
+ "slider_buttons_options": [],
+ "slider_input": false,
+ "title_case": false,
+ "tool_mode": false,
+ "type": "slider",
+ "value": 0.1
+ },
+ "timeout": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Timeout",
+ "dynamic": false,
+ "info": "The timeout for requests to OpenAI completion API.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "timeout",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 700
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": true,
+ "type": "OpenAIModel"
+ },
+ "id": "OpenAIModel-iudDZ",
+ "measured": {
+ "height": 656,
+ "width": 320
+ },
+ "position": {
+ "x": 2159.856153607566,
+ "y": 546.0283268474204
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "Prompt-vYcSa",
+ "node": {
+ "base_classes": [
+ "Message"
+ ],
+ "beta": false,
+ "conditional_paths": [],
+ "custom_fields": {
+ "template": [
+ "transcript"
+ ]
+ },
+ "description": "Create a prompt template with dynamic variables.",
+ "display_name": "Prompt",
+ "documentation": "",
+ "edited": false,
+ "error": null,
+ "field_order": [
+ "template",
+ "tool_placeholder"
+ ],
+ "frozen": false,
+ "full_path": null,
+ "icon": "prompts",
+ "is_composition": null,
+ "is_input": null,
+ "is_output": null,
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": false,
+ "name": "",
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Prompt Message",
+ "method": "build_prompt",
+ "name": "prompt",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "template": {
+ "_type": "Component",
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import MessageTextInput, Output, PromptInput\nfrom langflow.schema.message import Message\nfrom langflow.template.utils import update_template_values\n\n\nclass PromptComponent(Component):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n MessageTextInput(\n name=\"tool_placeholder\",\n display_name=\"Tool Placeholder\",\n tool_mode=True,\n advanced=True,\n info=\"A placeholder input for tool mode.\",\n ),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(self) -> Message:\n prompt = Message.from_template(**self._attributes)\n self.status = prompt.text\n return prompt\n\n def _update_template(self, frontend_node: dict):\n prompt_template = frontend_node[\"template\"][\"template\"][\"value\"]\n custom_fields = frontend_node[\"custom_fields\"]\n frontend_node_template = frontend_node[\"template\"]\n _ = process_prompt_template(\n template=prompt_template,\n name=\"template\",\n custom_fields=custom_fields,\n frontend_node_template=frontend_node_template,\n )\n return frontend_node\n\n async def update_frontend_node(self, new_frontend_node: dict, current_frontend_node: dict):\n \"\"\"This function is called after the code validation is done.\"\"\"\n frontend_node = await super().update_frontend_node(new_frontend_node, current_frontend_node)\n template = frontend_node[\"template\"][\"template\"][\"value\"]\n # Kept it duplicated for backwards compatibility\n _ = process_prompt_template(\n template=template,\n name=\"template\",\n custom_fields=frontend_node[\"custom_fields\"],\n frontend_node_template=frontend_node[\"template\"],\n )\n # Now that template is updated, we need to grab any values that were set in the current_frontend_node\n # and update the frontend_node with those values\n update_template_values(new_template=frontend_node, previous_template=current_frontend_node[\"template\"])\n return frontend_node\n\n def _get_fallback_input(self, **kwargs):\n return DefaultPromptField(**kwargs)\n"
+ },
+ "template": {
+ "_input_type": "PromptInput",
+ "advanced": false,
+ "display_name": "Template",
+ "dynamic": false,
+ "info": "",
+ "list": false,
+ "name": "template",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "type": "prompt",
+ "value": "{transcript}\n\n---\n\nSummarize the action items and main ideas based on the conversation above. Be objective and avoid redundancy. \n\n"
+ },
+ "tool_placeholder": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Tool Placeholder",
+ "dynamic": false,
+ "info": "A placeholder input for tool mode.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "tool_placeholder",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": true,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "transcript": {
+ "advanced": false,
+ "display_name": "transcript",
+ "dynamic": false,
+ "field_type": "str",
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "input_types": [
+ "Message",
+ "Text"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "transcript",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": true,
+ "type": "Prompt"
+ },
+ "id": "Prompt-vYcSa",
+ "measured": {
+ "height": 339,
+ "width": 320
+ },
+ "position": {
+ "x": 1752.6947356866303,
+ "y": 491.51833853334665
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "ChatOutput-l7B6O",
+ "node": {
+ "base_classes": [
+ "Message"
+ ],
+ "beta": false,
+ "category": "outputs",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Display a chat message in the Playground.",
+ "display_name": "Chat Output",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "input_value",
+ "should_store_message",
+ "sender",
+ "sender_name",
+ "session_id",
+ "data_template",
+ "background_color",
+ "chat_icon",
+ "text_color"
+ ],
+ "frozen": false,
+ "icon": "MessagesSquare",
+ "key": "ChatOutput",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": true,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Message",
+ "method": "message_response",
+ "name": "message",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 0.00012027401062119145,
+ "template": {
+ "_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Source\nfrom langflow.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_AI,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n minimized = True\n\n inputs = [\n MessageInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, id_: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if id_:\n source_dict[\"id\"] = id_\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n source_dict[\"source\"] = source\n return Source(**source_dict)\n\n async def message_response(self) -> Message:\n source, icon, display_name, source_id = self.get_properties_from_source_component()\n background_color = self.background_color\n text_color = self.text_color\n if self.chat_icon:\n icon = self.chat_icon\n message = self.input_value if isinstance(self.input_value, Message) else Message(text=self.input_value)\n message.sender = self.sender\n message.sender_name = self.sender_name\n message.session_id = self.session_id\n message.flow_id = self.graph.flow_id if hasattr(self, \"graph\") else None\n message.properties.source = self._build_source(source_id, display_name, source)\n message.properties.icon = icon\n message.properties.background_color = background_color\n message.properties.text_color = text_color\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = await self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ },
+ "data_template": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Data Template",
+ "dynamic": false,
+ "info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "data_template",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "{text}"
+ },
+ "input_value": {
+ "_input_type": "MessageInput",
+ "advanced": false,
+ "display_name": "Text",
+ "dynamic": false,
+ "info": "Message to be passed as output.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "input_value",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "sender": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "display_name": "Sender Type",
+ "dynamic": false,
+ "info": "Type of sender.",
+ "name": "sender",
+ "options": [
+ "Machine",
+ "User"
+ ],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "Machine"
+ },
+ "sender_name": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Sender Name",
+ "dynamic": false,
+ "info": "Name of the sender.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "sender_name",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "AI"
+ },
+ "session_id": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Session ID",
+ "dynamic": false,
+ "info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "session_id",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "should_store_message": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Store Messages",
+ "dynamic": false,
+ "info": "Store the message in the history.",
+ "list": false,
+ "name": "should_store_message",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": true,
+ "type": "ChatOutput"
+ },
+ "id": "ChatOutput-l7B6O",
+ "measured": {
+ "height": 230,
+ "width": 320
+ },
+ "position": {
+ "x": 2586.3668922112406,
+ "y": 713.1816341478374
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "ChatOutput-BMxpl",
+ "node": {
+ "base_classes": [
+ "Message"
+ ],
+ "beta": false,
+ "category": "outputs",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Display a chat message in the Playground.",
+ "display_name": "Chat Output",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "input_value",
+ "should_store_message",
+ "sender",
+ "sender_name",
+ "session_id",
+ "data_template",
+ "background_color",
+ "chat_icon",
+ "text_color"
+ ],
+ "frozen": false,
+ "icon": "MessagesSquare",
+ "key": "ChatOutput",
+ "legacy": false,
+ "lf_version": "1.1.1",
+ "metadata": {},
+ "minimized": true,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Message",
+ "method": "message_response",
+ "name": "message",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 0.00012027401062119145,
+ "template": {
+ "_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Source\nfrom langflow.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_AI,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n minimized = True\n\n inputs = [\n MessageInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, id_: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if id_:\n source_dict[\"id\"] = id_\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n source_dict[\"source\"] = source\n return Source(**source_dict)\n\n async def message_response(self) -> Message:\n source, icon, display_name, source_id = self.get_properties_from_source_component()\n background_color = self.background_color\n text_color = self.text_color\n if self.chat_icon:\n icon = self.chat_icon\n message = self.input_value if isinstance(self.input_value, Message) else Message(text=self.input_value)\n message.sender = self.sender\n message.sender_name = self.sender_name\n message.session_id = self.session_id\n message.flow_id = self.graph.flow_id if hasattr(self, \"graph\") else None\n message.properties.source = self._build_source(source_id, display_name, source)\n message.properties.icon = icon\n message.properties.background_color = background_color\n message.properties.text_color = text_color\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = await self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ },
+ "data_template": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Data Template",
+ "dynamic": false,
+ "info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "data_template",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "{text}"
+ },
+ "input_value": {
+ "_input_type": "MessageInput",
+ "advanced": false,
+ "display_name": "Text",
+ "dynamic": false,
+ "info": "Message to be passed as output.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "input_value",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "sender": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "display_name": "Sender Type",
+ "dynamic": false,
+ "info": "Type of sender.",
+ "name": "sender",
+ "options": [
+ "Machine",
+ "User"
+ ],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "Machine"
+ },
+ "sender_name": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Sender Name",
+ "dynamic": false,
+ "info": "Name of the sender.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "sender_name",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "Original"
+ },
+ "session_id": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Session ID",
+ "dynamic": false,
+ "info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "session_id",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "should_store_message": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Store Messages",
+ "dynamic": false,
+ "info": "Store the message in the history.",
+ "list": false,
+ "name": "should_store_message",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": false,
+ "type": "ChatOutput"
+ },
+ "id": "ChatOutput-BMxpl",
+ "measured": {
+ "height": 66,
+ "width": 192
+ },
+ "position": {
+ "x": 1808.9025759312458,
+ "y": 928.6030474712679
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "OpenAIModel-8fyum",
+ "node": {
+ "base_classes": [
+ "LanguageModel",
+ "Message"
+ ],
+ "beta": false,
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Generates text using OpenAI LLMs.",
+ "display_name": "OpenAI",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "input_value",
+ "system_message",
+ "stream",
+ "max_tokens",
+ "model_kwargs",
+ "json_mode",
+ "model_name",
+ "openai_api_base",
+ "api_key",
+ "temperature",
+ "seed",
+ "max_retries",
+ "timeout"
+ ],
+ "frozen": false,
+ "icon": "OpenAI",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": false,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Message",
+ "method": "text_response",
+ "name": "text_output",
+ "required_inputs": [],
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ },
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Language Model",
+ "method": "build_model",
+ "name": "model_output",
+ "required_inputs": [
+ "api_key"
+ ],
+ "selected": "LanguageModel",
+ "tool_mode": true,
+ "types": [
+ "LanguageModel"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "template": {
+ "_type": "Component",
+ "api_key": {
+ "_input_type": "SecretStrInput",
+ "advanced": false,
+ "display_name": "OpenAI API Key",
+ "dynamic": false,
+ "info": "The OpenAI API Key to use for the OpenAI model.",
+ "input_types": [
+ "Message"
+ ],
+ "load_from_db": true,
+ "name": "api_key",
+ "password": true,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "str",
+ "value": "OPENAI_API_KEY"
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import OPENAI_MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs import BoolInput, DictInput, DropdownInput, IntInput, SecretStrInput, SliderInput, StrInput\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n name = \"OpenAIModel\"\n\n inputs = [\n *LCModelComponent._base_inputs,\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n range_spec=RangeSpec(min=0, max=128000),\n ),\n DictInput(\n name=\"model_kwargs\",\n display_name=\"Model Kwargs\",\n advanced=True,\n info=\"Additional keyword arguments to pass to the model.\",\n ),\n BoolInput(\n name=\"json_mode\",\n display_name=\"JSON Mode\",\n advanced=True,\n info=\"If True, it will output JSON regardless of passing a schema.\",\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n advanced=False,\n options=OPENAI_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[0],\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. \"\n \"Defaults to https://api.openai.com/v1. \"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n required=True,\n ),\n SliderInput(\n name=\"temperature\", display_name=\"Temperature\", value=0.1, range_spec=RangeSpec(min=0, max=1, step=0.01)\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n IntInput(\n name=\"max_retries\",\n display_name=\"Max Retries\",\n info=\"The maximum number of retries to make when generating.\",\n advanced=True,\n value=5,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"The timeout for requests to OpenAI completion API.\",\n advanced=True,\n value=700,\n ),\n ]\n\n def build_model(self) -> LanguageModel: # type: ignore[type-var]\n openai_api_key = self.api_key\n temperature = self.temperature\n model_name: str = self.model_name\n max_tokens = self.max_tokens\n model_kwargs = self.model_kwargs or {}\n openai_api_base = self.openai_api_base or \"https://api.openai.com/v1\"\n json_mode = self.json_mode\n seed = self.seed\n max_retries = self.max_retries\n timeout = self.timeout\n\n api_key = SecretStr(openai_api_key).get_secret_value() if openai_api_key else None\n output = ChatOpenAI(\n max_tokens=max_tokens or None,\n model_kwargs=model_kwargs,\n model=model_name,\n base_url=openai_api_base,\n api_key=api_key,\n temperature=temperature if temperature is not None else 0.1,\n seed=seed,\n max_retries=max_retries,\n request_timeout=timeout,\n )\n if json_mode:\n output = output.bind(response_format={\"type\": \"json_object\"})\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"Get a message from an OpenAI exception.\n\n Args:\n e (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n try:\n from openai import BadRequestError\n except ImportError:\n return None\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\")\n if message:\n return message\n return None\n"
+ },
+ "input_value": {
+ "_input_type": "MessageInput",
+ "advanced": false,
+ "display_name": "Input",
+ "dynamic": false,
+ "info": "",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "input_value",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "json_mode": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "JSON Mode",
+ "dynamic": false,
+ "info": "If True, it will output JSON regardless of passing a schema.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "json_mode",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": false
+ },
+ "max_retries": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Max Retries",
+ "dynamic": false,
+ "info": "The maximum number of retries to make when generating.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "max_retries",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 5
+ },
+ "max_tokens": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Max Tokens",
+ "dynamic": false,
+ "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "max_tokens",
+ "placeholder": "",
+ "range_spec": {
+ "max": 128000,
+ "min": 0,
+ "step": 0.1,
+ "step_type": "float"
+ },
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": ""
+ },
+ "model_kwargs": {
+ "_input_type": "DictInput",
+ "advanced": true,
+ "display_name": "Model Kwargs",
+ "dynamic": false,
+ "info": "Additional keyword arguments to pass to the model.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "model_kwargs",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "type": "dict",
+ "value": {}
+ },
+ "model_name": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Model Name",
+ "dynamic": false,
+ "info": "",
+ "name": "model_name",
+ "options": [
+ "gpt-4o-mini",
+ "gpt-4o",
+ "gpt-4-turbo",
+ "gpt-4-turbo-preview",
+ "gpt-4",
+ "gpt-3.5-turbo",
+ "gpt-3.5-turbo-0125"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "gpt-4o-mini"
+ },
+ "openai_api_base": {
+ "_input_type": "StrInput",
+ "advanced": true,
+ "display_name": "OpenAI API Base",
+ "dynamic": false,
+ "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.",
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "openai_api_base",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "seed": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Seed",
+ "dynamic": false,
+ "info": "The seed controls the reproducibility of the job.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "seed",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 1
+ },
+ "stream": {
+ "_input_type": "BoolInput",
+ "advanced": false,
+ "display_name": "Stream",
+ "dynamic": false,
+ "info": "Stream the response from the model. Streaming works only in Chat.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "stream",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": false
+ },
+ "system_message": {
+ "_input_type": "MultilineInput",
+ "advanced": false,
+ "display_name": "System Message",
+ "dynamic": false,
+ "info": "System message to pass to the model.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "system_message",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "temperature": {
+ "_input_type": "SliderInput",
+ "advanced": false,
+ "display_name": "Temperature",
+ "dynamic": false,
+ "info": "",
+ "max_label": "",
+ "max_label_icon": "",
+ "min_label": "",
+ "min_label_icon": "",
+ "name": "temperature",
+ "placeholder": "",
+ "range_spec": {
+ "max": 1,
+ "min": 0,
+ "step": 0.01,
+ "step_type": "float"
+ },
+ "required": false,
+ "show": true,
+ "slider_buttons": false,
+ "slider_buttons_options": [],
+ "slider_input": false,
+ "title_case": false,
+ "tool_mode": false,
+ "type": "slider",
+ "value": 0.1
+ },
+ "timeout": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Timeout",
+ "dynamic": false,
+ "info": "The timeout for requests to OpenAI completion API.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "timeout",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 700
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": true,
+ "type": "OpenAIModel"
+ },
+ "id": "OpenAIModel-8fyum",
+ "measured": {
+ "height": 656,
+ "width": 320
+ },
+ "position": {
+ "x": 1668.2863585030223,
+ "y": 1394.531585772563
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "ChatOutput-04Red",
+ "node": {
+ "base_classes": [
+ "Message"
+ ],
+ "beta": false,
+ "category": "outputs",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Display a chat message in the Playground.",
+ "display_name": "Chat Output",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "input_value",
+ "should_store_message",
+ "sender",
+ "sender_name",
+ "session_id",
+ "data_template",
+ "background_color",
+ "chat_icon",
+ "text_color"
+ ],
+ "frozen": false,
+ "icon": "MessagesSquare",
+ "key": "ChatOutput",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": true,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Message",
+ "method": "message_response",
+ "name": "message",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 0.00012027401062119145,
+ "template": {
+ "_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Source\nfrom langflow.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_AI,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n minimized = True\n\n inputs = [\n MessageInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, id_: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if id_:\n source_dict[\"id\"] = id_\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n source_dict[\"source\"] = source\n return Source(**source_dict)\n\n async def message_response(self) -> Message:\n source, icon, display_name, source_id = self.get_properties_from_source_component()\n background_color = self.background_color\n text_color = self.text_color\n if self.chat_icon:\n icon = self.chat_icon\n message = self.input_value if isinstance(self.input_value, Message) else Message(text=self.input_value)\n message.sender = self.sender\n message.sender_name = self.sender_name\n message.session_id = self.session_id\n message.flow_id = self.graph.flow_id if hasattr(self, \"graph\") else None\n message.properties.source = self._build_source(source_id, display_name, source)\n message.properties.icon = icon\n message.properties.background_color = background_color\n message.properties.text_color = text_color\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = await self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ },
+ "data_template": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Data Template",
+ "dynamic": false,
+ "info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "data_template",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "{text}"
+ },
+ "input_value": {
+ "_input_type": "MessageInput",
+ "advanced": false,
+ "display_name": "Text",
+ "dynamic": false,
+ "info": "Message to be passed as output.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "input_value",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "sender": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "display_name": "Sender Type",
+ "dynamic": false,
+ "info": "Type of sender.",
+ "name": "sender",
+ "options": [
+ "Machine",
+ "User"
+ ],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "Machine"
+ },
+ "sender_name": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Sender Name",
+ "dynamic": false,
+ "info": "Name of the sender.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "sender_name",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "AI"
+ },
+ "session_id": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Session ID",
+ "dynamic": false,
+ "info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "session_id",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "should_store_message": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Store Messages",
+ "dynamic": false,
+ "info": "Store the message in the history.",
+ "list": false,
+ "name": "should_store_message",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": false,
+ "type": "ChatOutput"
+ },
+ "id": "ChatOutput-04Red",
+ "measured": {
+ "height": 66,
+ "width": 192
+ },
+ "position": {
+ "x": 2166.5776099158024,
+ "y": 1717.8823325046656
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "Prompt-f4vcK",
+ "node": {
+ "base_classes": [
+ "Message"
+ ],
+ "beta": false,
+ "conditional_paths": [],
+ "custom_fields": {
+ "template": [
+ "history",
+ "input"
+ ]
+ },
+ "description": "Create a prompt template with dynamic variables.",
+ "display_name": "Prompt",
+ "documentation": "",
+ "edited": false,
+ "error": null,
+ "field_order": [
+ "template",
+ "tool_placeholder"
+ ],
+ "frozen": false,
+ "full_path": null,
+ "icon": "prompts",
+ "is_composition": null,
+ "is_input": null,
+ "is_output": null,
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": false,
+ "name": "",
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Prompt Message",
+ "method": "build_prompt",
+ "name": "prompt",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "template": {
+ "_type": "Component",
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import MessageTextInput, Output, PromptInput\nfrom langflow.schema.message import Message\nfrom langflow.template.utils import update_template_values\n\n\nclass PromptComponent(Component):\n display_name: str = \"Prompt\"\n description: str = \"Create a prompt template with dynamic variables.\"\n icon = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n MessageTextInput(\n name=\"tool_placeholder\",\n display_name=\"Tool Placeholder\",\n tool_mode=True,\n advanced=True,\n info=\"A placeholder input for tool mode.\",\n ),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(self) -> Message:\n prompt = Message.from_template(**self._attributes)\n self.status = prompt.text\n return prompt\n\n def _update_template(self, frontend_node: dict):\n prompt_template = frontend_node[\"template\"][\"template\"][\"value\"]\n custom_fields = frontend_node[\"custom_fields\"]\n frontend_node_template = frontend_node[\"template\"]\n _ = process_prompt_template(\n template=prompt_template,\n name=\"template\",\n custom_fields=custom_fields,\n frontend_node_template=frontend_node_template,\n )\n return frontend_node\n\n async def update_frontend_node(self, new_frontend_node: dict, current_frontend_node: dict):\n \"\"\"This function is called after the code validation is done.\"\"\"\n frontend_node = await super().update_frontend_node(new_frontend_node, current_frontend_node)\n template = frontend_node[\"template\"][\"template\"][\"value\"]\n # Kept it duplicated for backwards compatibility\n _ = process_prompt_template(\n template=template,\n name=\"template\",\n custom_fields=frontend_node[\"custom_fields\"],\n frontend_node_template=frontend_node[\"template\"],\n )\n # Now that template is updated, we need to grab any values that were set in the current_frontend_node\n # and update the frontend_node with those values\n update_template_values(new_template=frontend_node, previous_template=current_frontend_node[\"template\"])\n return frontend_node\n\n def _get_fallback_input(self, **kwargs):\n return DefaultPromptField(**kwargs)\n"
+ },
+ "history": {
+ "advanced": false,
+ "display_name": "history",
+ "dynamic": false,
+ "field_type": "str",
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "input_types": [
+ "Message",
+ "Text"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "history",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "type": "str",
+ "value": ""
+ },
+ "input": {
+ "advanced": false,
+ "display_name": "input",
+ "dynamic": false,
+ "field_type": "str",
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "input_types": [
+ "Message",
+ "Text"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "input",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "type": "str",
+ "value": ""
+ },
+ "template": {
+ "_input_type": "PromptInput",
+ "advanced": false,
+ "display_name": "Template",
+ "dynamic": false,
+ "info": "",
+ "list": false,
+ "name": "template",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "type": "prompt",
+ "value": "{history}\n\n{input}\n\n"
+ },
+ "tool_placeholder": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Tool Placeholder",
+ "dynamic": false,
+ "info": "A placeholder input for tool mode.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "tool_placeholder",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": true,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": true,
+ "type": "Prompt"
+ },
+ "id": "Prompt-f4vcK",
+ "measured": {
+ "height": 421,
+ "width": 320
+ },
+ "position": {
+ "x": 1201.39455884454,
+ "y": 1434.0090202145623
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "Memory-0odic",
+ "node": {
+ "base_classes": [
+ "Data",
+ "Message"
+ ],
+ "beta": false,
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Retrieves stored chat messages from Langflow tables or an external memory.",
+ "display_name": "Message History",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "memory",
+ "sender",
+ "sender_name",
+ "n_messages",
+ "session_id",
+ "order",
+ "template"
+ ],
+ "frozen": false,
+ "icon": "message-square-more",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": false,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Data",
+ "method": "retrieve_messages",
+ "name": "messages",
+ "selected": "Data",
+ "tool_mode": true,
+ "types": [
+ "Data"
+ ],
+ "value": "__UNDEFINED__"
+ },
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Message",
+ "method": "retrieve_messages_as_text",
+ "name": "messages_text",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "template": {
+ "_type": "Component",
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.inputs import HandleInput\nfrom langflow.io import DropdownInput, IntInput, MessageTextInput, MultilineInput, Output\nfrom langflow.memory import aget_messages\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER\n\n\nclass MemoryComponent(Component):\n display_name = \"Message History\"\n description = \"Retrieves stored chat messages from Langflow tables or an external memory.\"\n icon = \"message-square-more\"\n name = \"Memory\"\n\n inputs = [\n HandleInput(\n name=\"memory\",\n display_name=\"External Memory\",\n input_types=[\"Memory\"],\n info=\"Retrieve messages from an external memory. If empty, it will use the Langflow tables.\",\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, \"Machine and User\"],\n value=\"Machine and User\",\n info=\"Filter by sender type.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Filter by sender name.\",\n advanced=True,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Messages\",\n value=100,\n info=\"Number of messages to retrieve.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"order\",\n display_name=\"Order\",\n options=[\"Ascending\", \"Descending\"],\n value=\"Ascending\",\n info=\"Order of the messages.\",\n advanced=True,\n tool_mode=True,\n ),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {sender} or any other key in the message data.\",\n value=\"{sender_name}: {text}\",\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"messages\", method=\"retrieve_messages\"),\n Output(display_name=\"Message\", name=\"messages_text\", method=\"retrieve_messages_as_text\"),\n ]\n\n async def retrieve_messages(self) -> Data:\n sender = self.sender\n sender_name = self.sender_name\n session_id = self.session_id\n n_messages = self.n_messages\n order = \"DESC\" if self.order == \"Descending\" else \"ASC\"\n\n if sender == \"Machine and User\":\n sender = None\n\n if self.memory:\n # override session_id\n self.memory.session_id = session_id\n\n stored = await self.memory.aget_messages()\n # langchain memories are supposed to return messages in ascending order\n if order == \"DESC\":\n stored = stored[::-1]\n if n_messages:\n stored = stored[:n_messages]\n stored = [Message.from_lc_message(m) for m in stored]\n if sender:\n expected_type = MESSAGE_SENDER_AI if sender == MESSAGE_SENDER_AI else MESSAGE_SENDER_USER\n stored = [m for m in stored if m.type == expected_type]\n else:\n stored = await aget_messages(\n sender=sender,\n sender_name=sender_name,\n session_id=session_id,\n limit=n_messages,\n order=order,\n )\n self.status = stored\n return stored\n\n async def retrieve_messages_as_text(self) -> Message:\n stored_text = data_to_text(self.template, await self.retrieve_messages())\n self.status = stored_text\n return Message(text=stored_text)\n"
+ },
+ "memory": {
+ "_input_type": "HandleInput",
+ "advanced": false,
+ "display_name": "External Memory",
+ "dynamic": false,
+ "info": "Retrieve messages from an external memory. If empty, it will use the Langflow tables.",
+ "input_types": [
+ "Memory"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "memory",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_metadata": true,
+ "type": "other",
+ "value": ""
+ },
+ "n_messages": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Number of Messages",
+ "dynamic": false,
+ "info": "Number of messages to retrieve.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "n_messages",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 100
+ },
+ "order": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Order",
+ "dynamic": false,
+ "info": "Order of the messages.",
+ "name": "order",
+ "options": [
+ "Ascending",
+ "Descending"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "Ascending"
+ },
+ "sender": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Sender Type",
+ "dynamic": false,
+ "info": "Filter by sender type.",
+ "name": "sender",
+ "options": [
+ "Machine",
+ "User",
+ "Machine and User"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "Machine and User"
+ },
+ "sender_name": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Sender Name",
+ "dynamic": false,
+ "info": "Filter by sender name.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "sender_name",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "session_id": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Session ID",
+ "dynamic": false,
+ "info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "session_id",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "template": {
+ "_input_type": "MultilineInput",
+ "advanced": true,
+ "display_name": "Template",
+ "dynamic": false,
+ "info": "The template to use for formatting the data. It can contain the keys {text}, {sender} or any other key in the message data.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "template",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "{sender_name}: {text}"
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": true,
+ "type": "Memory"
+ },
+ "id": "Memory-0odic",
+ "measured": {
+ "height": 260,
+ "width": 320
+ },
+ "position": {
+ "x": 685.5892616330983,
+ "y": 1365.244705292662
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "ChatInput-d3z9H",
+ "node": {
+ "base_classes": [
+ "Message"
+ ],
+ "beta": false,
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Get chat inputs from the Playground.",
+ "display_name": "Chat Input",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "input_value",
+ "should_store_message",
+ "sender",
+ "sender_name",
+ "session_id",
+ "files",
+ "background_color",
+ "chat_icon",
+ "text_color"
+ ],
+ "frozen": false,
+ "icon": "MessagesSquare",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": true,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Message",
+ "method": "message_response",
+ "name": "message",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "template": {
+ "_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import (\n DropdownInput,\n FileInput,\n MessageTextInput,\n MultilineInput,\n Output,\n)\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_USER,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n minimized = True\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n input_types=[],\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n async def message_response(self) -> Message:\n background_color = self.background_color\n text_color = self.text_color\n icon = self.chat_icon\n\n message = await Message.create(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n properties={\n \"background_color\": background_color,\n \"text_color\": text_color,\n \"icon\": icon,\n },\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = await self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ },
+ "files": {
+ "_input_type": "FileInput",
+ "advanced": true,
+ "display_name": "Files",
+ "dynamic": false,
+ "fileTypes": [
+ "txt",
+ "md",
+ "mdx",
+ "csv",
+ "json",
+ "yaml",
+ "yml",
+ "xml",
+ "html",
+ "htm",
+ "pdf",
+ "docx",
+ "py",
+ "sh",
+ "sql",
+ "js",
+ "ts",
+ "tsx",
+ "jpg",
+ "jpeg",
+ "png",
+ "bmp",
+ "image"
+ ],
+ "file_path": "",
+ "info": "Files to be sent with the message.",
+ "list": true,
+ "name": "files",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_metadata": true,
+ "type": "file",
+ "value": ""
+ },
+ "input_value": {
+ "_input_type": "MultilineInput",
+ "advanced": false,
+ "display_name": "Text",
+ "dynamic": false,
+ "info": "Message to be passed as input.",
+ "input_types": [],
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "input_value",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "sender": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "display_name": "Sender Type",
+ "dynamic": false,
+ "info": "Type of sender.",
+ "name": "sender",
+ "options": [
+ "Machine",
+ "User"
+ ],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "User"
+ },
+ "sender_name": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Sender Name",
+ "dynamic": false,
+ "info": "Name of the sender.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "sender_name",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "User"
+ },
+ "session_id": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Session ID",
+ "dynamic": false,
+ "info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "session_id",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "should_store_message": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Store Messages",
+ "dynamic": false,
+ "info": "Store the message in the history.",
+ "list": false,
+ "name": "should_store_message",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": false,
+ "type": "ChatInput"
+ },
+ "id": "ChatInput-d3z9H",
+ "measured": {
+ "height": 66,
+ "width": 192
+ },
+ "position": {
+ "x": 701.8270533776066,
+ "y": 1829.9409906958817
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "note-2icq2",
+ "node": {
+ "description": "### 💡 Add your Assembly AI API key and audio file here",
+ "display_name": "",
+ "documentation": "",
+ "template": {
+ "backgroundColor": "transparent"
+ }
+ },
+ "type": "note"
+ },
+ "dragging": false,
+ "height": 324,
+ "id": "note-2icq2",
+ "measured": {
+ "height": 324,
+ "width": 455
+ },
+ "position": {
+ "x": 452.7834981529654,
+ "y": 186.89794978262478
+ },
+ "resizing": false,
+ "selected": false,
+ "type": "noteNode",
+ "width": 456
+ },
+ {
+ "data": {
+ "id": "note-OejoR",
+ "node": {
+ "description": "### 💡 Add your Assembly AI API key here",
+ "display_name": "",
+ "documentation": "",
+ "template": {
+ "backgroundColor": "transparent"
+ }
+ },
+ "type": "note"
+ },
+ "dragging": false,
+ "height": 324,
+ "id": "note-OejoR",
+ "measured": {
+ "height": 324,
+ "width": 364
+ },
+ "position": {
+ "x": 920.5426847894952,
+ "y": 231.76073203017918
+ },
+ "resizing": false,
+ "selected": false,
+ "type": "noteNode",
+ "width": 365
+ },
+ {
+ "data": {
+ "id": "note-9B1rT",
+ "node": {
+ "description": "### 💡 Add your OpenAI API key here",
+ "display_name": "",
+ "documentation": "",
+ "template": {
+ "backgroundColor": "transparent"
+ }
+ },
+ "type": "note"
+ },
+ "dragging": false,
+ "height": 324,
+ "id": "note-9B1rT",
+ "measured": {
+ "height": 324,
+ "width": 334
+ },
+ "position": {
+ "x": 2151.1746324575247,
+ "y": 500.2170739157981
+ },
+ "resizing": false,
+ "selected": false,
+ "type": "noteNode",
+ "width": 335
+ },
+ {
+ "data": {
+ "id": "note-tO2On",
+ "node": {
+ "description": "### 💡 Add your OpenAI API key here",
+ "display_name": "",
+ "documentation": "",
+ "template": {
+ "backgroundColor": "transparent"
+ }
+ },
+ "type": "note"
+ },
+ "dragging": false,
+ "id": "note-tO2On",
+ "measured": {
+ "height": 324,
+ "width": 324
+ },
+ "position": {
+ "x": 1665.156818365488,
+ "y": 1348.5600122190888
+ },
+ "selected": false,
+ "type": "noteNode"
+ },
+ {
+ "data": {
+ "id": "AssemblyAITranscriptionJobCreator-ylQES",
+ "node": {
+ "base_classes": [
+ "Data"
+ ],
+ "beta": false,
+ "category": "assemblyai",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Create a transcription job for an audio file using AssemblyAI with advanced options",
+ "display_name": "AssemblyAI Start Transcript",
+ "documentation": "https://www.assemblyai.com/docs",
+ "edited": false,
+ "field_order": [
+ "api_key",
+ "audio_file",
+ "audio_file_url",
+ "speech_model",
+ "language_detection",
+ "language_code",
+ "speaker_labels",
+ "speakers_expected",
+ "punctuate",
+ "format_text"
+ ],
+ "frozen": false,
+ "icon": "AssemblyAI",
+ "key": "AssemblyAITranscriptionJobCreator",
+ "legacy": false,
+ "metadata": {},
+ "minimized": false,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Transcript ID",
+ "method": "create_transcription_job",
+ "name": "transcript_id",
+ "selected": "Data",
+ "tool_mode": true,
+ "types": [
+ "Data"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 0.000018578044550916993,
+ "template": {
+ "_type": "Component",
+ "api_key": {
+ "_input_type": "SecretStrInput",
+ "advanced": false,
+ "display_name": "Assembly API Key",
+ "dynamic": false,
+ "info": "Your AssemblyAI API key. You can get one from https://www.assemblyai.com/",
+ "input_types": [
+ "Message"
+ ],
+ "load_from_db": false,
+ "name": "api_key",
+ "password": true,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "str",
+ "value": ""
+ },
+ "audio_file": {
+ "_input_type": "FileInput",
+ "advanced": false,
+ "display_name": "Audio File",
+ "dynamic": false,
+ "fileTypes": [
+ "3ga",
+ "8svx",
+ "aac",
+ "ac3",
+ "aif",
+ "aiff",
+ "alac",
+ "amr",
+ "ape",
+ "au",
+ "dss",
+ "flac",
+ "flv",
+ "m4a",
+ "m4b",
+ "m4p",
+ "m4r",
+ "mp3",
+ "mpga",
+ "ogg",
+ "oga",
+ "mogg",
+ "opus",
+ "qcp",
+ "tta",
+ "voc",
+ "wav",
+ "wma",
+ "wv",
+ "webm",
+ "mts",
+ "m2ts",
+ "ts",
+ "mov",
+ "mp2",
+ "mp4",
+ "m4p",
+ "m4v",
+ "mxf"
+ ],
+ "file_path": "",
+ "info": "The audio file to transcribe",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "audio_file",
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "trace_as_metadata": true,
+ "type": "file",
+ "value": ""
+ },
+ "audio_file_url": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Audio File URL",
+ "dynamic": false,
+ "info": "The URL of the audio file to transcribe (Can be used instead of a File)",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "audio_file_url",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from pathlib import Path\n\nimport assemblyai as aai\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.io import BoolInput, DropdownInput, FileInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\n\n\nclass AssemblyAITranscriptionJobCreator(Component):\n display_name = \"AssemblyAI Start Transcript\"\n description = \"Create a transcription job for an audio file using AssemblyAI with advanced options\"\n documentation = \"https://www.assemblyai.com/docs\"\n icon = \"AssemblyAI\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Assembly API Key\",\n info=\"Your AssemblyAI API key. You can get one from https://www.assemblyai.com/\",\n required=True,\n ),\n FileInput(\n name=\"audio_file\",\n display_name=\"Audio File\",\n file_types=[\n \"3ga\",\n \"8svx\",\n \"aac\",\n \"ac3\",\n \"aif\",\n \"aiff\",\n \"alac\",\n \"amr\",\n \"ape\",\n \"au\",\n \"dss\",\n \"flac\",\n \"flv\",\n \"m4a\",\n \"m4b\",\n \"m4p\",\n \"m4r\",\n \"mp3\",\n \"mpga\",\n \"ogg\",\n \"oga\",\n \"mogg\",\n \"opus\",\n \"qcp\",\n \"tta\",\n \"voc\",\n \"wav\",\n \"wma\",\n \"wv\",\n \"webm\",\n \"mts\",\n \"m2ts\",\n \"ts\",\n \"mov\",\n \"mp2\",\n \"mp4\",\n \"m4p\",\n \"m4v\",\n \"mxf\",\n ],\n info=\"The audio file to transcribe\",\n required=True,\n ),\n MessageTextInput(\n name=\"audio_file_url\",\n display_name=\"Audio File URL\",\n info=\"The URL of the audio file to transcribe (Can be used instead of a File)\",\n advanced=True,\n ),\n DropdownInput(\n name=\"speech_model\",\n display_name=\"Speech Model\",\n options=[\n \"best\",\n \"nano\",\n ],\n value=\"best\",\n info=\"The speech model to use for the transcription\",\n advanced=True,\n ),\n BoolInput(\n name=\"language_detection\",\n display_name=\"Automatic Language Detection\",\n info=\"Enable automatic language detection\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"language_code\",\n display_name=\"Language\",\n info=(\n \"\"\"\n The language of the audio file. Can be set manually if automatic language detection is disabled.\n See https://www.assemblyai.com/docs/getting-started/supported-languages \"\"\"\n \"for a list of supported language codes.\"\n ),\n advanced=True,\n ),\n BoolInput(\n name=\"speaker_labels\",\n display_name=\"Enable Speaker Labels\",\n info=\"Enable speaker diarization\",\n ),\n MessageTextInput(\n name=\"speakers_expected\",\n display_name=\"Expected Number of Speakers\",\n info=\"Set the expected number of speakers (optional, enter a number)\",\n advanced=True,\n ),\n BoolInput(\n name=\"punctuate\",\n display_name=\"Punctuate\",\n info=\"Enable automatic punctuation\",\n advanced=True,\n value=True,\n ),\n BoolInput(\n name=\"format_text\",\n display_name=\"Format Text\",\n info=\"Enable text formatting\",\n advanced=True,\n value=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Transcript ID\", name=\"transcript_id\", method=\"create_transcription_job\"),\n ]\n\n def create_transcription_job(self) -> Data:\n aai.settings.api_key = self.api_key\n\n # Convert speakers_expected to int if it's not empty\n speakers_expected = None\n if self.speakers_expected and self.speakers_expected.strip():\n try:\n speakers_expected = int(self.speakers_expected)\n except ValueError:\n self.status = \"Error: Expected Number of Speakers must be a valid integer\"\n return Data(data={\"error\": \"Error: Expected Number of Speakers must be a valid integer\"})\n\n language_code = self.language_code or None\n\n config = aai.TranscriptionConfig(\n speech_model=self.speech_model,\n language_detection=self.language_detection,\n language_code=language_code,\n speaker_labels=self.speaker_labels,\n speakers_expected=speakers_expected,\n punctuate=self.punctuate,\n format_text=self.format_text,\n )\n\n audio = None\n if self.audio_file:\n if self.audio_file_url:\n logger.warning(\"Both an audio file an audio URL were specified. The audio URL was ignored.\")\n\n # Check if the file exists\n if not Path(self.audio_file).exists():\n self.status = \"Error: Audio file not found\"\n return Data(data={\"error\": \"Error: Audio file not found\"})\n audio = self.audio_file\n elif self.audio_file_url:\n audio = self.audio_file_url\n else:\n self.status = \"Error: Either an audio file or an audio URL must be specified\"\n return Data(data={\"error\": \"Error: Either an audio file or an audio URL must be specified\"})\n\n try:\n transcript = aai.Transcriber().submit(audio, config=config)\n except Exception as e: # noqa: BLE001\n logger.opt(exception=True).debug(\"Error submitting transcription job\")\n self.status = f\"An error occurred: {e}\"\n return Data(data={\"error\": f\"An error occurred: {e}\"})\n\n if transcript.error:\n self.status = transcript.error\n return Data(data={\"error\": transcript.error})\n result = Data(data={\"transcript_id\": transcript.id})\n self.status = result\n return result\n"
+ },
+ "format_text": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Format Text",
+ "dynamic": false,
+ "info": "Enable text formatting",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "format_text",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "language_code": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Language",
+ "dynamic": false,
+ "info": "\n The language of the audio file. Can be set manually if automatic language detection is disabled.\n See https://www.assemblyai.com/docs/getting-started/supported-languages for a list of supported language codes.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "language_code",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "language_detection": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Automatic Language Detection",
+ "dynamic": false,
+ "info": "Enable automatic language detection",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "language_detection",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": false
+ },
+ "punctuate": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Punctuate",
+ "dynamic": false,
+ "info": "Enable automatic punctuation",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "punctuate",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "speaker_labels": {
+ "_input_type": "BoolInput",
+ "advanced": false,
+ "display_name": "Enable Speaker Labels",
+ "dynamic": false,
+ "info": "Enable speaker diarization",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "speaker_labels",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "speakers_expected": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Expected Number of Speakers",
+ "dynamic": false,
+ "info": "Set the expected number of speakers (optional, enter a number)",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "speakers_expected",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "speech_model": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Speech Model",
+ "dynamic": false,
+ "info": "The speech model to use for the transcription",
+ "name": "speech_model",
+ "options": [
+ "best",
+ "nano"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "best"
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": true,
+ "type": "AssemblyAITranscriptionJobCreator"
+ },
+ "dragging": false,
+ "id": "AssemblyAITranscriptionJobCreator-ylQES",
+ "measured": {
+ "height": 373,
+ "width": 320
+ },
+ "position": {
+ "x": 515.589850902064,
+ "y": 232.58183434411956
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "note-fB5Sk",
+ "node": {
+ "description": "# Meeting Summary Generator\n\nThis flow automatically transcribes and summarizes meetings by converting audio recordings into concise summaries using **AssemblyAI** and **OpenAI GPT-4**. \n\n## Prerequisites\n\n- **[AssemblyAI API Key](https://www.assemblyai.com/)**\n- **[OpenAI API Key](https://platform.openai.com/)**\n\n## Quickstart\n\n1. Upload an audio file. Most common audio file formats are [supported](https://github.com/langflow-ai/langflow/blob/main/src/backend/base/langflow/components/assemblyai/assemblyai_start_transcript.py#L27).\n2. To run the summary generator flow, click **Playground**.\n\nThe flow transcribes the audio using **AssemblyAI**.\nThe transcript is formatted for AI processing.\nThe **GPT-4** model extracts key points and insights.\nThe summarized meeting details are displayed in a chat-friendly format.\n\n\n\n",
+ "display_name": "",
+ "documentation": "",
+ "template": {}
+ },
+ "type": "note"
+ },
+ "dragging": false,
+ "height": 612,
+ "id": "note-fB5Sk",
+ "measured": {
+ "height": 612,
+ "width": 549
+ },
+ "position": {
+ "x": -128.87171443390673,
+ "y": 227.16742082405324
+ },
+ "resizing": false,
+ "selected": false,
+ "type": "noteNode",
+ "width": 548
+ }
+ ],
+ "viewport": {
+ "x": 199.66634321516733,
+ "y": -38.61016993098076,
+ "zoom": 0.49475443116609724
+ }
+ },
+ "description": "An AI-powered meeting summary generator that transcribes and summarizes meetings using AssemblyAI and OpenAI for quick insights.",
+ "endpoint_name": "meeting_summary",
+ "icon": "headset",
+ "id": "5b99326e-70dc-4c7a-b791-67665ee1dac3",
+ "is_component": false,
+ "last_tested_version": "1.1.5",
+ "name": "Meeting Summary",
+ "tags": [
+ "chatbots",
+ "content-generation"
+ ]
+}
\ No newline at end of file
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json b/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json
index d9b3f0553c..8c154dfe68 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json
@@ -8,17 +8,12 @@
"dataType": "Memory",
"id": "Memory-gWJrq",
"name": "messages_text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "memory",
"id": "Prompt-yhdMP",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
@@ -36,16 +31,12 @@
"dataType": "ChatInput",
"id": "ChatInput-PEO9d",
"name": "message",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "OpenAIModel-63o3Q",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -63,16 +54,12 @@
"dataType": "Prompt",
"id": "Prompt-yhdMP",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "system_message",
"id": "OpenAIModel-63o3Q",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -90,16 +77,12 @@
"dataType": "OpenAIModel",
"id": "OpenAIModel-63o3Q",
"name": "text_output",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "ChatOutput-BIXzI",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -116,9 +99,7 @@
"data": {
"id": "ChatInput-PEO9d",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -152,9 +133,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -167,9 +146,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -189,9 +166,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -294,10 +269,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -313,9 +285,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -335,9 +305,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -373,9 +341,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -419,9 +385,7 @@
"display_name": "Chat Output",
"id": "ChatOutput-BIXzI",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -455,9 +419,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -470,9 +432,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -492,9 +452,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -532,9 +490,7 @@
"display_name": "Data Template",
"dynamic": false,
"info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "data_template",
@@ -554,9 +510,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Message to be passed as output.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -577,10 +531,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -596,9 +547,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -618,9 +567,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -656,9 +603,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -767,10 +712,7 @@
"data": {
"id": "Memory-gWJrq",
"node": {
- "base_classes": [
- "Data",
- "Message"
- ],
+ "base_classes": ["Data", "Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -802,9 +744,7 @@
"name": "messages",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
},
{
@@ -815,9 +755,7 @@
"name": "messages_text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -848,9 +786,7 @@
"display_name": "External Memory",
"dynamic": false,
"info": "Retrieve messages from an external memory. If empty, it will use the Langflow tables.",
- "input_types": [
- "Memory"
- ],
+ "input_types": ["Memory"],
"list": false,
"name": "memory",
"placeholder": "",
@@ -885,10 +821,7 @@
"dynamic": false,
"info": "Order of the messages.",
"name": "order",
- "options": [
- "Ascending",
- "Descending"
- ],
+ "options": ["Ascending", "Descending"],
"placeholder": "",
"required": false,
"show": true,
@@ -906,11 +839,7 @@
"dynamic": false,
"info": "Filter by sender type.",
"name": "sender",
- "options": [
- "Machine",
- "User",
- "Machine and User"
- ],
+ "options": ["Machine", "User", "Machine and User"],
"placeholder": "",
"required": false,
"show": true,
@@ -926,9 +855,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Filter by sender name.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -948,9 +875,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -970,9 +895,7 @@
"display_name": "Template",
"dynamic": false,
"info": "The template to use for formatting the data. It can contain the keys {text}, {sender} or any other key in the message data.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1015,24 +938,18 @@
"data": {
"id": "Prompt-yhdMP",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
- "template": [
- "memory"
- ]
+ "template": ["memory"]
},
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
"documentation": "",
"edited": false,
"error": null,
- "field_order": [
- "template"
- ],
+ "field_order": ["template"],
"frozen": false,
"full_path": null,
"icon": "prompts",
@@ -1053,9 +970,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1088,10 +1003,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1126,9 +1038,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -1170,10 +1080,7 @@
"data": {
"id": "OpenAIModel-63o3Q",
"node": {
- "base_classes": [
- "LanguageModel",
- "Message"
- ],
+ "base_classes": ["LanguageModel", "Message"],
"beta": false,
"category": "models",
"conditional_paths": [],
@@ -1212,9 +1119,7 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -1223,14 +1128,10 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
- "required_inputs": [
- "api_key"
- ],
+ "required_inputs": ["api_key"],
"selected": "LanguageModel",
"tool_mode": true,
- "types": [
- "LanguageModel"
- ],
+ "types": ["LanguageModel"],
"value": "__UNDEFINED__"
}
],
@@ -1244,9 +1145,7 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -1255,7 +1154,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"code": {
"advanced": true,
@@ -1281,9 +1180,7 @@
"display_name": "Input",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1465,9 +1362,7 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1563,9 +1458,5 @@
"is_component": false,
"last_tested_version": "1.0.19.post2",
"name": "Memory Chatbot",
- "tags": [
- "chatbots",
- "openai",
- "assistants"
- ]
-}
\ No newline at end of file
+ "tags": ["chatbots", "openai", "assistants"]
+}
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json b/src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json
new file mode 100644
index 0000000000..5e2488579d
--- /dev/null
+++ b/src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json
@@ -0,0 +1,1733 @@
+{
+ "data": {
+ "edges": [
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "AgentQL",
+ "id": "AgentQL-mPzt1",
+ "name": "component_as_tool",
+ "output_types": [
+ "Tool"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "tools",
+ "id": "Agent-VOnBt",
+ "inputTypes": [
+ "Tool"
+ ],
+ "type": "other"
+ }
+ },
+ "id": "xy-edge__AgentQL-mPzt1{œdataTypeœ:œAgentQLœ,œidœ:œAgentQL-mPzt1œ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-VOnBt{œfieldNameœ:œtoolsœ,œidœ:œAgent-VOnBtœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}",
+ "source": "AgentQL-mPzt1",
+ "sourceHandle": "{œdataTypeœ: œAgentQLœ, œidœ: œAgentQL-mPzt1œ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}",
+ "target": "Agent-VOnBt",
+ "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-VOnBtœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "Agent",
+ "id": "Agent-VOnBt",
+ "name": "response",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "input_value",
+ "id": "ChatOutput-SyzjF",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "xy-edge__Agent-VOnBt{œdataTypeœ:œAgentœ,œidœ:œAgent-VOnBtœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-SyzjF{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-SyzjFœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "Agent-VOnBt",
+ "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-VOnBtœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "ChatOutput-SyzjF",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-SyzjFœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "ChatInput",
+ "id": "ChatInput-5A2FR",
+ "name": "message",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "input_value",
+ "id": "Agent-VOnBt",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "xy-edge__ChatInput-5A2FR{œdataTypeœ:œChatInputœ,œidœ:œChatInput-5A2FRœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-VOnBt{œfieldNameœ:œinput_valueœ,œidœ:œAgent-VOnBtœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "ChatInput-5A2FR",
+ "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-5A2FRœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Agent-VOnBt",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-VOnBtœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ }
+ ],
+ "nodes": [
+ {
+ "data": {
+ "id": "note-LzOM2",
+ "node": {
+ "description": "### 💡 Add your OpenAI API key here",
+ "display_name": "",
+ "documentation": "",
+ "template": {
+ "backgroundColor": "transparent"
+ }
+ },
+ "type": "note"
+ },
+ "dragging": false,
+ "id": "note-LzOM2",
+ "measured": {
+ "height": 324,
+ "width": 324
+ },
+ "position": {
+ "x": 1170.377736042162,
+ "y": 143.70815416701694
+ },
+ "selected": false,
+ "type": "noteNode"
+ },
+ {
+ "data": {
+ "id": "note-u8dIb",
+ "node": {
+ "description": "### 💡 Add your AgentQL API key here",
+ "display_name": "",
+ "documentation": "",
+ "template": {
+ "backgroundColor": "transparent"
+ }
+ },
+ "type": "note"
+ },
+ "dragging": false,
+ "height": 346,
+ "id": "note-zgc96",
+ "measured": {
+ "height": 346,
+ "width": 324
+ },
+ "position": {
+ "x": 741.8464477206785,
+ "y": 270.1565987952192
+ },
+ "selected": true,
+ "type": "noteNode"
+ },
+ {
+ "data": {
+ "id": "AgentQL-mPzt1",
+ "node": {
+ "base_classes": [
+ "Data"
+ ],
+ "beta": false,
+ "category": "agentql",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Uses AgentQL API to extract structured data from a given URL.",
+ "display_name": "AgentQL Query Data",
+ "documentation": "https://docs.agentql.com/rest-api/api-reference",
+ "edited": false,
+ "field_order": [
+ "api_key",
+ "url",
+ "query",
+ "timeout",
+ "params"
+ ],
+ "frozen": false,
+ "icon": "AgentQL",
+ "key": "AgentQL",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": false,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Toolset",
+ "hidden": null,
+ "method": "to_toolkit",
+ "name": "component_as_tool",
+ "required_inputs": null,
+ "selected": "Tool",
+ "tool_mode": true,
+ "types": [
+ "Tool"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 7.517768383416648e-6,
+ "template": {
+ "_type": "Component",
+ "api_key": {
+ "_input_type": "SecretStrInput",
+ "advanced": false,
+ "display_name": "AgentQL API Key",
+ "dynamic": false,
+ "info": "Your AgentQL API key. Get one at https://dev.agentql.com.",
+ "input_types": [
+ "Message"
+ ],
+ "load_from_db": true,
+ "name": "api_key",
+ "password": true,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.io import (\n DictInput,\n IntInput,\n MessageTextInput,\n MultilineInput,\n Output,\n SecretStrInput,\n)\nfrom langflow.schema import Data\n\n\nclass AgentQL(Component):\n display_name = \"AgentQL Query Data\"\n description = \"Uses AgentQL API to extract structured data from a given URL.\"\n documentation: str = \"https://docs.agentql.com/rest-api/api-reference\"\n icon = \"AgentQL\"\n name = \"AgentQL\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"AgentQL API Key\",\n required=True,\n password=True,\n info=\"Your AgentQL API key. Get one at https://dev.agentql.com.\",\n ),\n MessageTextInput(\n name=\"url\",\n display_name=\"URL\",\n required=True,\n info=\"The public URL of the webpage to extract data from.\",\n tool_mode=True,\n ),\n MultilineInput(\n name=\"query\",\n display_name=\"AgentQL Query\",\n required=True,\n info=\"The AgentQL query to execute. Read more at https://docs.agentql.com/agentql-query.\",\n tool_mode=True,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"Timeout in seconds for the request. Increase if data extraction takes too long.\",\n value=900,\n advanced=True,\n ),\n DictInput(\n name=\"params\",\n display_name=\"Additional Params\",\n info=\"The additional params to send with the request. For details refer to https://docs.agentql.com/rest-api/api-reference#request-body.\",\n is_list=True,\n value={\n \"mode\": \"fast\",\n \"wait_for\": 0,\n \"is_scroll_to_bottom_enabled\": False,\n \"is_screenshot_enabled\": False,\n },\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"build_output\"),\n ]\n\n def build_output(self) -> Data:\n endpoint = \"https://api.agentql.com/v1/query-data\"\n headers = {\n \"X-API-Key\": self.api_key,\n \"Content-Type\": \"application/json\",\n }\n\n payload = {\n \"url\": self.url,\n \"query\": self.query,\n \"params\": self.params,\n }\n\n try:\n response = httpx.post(endpoint, headers=headers, json=payload, timeout=self.timeout)\n response.raise_for_status()\n\n json = response.json()\n data = Data(result=json[\"data\"], metadata=json[\"metadata\"])\n\n except httpx.HTTPStatusError as e:\n response = e.response\n if response.status_code in {401, 403}:\n self.status = \"Please, provide a valid API Key. You can create one at https://dev.agentql.com.\"\n else:\n try:\n error_json = response.json()\n logger.error(\n f\"Failure response: '{response.status_code} {response.reason_phrase}' with body: {error_json}\"\n )\n msg = error_json[\"error_info\"] if \"error_info\" in error_json else error_json[\"detail\"]\n except (ValueError, TypeError):\n msg = f\"HTTP {e}.\"\n self.status = msg\n raise ValueError(self.status) from e\n\n else:\n self.status = data\n return data\n"
+ },
+ "params": {
+ "_input_type": "DictInput",
+ "advanced": true,
+ "display_name": "Additional Params",
+ "dynamic": false,
+ "info": "The additional params to send with the request. For details refer to https://docs.agentql.com/rest-api/api-reference#request-body.",
+ "list": true,
+ "list_add_label": "Add More",
+ "name": "params",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "type": "dict",
+ "value": {
+ "is_screenshot_enabled": false,
+ "is_scroll_to_bottom_enabled": false,
+ "mode": "fast",
+ "wait_for": 0
+ }
+ },
+ "query": {
+ "_input_type": "MultilineInput",
+ "advanced": false,
+ "display_name": "AgentQL Query",
+ "dynamic": false,
+ "info": "The AgentQL query to execute. Read more at https://docs.agentql.com/agentql-query.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "query",
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": true,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "timeout": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Timeout",
+ "dynamic": false,
+ "info": "Timeout in seconds for the request. Increase if data extraction takes too long.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "timeout",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 900
+ },
+ "tools_metadata": {
+ "_input_type": "TableInput",
+ "advanced": false,
+ "display_name": "Edit tools",
+ "dynamic": false,
+ "info": "",
+ "is_list": true,
+ "list_add_label": "Add More",
+ "name": "tools_metadata",
+ "placeholder": "",
+ "real_time_refresh": true,
+ "required": false,
+ "show": true,
+ "table_icon": "Hammer",
+ "table_options": {
+ "block_add": true,
+ "block_delete": true,
+ "block_edit": true,
+ "block_filter": true,
+ "block_hide": true,
+ "block_select": true,
+ "block_sort": true,
+ "description": "Modify tool names and descriptions to help agents understand when to use each tool.",
+ "field_parsers": {
+ "commands": "commands",
+ "name": [
+ "snake_case",
+ "no_blank"
+ ]
+ },
+ "hide_options": true
+ },
+ "table_schema": {
+ "columns": [
+ {
+ "description": "Specify the name of the tool.",
+ "disable_edit": false,
+ "display_name": "Tool Name",
+ "edit_mode": "inline",
+ "filterable": false,
+ "formatter": "text",
+ "name": "name",
+ "sortable": false,
+ "type": "text"
+ },
+ {
+ "description": "Describe the purpose of the tool.",
+ "disable_edit": false,
+ "display_name": "Tool Description",
+ "edit_mode": "popover",
+ "filterable": false,
+ "formatter": "text",
+ "name": "description",
+ "sortable": false,
+ "type": "text"
+ },
+ {
+ "description": "The default identifiers for the tools and cannot be changed.",
+ "disable_edit": true,
+ "display_name": "Tool Identifiers",
+ "edit_mode": "inline",
+ "filterable": false,
+ "formatter": "text",
+ "name": "tags",
+ "sortable": false,
+ "type": "text"
+ }
+ ]
+ },
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "trigger_icon": "Hammer",
+ "trigger_text": "",
+ "type": "table",
+ "value": [
+ {
+ "description": "build_output(api_key: Message, query: Message, url: Message) - Uses AgentQL API to extract structured data from a given URL.",
+ "name": "AgentQL-build_output",
+ "tags": [
+ "AgentQL-build_output"
+ ]
+ }
+ ]
+ },
+ "url": {
+ "_input_type": "MessageTextInput",
+ "advanced": false,
+ "display_name": "URL",
+ "dynamic": false,
+ "info": "The public URL of the webpage to extract data from.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "url",
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": true,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": true
+ },
+ "showNode": true,
+ "type": "AgentQL"
+ },
+ "dragging": false,
+ "id": "AgentQL-mPzt1",
+ "measured": {
+ "height": 499,
+ "width": 320
+ },
+ "position": {
+ "x": 746.6171255053692,
+ "y": 323.12336325015775
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "ChatInput-5A2FR",
+ "node": {
+ "base_classes": [
+ "Message"
+ ],
+ "beta": false,
+ "category": "inputs",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Get chat inputs from the Playground.",
+ "display_name": "Chat Input",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "input_value",
+ "should_store_message",
+ "sender",
+ "sender_name",
+ "session_id",
+ "files",
+ "background_color",
+ "chat_icon",
+ "text_color"
+ ],
+ "frozen": false,
+ "icon": "MessagesSquare",
+ "key": "ChatInput",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": true,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Message",
+ "method": "message_response",
+ "name": "message",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 0.0020353564437605998,
+ "template": {
+ "_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import (\n DropdownInput,\n FileInput,\n MessageTextInput,\n MultilineInput,\n Output,\n)\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_USER,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n minimized = True\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n input_types=[],\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n async def message_response(self) -> Message:\n background_color = self.background_color\n text_color = self.text_color\n icon = self.chat_icon\n\n message = await Message.create(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n properties={\n \"background_color\": background_color,\n \"text_color\": text_color,\n \"icon\": icon,\n },\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = await self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ },
+ "files": {
+ "_input_type": "FileInput",
+ "advanced": true,
+ "display_name": "Files",
+ "dynamic": false,
+ "fileTypes": [
+ "txt",
+ "md",
+ "mdx",
+ "csv",
+ "json",
+ "yaml",
+ "yml",
+ "xml",
+ "html",
+ "htm",
+ "pdf",
+ "docx",
+ "py",
+ "sh",
+ "sql",
+ "js",
+ "ts",
+ "tsx",
+ "jpg",
+ "jpeg",
+ "png",
+ "bmp",
+ "image"
+ ],
+ "file_path": "",
+ "info": "Files to be sent with the message.",
+ "list": true,
+ "list_add_label": "Add More",
+ "name": "files",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_metadata": true,
+ "type": "file",
+ "value": ""
+ },
+ "input_value": {
+ "_input_type": "MultilineInput",
+ "advanced": false,
+ "display_name": "Text",
+ "dynamic": false,
+ "info": "Message to be passed as input.",
+ "input_types": [],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "input_value",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "sender": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Sender Type",
+ "dynamic": false,
+ "info": "Type of sender.",
+ "name": "sender",
+ "options": [
+ "Machine",
+ "User"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "User"
+ },
+ "sender_name": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Sender Name",
+ "dynamic": false,
+ "info": "Name of the sender.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "sender_name",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "User"
+ },
+ "session_id": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Session ID",
+ "dynamic": false,
+ "info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "session_id",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "should_store_message": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Store Messages",
+ "dynamic": false,
+ "info": "Store the message in the history.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "should_store_message",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": false,
+ "type": "ChatInput"
+ },
+ "dragging": false,
+ "id": "ChatInput-5A2FR",
+ "measured": {
+ "height": 66,
+ "width": 192
+ },
+ "position": {
+ "x": 414.26981499855697,
+ "y": 618.0969310476024
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "ChatOutput-SyzjF",
+ "node": {
+ "base_classes": [
+ "Message"
+ ],
+ "beta": false,
+ "category": "outputs",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Display a chat message in the Playground.",
+ "display_name": "Chat Output",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "input_value",
+ "should_store_message",
+ "sender",
+ "sender_name",
+ "session_id",
+ "data_template",
+ "background_color",
+ "chat_icon",
+ "text_color"
+ ],
+ "frozen": false,
+ "icon": "MessagesSquare",
+ "key": "ChatOutput",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": true,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Message",
+ "method": "message_response",
+ "name": "message",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 0.007568328950209746,
+ "template": {
+ "_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Source\nfrom langflow.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_AI,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n minimized = True\n\n inputs = [\n MessageInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, id_: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if id_:\n source_dict[\"id\"] = id_\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n source_dict[\"source\"] = source\n return Source(**source_dict)\n\n async def message_response(self) -> Message:\n source, icon, display_name, source_id = self.get_properties_from_source_component()\n background_color = self.background_color\n text_color = self.text_color\n if self.chat_icon:\n icon = self.chat_icon\n message = self.input_value if isinstance(self.input_value, Message) else Message(text=self.input_value)\n message.sender = self.sender\n message.sender_name = self.sender_name\n message.session_id = self.session_id\n message.flow_id = self.graph.flow_id if hasattr(self, \"graph\") else None\n message.properties.source = self._build_source(source_id, display_name, source)\n message.properties.icon = icon\n message.properties.background_color = background_color\n message.properties.text_color = text_color\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = await self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ },
+ "data_template": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Data Template",
+ "dynamic": false,
+ "info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "data_template",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "{text}"
+ },
+ "input_value": {
+ "_input_type": "MessageInput",
+ "advanced": false,
+ "display_name": "Text",
+ "dynamic": false,
+ "info": "Message to be passed as output.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "input_value",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "sender": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Sender Type",
+ "dynamic": false,
+ "info": "Type of sender.",
+ "name": "sender",
+ "options": [
+ "Machine",
+ "User"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "Machine"
+ },
+ "sender_name": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Sender Name",
+ "dynamic": false,
+ "info": "Name of the sender.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "sender_name",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "AI"
+ },
+ "session_id": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Session ID",
+ "dynamic": false,
+ "info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "session_id",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "should_store_message": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Store Messages",
+ "dynamic": false,
+ "info": "Store the message in the history.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "should_store_message",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": false,
+ "type": "ChatOutput"
+ },
+ "dragging": false,
+ "id": "ChatOutput-SyzjF",
+ "measured": {
+ "height": 66,
+ "width": 192
+ },
+ "position": {
+ "x": 1564.8269684087277,
+ "y": 540
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "Agent-VOnBt",
+ "node": {
+ "base_classes": [
+ "Message"
+ ],
+ "beta": false,
+ "category": "agents",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Define the agent's instructions, then enter a task to complete using tools.",
+ "display_name": "Agent",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "agent_llm",
+ "max_tokens",
+ "model_kwargs",
+ "json_mode",
+ "model_name",
+ "openai_api_base",
+ "api_key",
+ "temperature",
+ "seed",
+ "max_retries",
+ "timeout",
+ "system_prompt",
+ "tools",
+ "input_value",
+ "handle_parsing_errors",
+ "verbose",
+ "max_iterations",
+ "agent_description",
+ "memory",
+ "sender",
+ "sender_name",
+ "n_messages",
+ "session_id",
+ "order",
+ "template",
+ "add_current_date_tool"
+ ],
+ "frozen": false,
+ "icon": "bot",
+ "key": "Agent",
+ "legacy": false,
+ "lf_version": "1.1.5",
+ "metadata": {},
+ "minimized": false,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Response",
+ "method": "message_response",
+ "name": "response",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 1.1732828199964098e-19,
+ "template": {
+ "_type": "Component",
+ "add_current_date_tool": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Current Date",
+ "dynamic": false,
+ "info": "If true, will add a tool to the agent that returns the current date.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "add_current_date_tool",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "agent_description": {
+ "_input_type": "MultilineInput",
+ "advanced": true,
+ "display_name": "Agent Description [Deprecated]",
+ "dynamic": false,
+ "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "agent_description",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "A helpful assistant with access to the following tools:"
+ },
+ "agent_llm": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Model Provider",
+ "dynamic": false,
+ "info": "The provider of the language model that the agent will use to generate responses.",
+ "input_types": [],
+ "name": "agent_llm",
+ "options": [
+ "Amazon Bedrock",
+ "Anthropic",
+ "Azure OpenAI",
+ "Google Generative AI",
+ "Groq",
+ "NVIDIA",
+ "OpenAI",
+ "SambaNova",
+ "Custom"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "real_time_refresh": true,
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "OpenAI"
+ },
+ "api_key": {
+ "_input_type": "SecretStrInput",
+ "advanced": false,
+ "display_name": "OpenAI API Key",
+ "dynamic": false,
+ "info": "The OpenAI API Key to use for the OpenAI model.",
+ "input_types": [
+ "Message"
+ ],
+ "load_from_db": true,
+ "name": "api_key",
+ "password": true,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS_DICT,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS_DICT.keys()), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n\n # Validate tools\n if not self.tools:\n msg = \"Tools are required to run the agent. Please add at least one tool.\"\n raise ValueError(msg)\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools,\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS_DICT.keys()), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def to_toolkit(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=self.get_tool_name(), tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n"
+ },
+ "handle_parsing_errors": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Handle Parse Errors",
+ "dynamic": false,
+ "info": "Should the Agent fix errors when reading user input for better processing?",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "handle_parsing_errors",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "input_value": {
+ "_input_type": "MessageTextInput",
+ "advanced": false,
+ "display_name": "Input",
+ "dynamic": false,
+ "info": "The input provided by the user for the agent to process.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "input_value",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": true,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "json_mode": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "JSON Mode",
+ "dynamic": false,
+ "info": "If True, it will output JSON regardless of passing a schema.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "json_mode",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": false
+ },
+ "max_iterations": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Max Iterations",
+ "dynamic": false,
+ "info": "The maximum number of attempts the agent can make to complete its task before it stops.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "max_iterations",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 15
+ },
+ "max_retries": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Max Retries",
+ "dynamic": false,
+ "info": "The maximum number of retries to make when generating.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "max_retries",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 5
+ },
+ "max_tokens": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Max Tokens",
+ "dynamic": false,
+ "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "max_tokens",
+ "placeholder": "",
+ "range_spec": {
+ "max": 128000,
+ "min": 0,
+ "step": 0.1,
+ "step_type": "float"
+ },
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": ""
+ },
+ "memory": {
+ "_input_type": "HandleInput",
+ "advanced": true,
+ "display_name": "External Memory",
+ "dynamic": false,
+ "info": "Retrieve messages from an external memory. If empty, it will use the Langflow tables.",
+ "input_types": [
+ "Memory"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "memory",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_metadata": true,
+ "type": "other",
+ "value": ""
+ },
+ "model_kwargs": {
+ "_input_type": "DictInput",
+ "advanced": true,
+ "display_name": "Model Kwargs",
+ "dynamic": false,
+ "info": "Additional keyword arguments to pass to the model.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "model_kwargs",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "type": "dict",
+ "value": {}
+ },
+ "model_name": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": true,
+ "dialog_inputs": {},
+ "display_name": "Model Name",
+ "dynamic": false,
+ "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.",
+ "name": "model_name",
+ "options": [
+ "gpt-4o-mini",
+ "gpt-4o",
+ "gpt-4-turbo",
+ "gpt-4-turbo-preview",
+ "gpt-4",
+ "gpt-3.5-turbo",
+ "gpt-3.5-turbo-0125"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "real_time_refresh": false,
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "gpt-4o-mini"
+ },
+ "n_messages": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Number of Messages",
+ "dynamic": false,
+ "info": "Number of messages to retrieve.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "n_messages",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 100
+ },
+ "openai_api_base": {
+ "_input_type": "StrInput",
+ "advanced": true,
+ "display_name": "OpenAI API Base",
+ "dynamic": false,
+ "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.",
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "openai_api_base",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "order": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Order",
+ "dynamic": false,
+ "info": "Order of the messages.",
+ "name": "order",
+ "options": [
+ "Ascending",
+ "Descending"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "Ascending"
+ },
+ "seed": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Seed",
+ "dynamic": false,
+ "info": "The seed controls the reproducibility of the job.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "seed",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 1
+ },
+ "sender": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Sender Type",
+ "dynamic": false,
+ "info": "Filter by sender type.",
+ "name": "sender",
+ "options": [
+ "Machine",
+ "User",
+ "Machine and User"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "Machine and User"
+ },
+ "sender_name": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Sender Name",
+ "dynamic": false,
+ "info": "Filter by sender name.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "sender_name",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "session_id": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Session ID",
+ "dynamic": false,
+ "info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "session_id",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "system_prompt": {
+ "_input_type": "MultilineInput",
+ "advanced": false,
+ "display_name": "Agent Instructions",
+ "dynamic": false,
+ "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "system_prompt",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "You are a helpful assistant that can use tools to answer questions and perform tasks."
+ },
+ "temperature": {
+ "_input_type": "SliderInput",
+ "advanced": true,
+ "display_name": "Temperature",
+ "dynamic": false,
+ "info": "",
+ "max_label": "",
+ "max_label_icon": "",
+ "min_label": "",
+ "min_label_icon": "",
+ "name": "temperature",
+ "placeholder": "",
+ "range_spec": {
+ "max": 2,
+ "min": 0,
+ "step": 0.01,
+ "step_type": "float"
+ },
+ "required": false,
+ "show": true,
+ "slider_buttons": false,
+ "slider_buttons_options": [],
+ "slider_input": false,
+ "title_case": false,
+ "tool_mode": false,
+ "type": "slider",
+ "value": 0.1
+ },
+ "template": {
+ "_input_type": "MultilineInput",
+ "advanced": true,
+ "display_name": "Template",
+ "dynamic": false,
+ "info": "The template to use for formatting the data. It can contain the keys {text}, {sender} or any other key in the message data.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "template",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "{sender_name}: {text}"
+ },
+ "timeout": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Timeout",
+ "dynamic": false,
+ "info": "The timeout for requests to OpenAI completion API.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "timeout",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 700
+ },
+ "tools": {
+ "_input_type": "HandleInput",
+ "advanced": false,
+ "display_name": "Tools",
+ "dynamic": false,
+ "info": "These are the tools that the agent can use to help with tasks.",
+ "input_types": [
+ "Tool"
+ ],
+ "list": true,
+ "list_add_label": "Add More",
+ "name": "tools",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_metadata": true,
+ "type": "other",
+ "value": ""
+ },
+ "verbose": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Verbose",
+ "dynamic": false,
+ "info": "",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "verbose",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": true,
+ "type": "Agent"
+ },
+ "dragging": false,
+ "id": "Agent-VOnBt",
+ "measured": {
+ "height": 624,
+ "width": 320
+ },
+ "position": {
+ "x": 1176.7234802624862,
+ "y": 190.59802023099996
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "note-16o52",
+ "node": {
+ "description": "# News Aggregator\n\nThis flow extracts structured data from a URL.\n## Prerequisites\n\n* **[AgentQL API Key](https://dev.agentql.com/api-keys)**\n* **[OpenAI API Key](https://platform.openai.com/)**\n\n## Quick Start\n\n1. Add your [AgentQL API Key](https://dev.agentql.com/api-keys) to the **AgentQL** component.\n2. Add your [OpenAI API Key](https://platform.openai.com/) to the **Agent** component.\n3. Click **Playground** and enter a question.\nThe **Agent** component populates the **Agent QL** component's **URL** and **Query** fields, and returns a structured response to your question.",
+ "display_name": "",
+ "documentation": "",
+ "template": {
+ "backgroundColor": "amber"
+ }
+ },
+ "type": "note"
+ },
+ "dragging": false,
+ "id": "note-16o52",
+ "measured": {
+ "height": 581,
+ "width": 404
+ },
+ "position": {
+ "x": 215.10951666579462,
+ "y": -25.20466668876412
+ },
+ "selected": true,
+ "type": "noteNode"
+ }
+ ],
+ "viewport": {
+ "x": 12.487929830752307,
+ "y": 53.296431264065234,
+ "zoom": 0.4998778160758756
+ }
+ },
+ "description": "Extracts data and information from webpages.",
+ "endpoint_name": null,
+ "icon": "Newspaper",
+ "id": "4b857ff3-595a-4902-874f-f591bd804fa1",
+ "is_component": false,
+ "last_tested_version": "1.1.5",
+ "name": "News Aggregator",
+ "tags": [
+ "web-scraping",
+ "agents"
+ ]
+}
\ No newline at end of file
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Portfolio Website Code Generator.json b/src/backend/base/langflow/initial_setup/starter_projects/Portfolio Website Code Generator.json
index e350b33d4a..972aaf86b1 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Portfolio Website Code Generator.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Portfolio Website Code Generator.json
@@ -9,16 +9,12 @@
"dataType": "Prompt",
"id": "Prompt-ysecC",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "StructuredOutput-TArXO",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -36,16 +32,12 @@
"dataType": "StructuredOutput",
"id": "StructuredOutput-TArXO",
"name": "structured_output",
- "output_types": [
- "Data"
- ]
+ "output_types": ["Data"]
},
"targetHandle": {
"fieldName": "data",
"id": "ParseData-x7Rgx",
- "inputTypes": [
- "Data"
- ],
+ "inputTypes": ["Data"],
"type": "other"
}
},
@@ -63,16 +55,12 @@
"dataType": "ParseData",
"id": "ParseData-sGhWo",
"name": "text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "resume",
"id": "Prompt-ysecC",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -90,16 +78,12 @@
"dataType": "AnthropicModel",
"id": "AnthropicModel-sHFTc",
"name": "model_output",
- "output_types": [
- "LanguageModel"
- ]
+ "output_types": ["LanguageModel"]
},
"targetHandle": {
"fieldName": "llm",
"id": "StructuredOutput-TArXO",
- "inputTypes": [
- "LanguageModel"
- ],
+ "inputTypes": ["LanguageModel"],
"type": "other"
}
},
@@ -117,16 +101,12 @@
"dataType": "ParseData",
"id": "ParseData-x7Rgx",
"name": "text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "AnthropicModel-IrjAe",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -144,16 +124,12 @@
"dataType": "TextInput",
"id": "TextInput-CPTOR",
"name": "text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "system_message",
"id": "AnthropicModel-IrjAe",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -171,16 +147,12 @@
"dataType": "AnthropicModel",
"id": "AnthropicModel-IrjAe",
"name": "text_output",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "ChatOutput-d1tmJ",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -197,16 +169,12 @@
"dataType": "File",
"id": "File-JgIx7",
"name": "data",
- "output_types": [
- "Data"
- ]
+ "output_types": ["Data"]
},
"targetHandle": {
"fieldName": "data",
"id": "ParseData-sGhWo",
- "inputTypes": [
- "Data"
- ],
+ "inputTypes": ["Data"],
"type": "other"
}
},
@@ -222,25 +190,18 @@
"data": {
"id": "Prompt-ysecC",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
- "template": [
- "resume"
- ]
+ "template": ["resume"]
},
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
"documentation": "",
"edited": false,
"error": null,
- "field_order": [
- "template",
- "tool_placeholder"
- ],
+ "field_order": ["template", "tool_placeholder"],
"frozen": false,
"full_path": null,
"icon": "prompts",
@@ -262,9 +223,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -297,9 +256,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -335,9 +292,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -375,10 +330,7 @@
"data": {
"id": "ParseData-sGhWo",
"node": {
- "base_classes": [
- "Data",
- "Message"
- ],
+ "base_classes": ["Data", "Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -386,16 +338,14 @@
"display_name": "Data to Message",
"documentation": "",
"edited": false,
- "field_order": [
- "data",
- "template",
- "sep"
- ],
+ "field_order": ["data", "template", "sep"],
"frozen": false,
"icon": "message-square",
"legacy": false,
"lf_version": "1.1.4.post1",
- "metadata": {},
+ "metadata": {
+ "legacy_name": "Parse Data"
+ },
"minimized": false,
"output_types": [],
"outputs": [
@@ -407,9 +357,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -420,9 +368,7 @@
"name": "data_list",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -445,7 +391,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\", is_list=True, required=True),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
+ "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n metadata = {\n \"legacy_name\": \"Parse Data\",\n }\n\n inputs = [\n DataInput(\n name=\"data\",\n display_name=\"Data\",\n info=\"The data to convert to text.\",\n is_list=True,\n required=True,\n ),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
},
"data": {
"_input_type": "DataInput",
@@ -453,9 +399,7 @@
"display_name": "Data",
"dynamic": false,
"info": "The data to convert to text.",
- "input_types": [
- "Data"
- ],
+ "input_types": ["Data"],
"list": true,
"list_add_label": "Add More",
"name": "data",
@@ -494,9 +438,7 @@
"display_name": "Template",
"dynamic": false,
"info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -535,9 +477,7 @@
"data": {
"id": "StructuredOutput-TArXO",
"node": {
- "base_classes": [
- "Data"
- ],
+ "base_classes": ["Data"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -569,9 +509,7 @@
"name": "structured_output",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -602,9 +540,7 @@
"display_name": "Input Message",
"dynamic": false,
"info": "The input message to the language model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -625,9 +561,7 @@
"display_name": "Language Model",
"dynamic": false,
"info": "The language model to use to generate the structured output.",
- "input_types": [
- "LanguageModel"
- ],
+ "input_types": ["LanguageModel"],
"list": false,
"list_add_label": "Add More",
"name": "llm",
@@ -846,10 +780,7 @@
"data": {
"id": "ParseData-x7Rgx",
"node": {
- "base_classes": [
- "Data",
- "Message"
- ],
+ "base_classes": ["Data", "Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -857,16 +788,14 @@
"display_name": "Data to Message",
"documentation": "",
"edited": false,
- "field_order": [
- "data",
- "template",
- "sep"
- ],
+ "field_order": ["data", "template", "sep"],
"frozen": false,
"icon": "message-square",
"legacy": false,
"lf_version": "1.1.4.post1",
- "metadata": {},
+ "metadata": {
+ "legacy_name": "Parse Data"
+ },
"minimized": false,
"output_types": [],
"outputs": [
@@ -878,9 +807,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -891,9 +818,7 @@
"name": "data_list",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -916,7 +841,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\", is_list=True, required=True),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
+ "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n metadata = {\n \"legacy_name\": \"Parse Data\",\n }\n\n inputs = [\n DataInput(\n name=\"data\",\n display_name=\"Data\",\n info=\"The data to convert to text.\",\n is_list=True,\n required=True,\n ),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
},
"data": {
"_input_type": "DataInput",
@@ -924,9 +849,7 @@
"display_name": "Data",
"dynamic": false,
"info": "The data to convert to text.",
- "input_types": [
- "Data"
- ],
+ "input_types": ["Data"],
"list": true,
"list_add_label": "Add More",
"name": "data",
@@ -965,9 +888,7 @@
"display_name": "Template",
"dynamic": false,
"info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1006,9 +927,7 @@
"data": {
"id": "TextInput-CPTOR",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"category": "inputs",
"conditional_paths": [],
@@ -1017,9 +936,7 @@
"display_name": "Text Input",
"documentation": "",
"edited": false,
- "field_order": [
- "input_value"
- ],
+ "field_order": ["input_value"],
"frozen": false,
"icon": "type",
"key": "TextInput",
@@ -1037,9 +954,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1071,9 +986,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Text to be passed as input.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1112,10 +1025,7 @@
"data": {
"id": "AnthropicModel-sHFTc",
"node": {
- "base_classes": [
- "LanguageModel",
- "Message"
- ],
+ "base_classes": ["LanguageModel", "Message"],
"beta": false,
"category": "models",
"conditional_paths": [],
@@ -1154,9 +1064,7 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -1165,14 +1073,10 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
- "required_inputs": [
- "api_key"
- ],
+ "required_inputs": ["api_key"],
"selected": "LanguageModel",
"tool_mode": true,
- "types": [
- "LanguageModel"
- ],
+ "types": ["LanguageModel"],
"value": "__UNDEFINED__"
}
],
@@ -1186,10 +1090,8 @@
"display_name": "Anthropic API Key",
"dynamic": false,
"info": "Your Anthropic API key.",
- "input_types": [
- "Message"
- ],
- "load_from_db": false,
+ "input_types": ["Message"],
+ "load_from_db": true,
"name": "api_key",
"password": true,
"placeholder": "",
@@ -1198,7 +1100,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "ANTHROPIC_API_KEY"
},
"base_url": {
"_input_type": "MessageTextInput",
@@ -1206,9 +1108,7 @@
"display_name": "Anthropic API URL",
"dynamic": false,
"info": "Endpoint of the Anthropic API. Defaults to 'https://api.anthropic.com' if not specified.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1248,9 +1148,7 @@
"display_name": "Input",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1319,9 +1217,7 @@
"display_name": "Prefill",
"dynamic": false,
"info": "Prefill text to guide the model's response.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1360,9 +1256,7 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1448,10 +1342,7 @@
"data": {
"id": "AnthropicModel-IrjAe",
"node": {
- "base_classes": [
- "LanguageModel",
- "Message"
- ],
+ "base_classes": ["LanguageModel", "Message"],
"beta": false,
"category": "models",
"conditional_paths": [],
@@ -1490,9 +1381,7 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -1501,14 +1390,10 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
- "required_inputs": [
- "api_key"
- ],
+ "required_inputs": ["api_key"],
"selected": "LanguageModel",
"tool_mode": true,
- "types": [
- "LanguageModel"
- ],
+ "types": ["LanguageModel"],
"value": "__UNDEFINED__"
}
],
@@ -1522,10 +1407,8 @@
"display_name": "Anthropic API Key",
"dynamic": false,
"info": "Your Anthropic API key.",
- "input_types": [
- "Message"
- ],
- "load_from_db": false,
+ "input_types": ["Message"],
+ "load_from_db": true,
"name": "api_key",
"password": true,
"placeholder": "",
@@ -1534,7 +1417,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "ANTHROPIC_API_KEY"
},
"base_url": {
"_input_type": "MessageTextInput",
@@ -1542,9 +1425,7 @@
"display_name": "Anthropic API URL",
"dynamic": false,
"info": "Endpoint of the Anthropic API. Defaults to 'https://api.anthropic.com' if not specified.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1584,9 +1465,7 @@
"display_name": "Input",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1655,9 +1534,7 @@
"display_name": "Prefill",
"dynamic": false,
"info": "Prefill text to guide the model's response.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1696,9 +1573,7 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1784,9 +1659,7 @@
"data": {
"id": "ChatOutput-d1tmJ",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"category": "outputs",
"conditional_paths": [],
@@ -1823,9 +1696,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1839,9 +1710,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1862,9 +1731,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1903,9 +1770,7 @@
"display_name": "Data Template",
"dynamic": false,
"info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1926,9 +1791,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Message to be passed as output.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1952,10 +1815,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"options_metadata": [],
"placeholder": "",
"required": false,
@@ -1972,9 +1832,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1995,9 +1853,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -2036,9 +1892,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -2076,9 +1930,7 @@
"data": {
"id": "File-JgIx7",
"node": {
- "base_classes": [
- "Data"
- ],
+ "base_classes": ["Data"],
"beta": false,
"category": "data",
"conditional_paths": [],
@@ -2114,9 +1966,7 @@
"required_inputs": [],
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -2184,10 +2034,7 @@
"display_name": "Server File Path",
"dynamic": false,
"info": "Data object with a 'file_path' property pointing to server file or a Message object with a path to the file. Supercedes 'Path' but supports same file types.",
- "input_types": [
- "Data",
- "Message"
- ],
+ "input_types": ["Data", "Message"],
"list": true,
"list_add_label": "Add More",
"name": "file_path",
@@ -2491,8 +2338,5 @@
"is_component": false,
"last_tested_version": "1.1.4",
"name": "Portfolio Website Code Generator",
- "tags": [
- "chatbots",
- "coding"
- ]
-}
\ No newline at end of file
+ "tags": ["chatbots", "coding"]
+}
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json b/src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json
new file mode 100644
index 0000000000..b4d3c3c77e
--- /dev/null
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json
@@ -0,0 +1,2137 @@
+{
+ "data": {
+ "edges": [
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "AgentQL",
+ "id": "AgentQL-6fb13",
+ "name": "component_as_tool",
+ "output_types": [
+ "Tool"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "tools",
+ "id": "Agent-7MSQT",
+ "inputTypes": [
+ "Tool"
+ ],
+ "type": "other"
+ }
+ },
+ "id": "reactflow__edge-AgentQL-6fb13{œdataTypeœ:œAgentQLœ,œidœ:œAgentQL-6fb13œ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-7MSQT{œfieldNameœ:œtoolsœ,œidœ:œAgent-7MSQTœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}",
+ "selected": false,
+ "source": "AgentQL-6fb13",
+ "sourceHandle": "{œdataTypeœ: œAgentQLœ, œidœ: œAgentQL-6fb13œ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}",
+ "target": "Agent-7MSQT",
+ "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-7MSQTœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "TavilySearchComponent",
+ "id": "TavilySearchComponent-141bi",
+ "name": "component_as_tool",
+ "output_types": [
+ "Tool"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "tools",
+ "id": "Agent-7MSQT",
+ "inputTypes": [
+ "Tool"
+ ],
+ "type": "other"
+ }
+ },
+ "id": "reactflow__edge-TavilySearchComponent-141bi{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-141biœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-7MSQT{œfieldNameœ:œtoolsœ,œidœ:œAgent-7MSQTœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}",
+ "selected": false,
+ "source": "TavilySearchComponent-141bi",
+ "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-141biœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}",
+ "target": "Agent-7MSQT",
+ "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-7MSQTœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "ChatInput",
+ "id": "ChatInput-X0wLK",
+ "name": "message",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "input_value",
+ "id": "Agent-7MSQT",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "reactflow__edge-ChatInput-X0wLK{œdataTypeœ:œChatInputœ,œidœ:œChatInput-X0wLKœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-7MSQT{œfieldNameœ:œinput_valueœ,œidœ:œAgent-7MSQTœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "ChatInput-X0wLK",
+ "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-X0wLKœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Agent-7MSQT",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-7MSQTœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "Agent",
+ "id": "Agent-7MSQT",
+ "name": "response",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "input_value",
+ "id": "ChatOutput-QZLoV",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "reactflow__edge-Agent-7MSQT{œdataTypeœ:œAgentœ,œidœ:œAgent-7MSQTœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-QZLoV{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-QZLoVœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "Agent-7MSQT",
+ "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-7MSQTœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "ChatOutput-QZLoV",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-QZLoVœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ }
+ ],
+ "nodes": [
+ {
+ "data": {
+ "id": "ChatInput-X0wLK",
+ "node": {
+ "base_classes": [
+ "Message"
+ ],
+ "beta": false,
+ "category": "inputs",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Get chat inputs from the Playground.",
+ "display_name": "Chat Input",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "input_value",
+ "should_store_message",
+ "sender",
+ "sender_name",
+ "session_id",
+ "files",
+ "background_color",
+ "chat_icon",
+ "text_color"
+ ],
+ "frozen": false,
+ "icon": "MessagesSquare",
+ "key": "ChatInput",
+ "legacy": false,
+ "lf_version": "1.1.4.post1",
+ "metadata": {},
+ "minimized": true,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Message",
+ "method": "message_response",
+ "name": "message",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 0.0020353564437605998,
+ "template": {
+ "_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import (\n DropdownInput,\n FileInput,\n MessageTextInput,\n MultilineInput,\n Output,\n)\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_USER,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatInput\"\n minimized = True\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\n input_types=[],\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_USER,\n info=\"Type of sender.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_USER,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n FileInput(\n name=\"files\",\n display_name=\"Files\",\n file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n info=\"Files to be sent with the message.\",\n advanced=True,\n is_list=True,\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n async def message_response(self) -> Message:\n background_color = self.background_color\n text_color = self.text_color\n icon = self.chat_icon\n\n message = await Message.create(\n text=self.input_value,\n sender=self.sender,\n sender_name=self.sender_name,\n session_id=self.session_id,\n files=self.files,\n properties={\n \"background_color\": background_color,\n \"text_color\": text_color,\n \"icon\": icon,\n },\n )\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = await self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ },
+ "files": {
+ "_input_type": "FileInput",
+ "advanced": true,
+ "display_name": "Files",
+ "dynamic": false,
+ "fileTypes": [
+ "txt",
+ "md",
+ "mdx",
+ "csv",
+ "json",
+ "yaml",
+ "yml",
+ "xml",
+ "html",
+ "htm",
+ "pdf",
+ "docx",
+ "py",
+ "sh",
+ "sql",
+ "js",
+ "ts",
+ "tsx",
+ "jpg",
+ "jpeg",
+ "png",
+ "bmp",
+ "image"
+ ],
+ "file_path": "",
+ "info": "Files to be sent with the message.",
+ "list": true,
+ "list_add_label": "Add More",
+ "name": "files",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_metadata": true,
+ "type": "file",
+ "value": ""
+ },
+ "input_value": {
+ "_input_type": "MultilineInput",
+ "advanced": false,
+ "display_name": "Text",
+ "dynamic": false,
+ "info": "Message to be passed as input.",
+ "input_types": [],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "input_value",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "sender": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Sender Type",
+ "dynamic": false,
+ "info": "Type of sender.",
+ "name": "sender",
+ "options": [
+ "Machine",
+ "User"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "User"
+ },
+ "sender_name": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Sender Name",
+ "dynamic": false,
+ "info": "Name of the sender.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "sender_name",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "User"
+ },
+ "session_id": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Session ID",
+ "dynamic": false,
+ "info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "session_id",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "should_store_message": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Store Messages",
+ "dynamic": false,
+ "info": "Store the message in the history.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "should_store_message",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": false,
+ "type": "ChatInput"
+ },
+ "dragging": false,
+ "id": "ChatInput-X0wLK",
+ "measured": {
+ "height": 66,
+ "width": 192
+ },
+ "position": {
+ "x": 32.99622536761149,
+ "y": 367.6878380048698
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "ChatOutput-QZLoV",
+ "node": {
+ "base_classes": [
+ "Message"
+ ],
+ "beta": false,
+ "category": "outputs",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Display a chat message in the Playground.",
+ "display_name": "Chat Output",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "input_value",
+ "should_store_message",
+ "sender",
+ "sender_name",
+ "session_id",
+ "data_template",
+ "background_color",
+ "chat_icon",
+ "text_color"
+ ],
+ "frozen": false,
+ "icon": "MessagesSquare",
+ "key": "ChatOutput",
+ "legacy": false,
+ "lf_version": "1.1.4.post1",
+ "metadata": {},
+ "minimized": true,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Message",
+ "method": "message_response",
+ "name": "message",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 0.00012027401062119145,
+ "template": {
+ "_type": "Component",
+ "background_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Background Color",
+ "dynamic": false,
+ "info": "The background color of the icon.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "background_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "chat_icon": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Icon",
+ "dynamic": false,
+ "info": "The icon of the message.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "chat_icon",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageInput, MessageTextInput, Output\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Source\nfrom langflow.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_AI,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n minimized = True\n\n inputs = [\n MessageInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, id_: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if id_:\n source_dict[\"id\"] = id_\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n source_dict[\"source\"] = source\n return Source(**source_dict)\n\n async def message_response(self) -> Message:\n source, icon, display_name, source_id = self.get_properties_from_source_component()\n background_color = self.background_color\n text_color = self.text_color\n if self.chat_icon:\n icon = self.chat_icon\n message = self.input_value if isinstance(self.input_value, Message) else Message(text=self.input_value)\n message.sender = self.sender\n message.sender_name = self.sender_name\n message.session_id = self.session_id\n message.flow_id = self.graph.flow_id if hasattr(self, \"graph\") else None\n message.properties.source = self._build_source(source_id, display_name, source)\n message.properties.icon = icon\n message.properties.background_color = background_color\n message.properties.text_color = text_color\n if self.session_id and isinstance(message, Message) and self.should_store_message:\n stored_message = await self.send_message(\n message,\n )\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n"
+ },
+ "data_template": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Data Template",
+ "dynamic": false,
+ "info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "data_template",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "{text}"
+ },
+ "input_value": {
+ "_input_type": "MessageInput",
+ "advanced": false,
+ "display_name": "Text",
+ "dynamic": false,
+ "info": "Message to be passed as output.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "input_value",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "sender": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Sender Type",
+ "dynamic": false,
+ "info": "Type of sender.",
+ "name": "sender",
+ "options": [
+ "Machine",
+ "User"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "Machine"
+ },
+ "sender_name": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Sender Name",
+ "dynamic": false,
+ "info": "Name of the sender.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "sender_name",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "AI"
+ },
+ "session_id": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Session ID",
+ "dynamic": false,
+ "info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "session_id",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "should_store_message": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Store Messages",
+ "dynamic": false,
+ "info": "Store the message in the history.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "should_store_message",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "text_color": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Text Color",
+ "dynamic": false,
+ "info": "The text color of the name",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "text_color",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": false,
+ "type": "ChatOutput"
+ },
+ "dragging": false,
+ "id": "ChatOutput-QZLoV",
+ "measured": {
+ "height": 66,
+ "width": 192
+ },
+ "position": {
+ "x": 1239.8390470797185,
+ "y": 313.42117075262695
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "TavilySearchComponent-141bi",
+ "node": {
+ "base_classes": [
+ "Data",
+ "Message"
+ ],
+ "beta": false,
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "**Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.",
+ "display_name": "Tavily AI Search",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "api_key",
+ "query",
+ "search_depth",
+ "topic",
+ "time_range",
+ "max_results",
+ "include_images",
+ "include_answer"
+ ],
+ "frozen": false,
+ "icon": "TavilyIcon",
+ "legacy": false,
+ "metadata": {},
+ "minimized": false,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Toolset",
+ "hidden": null,
+ "method": "to_toolkit",
+ "name": "component_as_tool",
+ "required_inputs": null,
+ "selected": "Tool",
+ "tool_mode": true,
+ "types": [
+ "Tool"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "template": {
+ "_type": "Component",
+ "api_key": {
+ "_input_type": "SecretStrInput",
+ "advanced": false,
+ "display_name": "Tavily API Key",
+ "dynamic": false,
+ "info": "Your Tavily API Key.",
+ "input_types": [
+ "Message"
+ ],
+ "load_from_db": true,
+ "name": "api_key",
+ "password": true,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily AI Search\"\n description = \"\"\"**Tavily AI** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n DropdownInput(\n name=\"time_range\",\n display_name=\"Time Range\",\n info=\"The time range back from the current date to include in the search results.\",\n options=[\"day\", \"week\", \"month\", \"year\"],\n value=None,\n advanced=True,\n combobox=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"fetch_content\"),\n Output(display_name=\"Text\", name=\"text\", method=\"fetch_content_text\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n \"time_range\": self.time_range,\n }\n\n with httpx.Client() as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n data_results.append(\n Data(\n text=content,\n data={\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n },\n )\n )\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_text(self) -> Message:\n data = self.fetch_content()\n result_string = data_to_text(\"{text}\", data)\n self.status = result_string\n return Message(text=result_string)\n"
+ },
+ "include_answer": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Include Answer",
+ "dynamic": false,
+ "info": "Include a short answer to original query.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "include_answer",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "include_images": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Include Images",
+ "dynamic": false,
+ "info": "Include a list of query-related images in the response.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "include_images",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "max_results": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Max Results",
+ "dynamic": false,
+ "info": "The maximum number of search results to return.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "max_results",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 5
+ },
+ "query": {
+ "_input_type": "MessageTextInput",
+ "advanced": false,
+ "display_name": "Search Query",
+ "dynamic": false,
+ "info": "The search query you want to execute with Tavily.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "query",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": true,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "search_depth": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Search Depth",
+ "dynamic": false,
+ "info": "The depth of the search.",
+ "name": "search_depth",
+ "options": [
+ "basic",
+ "advanced"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "advanced"
+ },
+ "time_range": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": true,
+ "dialog_inputs": {},
+ "display_name": "Time Range",
+ "dynamic": false,
+ "info": "The time range back from the current date to include in the search results.",
+ "name": "time_range",
+ "options": [
+ "day",
+ "week",
+ "month",
+ "year"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str"
+ },
+ "tools_metadata": {
+ "_input_type": "TableInput",
+ "advanced": false,
+ "display_name": "Edit tools",
+ "dynamic": false,
+ "info": "",
+ "is_list": true,
+ "list_add_label": "Add More",
+ "name": "tools_metadata",
+ "placeholder": "",
+ "real_time_refresh": true,
+ "required": false,
+ "show": true,
+ "table_icon": "Hammer",
+ "table_options": {
+ "block_add": true,
+ "block_delete": true,
+ "block_edit": true,
+ "block_filter": true,
+ "block_hide": true,
+ "block_select": true,
+ "block_sort": true,
+ "description": "Modify tool names and descriptions to help agents understand when to use each tool.",
+ "field_parsers": {
+ "commands": "commands",
+ "name": [
+ "snake_case",
+ "no_blank"
+ ]
+ },
+ "hide_options": true
+ },
+ "table_schema": {
+ "columns": [
+ {
+ "description": "Specify the name of the tool.",
+ "disable_edit": false,
+ "display_name": "Tool Name",
+ "edit_mode": "inline",
+ "filterable": false,
+ "formatter": "text",
+ "name": "name",
+ "sortable": false,
+ "type": "text"
+ },
+ {
+ "description": "Describe the purpose of the tool.",
+ "disable_edit": false,
+ "display_name": "Tool Description",
+ "edit_mode": "popover",
+ "filterable": false,
+ "formatter": "text",
+ "name": "description",
+ "sortable": false,
+ "type": "text"
+ },
+ {
+ "description": "The default identifiers for the tools and cannot be changed.",
+ "disable_edit": true,
+ "display_name": "Tool Identifiers",
+ "edit_mode": "inline",
+ "filterable": false,
+ "formatter": "text",
+ "name": "tags",
+ "sortable": false,
+ "type": "text"
+ }
+ ]
+ },
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "trigger_icon": "Hammer",
+ "trigger_text": "",
+ "type": "table",
+ "value": [
+ {
+ "description": "fetch_content(api_key: Message) - **Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.",
+ "name": "TavilySearchComponent-fetch_content",
+ "tags": [
+ "TavilySearchComponent-fetch_content"
+ ]
+ },
+ {
+ "description": "fetch_content_text(api_key: Message) - **Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.",
+ "name": "TavilySearchComponent-fetch_content_text",
+ "tags": [
+ "TavilySearchComponent-fetch_content_text"
+ ]
+ }
+ ]
+ },
+ "topic": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Search Topic",
+ "dynamic": false,
+ "info": "The category of the search.",
+ "name": "topic",
+ "options": [
+ "general",
+ "news"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "general"
+ }
+ },
+ "tool_mode": true
+ },
+ "showNode": true,
+ "type": "TavilySearchComponent"
+ },
+ "dragging": false,
+ "id": "TavilySearchComponent-141bi",
+ "measured": {
+ "height": 435,
+ "width": 320
+ },
+ "position": {
+ "x": 345.9762510966062,
+ "y": 500.79656821057074
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "AgentQL-6fb13",
+ "node": {
+ "base_classes": [
+ "Data"
+ ],
+ "beta": false,
+ "category": "agentql",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Uses AgentQL API to extract structured data from a given URL.",
+ "display_name": "AgentQL Query Data",
+ "documentation": "https://docs.agentql.com/rest-api/api-reference",
+ "edited": false,
+ "field_order": [
+ "api_key",
+ "url",
+ "query",
+ "timeout",
+ "params"
+ ],
+ "frozen": false,
+ "icon": "AgentQL",
+ "key": "AgentQL",
+ "legacy": false,
+ "lf_version": "1.1.4.post1",
+ "metadata": {},
+ "minimized": false,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Toolset",
+ "hidden": null,
+ "method": "to_toolkit",
+ "name": "component_as_tool",
+ "required_inputs": null,
+ "selected": "Tool",
+ "tool_mode": true,
+ "types": [
+ "Tool"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 7.517768383416648e-6,
+ "template": {
+ "_type": "Component",
+ "api_key": {
+ "_input_type": "SecretStrInput",
+ "advanced": false,
+ "display_name": "AgentQL API Key",
+ "dynamic": false,
+ "info": "Your AgentQL API key. Get one at https://dev.agentql.com.",
+ "input_types": [
+ "Message"
+ ],
+ "load_from_db": false,
+ "name": "api_key",
+ "password": true,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.io import (\n DictInput,\n IntInput,\n MessageTextInput,\n MultilineInput,\n Output,\n SecretStrInput,\n)\nfrom langflow.schema import Data\n\n\nclass AgentQL(Component):\n display_name = \"AgentQL Query Data\"\n description = \"Uses AgentQL API to extract structured data from a given URL.\"\n documentation: str = \"https://docs.agentql.com/rest-api/api-reference\"\n icon = \"AgentQL\"\n name = \"AgentQL\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"AgentQL API Key\",\n required=True,\n password=True,\n info=\"Your AgentQL API key. Get one at https://dev.agentql.com.\",\n ),\n MessageTextInput(\n name=\"url\",\n display_name=\"URL\",\n required=True,\n info=\"The public URL of the webpage to extract data from.\",\n tool_mode=True,\n ),\n MultilineInput(\n name=\"query\",\n display_name=\"AgentQL Query\",\n required=True,\n info=\"The AgentQL query to execute. Read more at https://docs.agentql.com/agentql-query.\",\n tool_mode=True,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"Timeout in seconds for the request. Increase if data extraction takes too long.\",\n value=900,\n advanced=True,\n ),\n DictInput(\n name=\"params\",\n display_name=\"Additional Params\",\n info=\"The additional params to send with the request. For details refer to https://docs.agentql.com/rest-api/api-reference#request-body.\",\n is_list=True,\n value={\n \"mode\": \"fast\",\n \"wait_for\": 0,\n \"is_scroll_to_bottom_enabled\": False,\n \"is_screenshot_enabled\": False,\n },\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"build_output\"),\n ]\n\n def build_output(self) -> Data:\n endpoint = \"https://api.agentql.com/v1/query-data\"\n headers = {\n \"X-API-Key\": self.api_key,\n \"Content-Type\": \"application/json\",\n }\n\n payload = {\n \"url\": self.url,\n \"query\": self.query,\n \"params\": self.params,\n }\n\n try:\n response = httpx.post(endpoint, headers=headers, json=payload, timeout=self.timeout)\n response.raise_for_status()\n\n json = response.json()\n data = Data(result=json[\"data\"], metadata=json[\"metadata\"])\n\n except httpx.HTTPStatusError as e:\n response = e.response\n if response.status_code in {401, 403}:\n self.status = \"Please, provide a valid API Key. You can create one at https://dev.agentql.com.\"\n else:\n try:\n error_json = response.json()\n logger.error(\n f\"Failure response: '{response.status_code} {response.reason_phrase}' with body: {error_json}\"\n )\n msg = error_json[\"error_info\"] if \"error_info\" in error_json else error_json[\"detail\"]\n except (ValueError, TypeError):\n msg = f\"HTTP {e}.\"\n self.status = msg\n raise ValueError(self.status) from e\n\n else:\n self.status = data\n return data\n"
+ },
+ "params": {
+ "_input_type": "DictInput",
+ "advanced": true,
+ "display_name": "Additional Params",
+ "dynamic": false,
+ "info": "The additional params to send with the request. For details refer to https://docs.agentql.com/rest-api/api-reference#request-body.",
+ "list": true,
+ "list_add_label": "Add More",
+ "name": "params",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "type": "dict",
+ "value": {
+ "is_screenshot_enabled": false,
+ "is_scroll_to_bottom_enabled": false,
+ "mode": "fast",
+ "wait_for": 0
+ }
+ },
+ "query": {
+ "_input_type": "MultilineInput",
+ "advanced": false,
+ "display_name": "AgentQL Query",
+ "dynamic": false,
+ "info": "The AgentQL query to execute. Read more at https://docs.agentql.com/agentql-query.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "query",
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": true,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "timeout": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Timeout",
+ "dynamic": false,
+ "info": "Timeout in seconds for the request. Increase if data extraction takes too long.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "timeout",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 900
+ },
+ "tools_metadata": {
+ "_input_type": "TableInput",
+ "advanced": false,
+ "display_name": "Edit tools",
+ "dynamic": false,
+ "info": "",
+ "is_list": true,
+ "list_add_label": "Add More",
+ "name": "tools_metadata",
+ "placeholder": "",
+ "real_time_refresh": true,
+ "required": false,
+ "show": true,
+ "table_icon": "Hammer",
+ "table_options": {
+ "block_add": true,
+ "block_delete": true,
+ "block_edit": true,
+ "block_filter": true,
+ "block_hide": true,
+ "block_select": true,
+ "block_sort": true,
+ "description": "Modify tool names and descriptions to help agents understand when to use each tool.",
+ "field_parsers": {
+ "commands": "commands",
+ "name": [
+ "snake_case",
+ "no_blank"
+ ]
+ },
+ "hide_options": true
+ },
+ "table_schema": {
+ "columns": [
+ {
+ "description": "Specify the name of the tool.",
+ "disable_edit": false,
+ "display_name": "Tool Name",
+ "edit_mode": "inline",
+ "filterable": false,
+ "formatter": "text",
+ "name": "name",
+ "sortable": false,
+ "type": "text"
+ },
+ {
+ "description": "Describe the purpose of the tool.",
+ "disable_edit": false,
+ "display_name": "Tool Description",
+ "edit_mode": "popover",
+ "filterable": false,
+ "formatter": "text",
+ "name": "description",
+ "sortable": false,
+ "type": "text"
+ },
+ {
+ "description": "The default identifiers for the tools and cannot be changed.",
+ "disable_edit": true,
+ "display_name": "Tool Identifiers",
+ "edit_mode": "inline",
+ "filterable": false,
+ "formatter": "text",
+ "name": "tags",
+ "sortable": false,
+ "type": "text"
+ }
+ ]
+ },
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "trigger_icon": "Hammer",
+ "trigger_text": "",
+ "type": "table",
+ "value": [
+ {
+ "description": "build_output(api_key: Message, query: Message, url: Message) - Uses AgentQL API to extract structured data from a given URL.",
+ "name": "AgentQL-build_output",
+ "tags": [
+ "AgentQL-build_output"
+ ]
+ }
+ ]
+ },
+ "url": {
+ "_input_type": "MessageTextInput",
+ "advanced": false,
+ "display_name": "URL",
+ "dynamic": false,
+ "info": "The public URL of the webpage to extract data from.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "url",
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": true,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ },
+ "tool_mode": true
+ },
+ "showNode": true,
+ "type": "AgentQL"
+ },
+ "dragging": false,
+ "id": "AgentQL-6fb13",
+ "measured": {
+ "height": 497,
+ "width": 320
+ },
+ "position": {
+ "x": 329.8776020848543,
+ "y": -114.65601128197832
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "Agent-7MSQT",
+ "node": {
+ "base_classes": [
+ "Message"
+ ],
+ "beta": false,
+ "category": "agents",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Define the agent's instructions, then enter a task to complete using tools.",
+ "display_name": "Agent",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "agent_llm",
+ "max_tokens",
+ "model_kwargs",
+ "json_mode",
+ "model_name",
+ "openai_api_base",
+ "api_key",
+ "temperature",
+ "seed",
+ "system_prompt",
+ "tools",
+ "input_value",
+ "handle_parsing_errors",
+ "verbose",
+ "max_iterations",
+ "agent_description",
+ "memory",
+ "sender",
+ "sender_name",
+ "n_messages",
+ "session_id",
+ "order",
+ "template",
+ "add_current_date_tool"
+ ],
+ "frozen": false,
+ "icon": "bot",
+ "key": "Agent",
+ "legacy": false,
+ "lf_version": "1.1.4.post1",
+ "metadata": {},
+ "minimized": false,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Response",
+ "method": "message_response",
+ "name": "response",
+ "selected": "Message",
+ "tool_mode": true,
+ "types": [
+ "Message"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 1.1732828199964098e-19,
+ "template": {
+ "_type": "Component",
+ "add_current_date_tool": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Current Date",
+ "dynamic": false,
+ "info": "If true, will add a tool to the agent that returns the current date.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "add_current_date_tool",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "agent_description": {
+ "_input_type": "MultilineInput",
+ "advanced": true,
+ "display_name": "Agent Description [Deprecated]",
+ "dynamic": false,
+ "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "agent_description",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "A helpful assistant with access to the following tools:"
+ },
+ "agent_llm": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Model Provider",
+ "dynamic": false,
+ "info": "The provider of the language model that the agent will use to generate responses.",
+ "input_types": [],
+ "name": "agent_llm",
+ "options": [
+ "Amazon Bedrock",
+ "Anthropic",
+ "Azure OpenAI",
+ "Google Generative AI",
+ "Groq",
+ "NVIDIA",
+ "OpenAI",
+ "SambaNova",
+ "Custom"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "real_time_refresh": true,
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "OpenAI"
+ },
+ "api_key": {
+ "_input_type": "SecretStrInput",
+ "advanced": false,
+ "display_name": "OpenAI API Key",
+ "dynamic": false,
+ "info": "The OpenAI API Key to use for the OpenAI model.",
+ "input_types": [
+ "Message"
+ ],
+ "load_from_db": false,
+ "name": "api_key",
+ "password": true,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "str",
+ "value": ""
+ },
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS_DICT,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS_DICT.keys()), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n\n # Validate tools\n if not self.tools:\n msg = \"Tools are required to run the agent. Please add at least one tool.\"\n raise ValueError(msg)\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools,\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS_DICT.keys()), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def to_toolkit(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=self.get_tool_name(), tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n"
+ },
+ "handle_parsing_errors": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Handle Parse Errors",
+ "dynamic": false,
+ "info": "Should the Agent fix errors when reading user input for better processing?",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "handle_parsing_errors",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ },
+ "input_value": {
+ "_input_type": "MessageTextInput",
+ "advanced": false,
+ "display_name": "Input",
+ "dynamic": false,
+ "info": "The input provided by the user for the agent to process.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "input_value",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": true,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "json_mode": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "JSON Mode",
+ "dynamic": false,
+ "info": "If True, it will output JSON regardless of passing a schema.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "json_mode",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": false
+ },
+ "max_iterations": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Max Iterations",
+ "dynamic": false,
+ "info": "The maximum number of attempts the agent can make to complete its task before it stops.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "max_iterations",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 15
+ },
+ "max_retries": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Max Retries",
+ "dynamic": false,
+ "info": "The maximum number of retries to make when generating.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "max_retries",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 5
+ },
+ "max_tokens": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Max Tokens",
+ "dynamic": false,
+ "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "max_tokens",
+ "placeholder": "",
+ "range_spec": {
+ "max": 128000,
+ "min": 0,
+ "step": 0.1,
+ "step_type": "float"
+ },
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": ""
+ },
+ "memory": {
+ "_input_type": "HandleInput",
+ "advanced": true,
+ "display_name": "External Memory",
+ "dynamic": false,
+ "info": "Retrieve messages from an external memory. If empty, it will use the Langflow tables.",
+ "input_types": [
+ "Memory"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "memory",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_metadata": true,
+ "type": "other",
+ "value": ""
+ },
+ "model_kwargs": {
+ "_input_type": "DictInput",
+ "advanced": true,
+ "display_name": "Model Kwargs",
+ "dynamic": false,
+ "info": "Additional keyword arguments to pass to the model.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "model_kwargs",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "type": "dict",
+ "value": {}
+ },
+ "model_name": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": true,
+ "dialog_inputs": {},
+ "display_name": "Model Name",
+ "dynamic": false,
+ "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.",
+ "name": "model_name",
+ "options": [
+ "gpt-4o-mini",
+ "gpt-4o",
+ "gpt-4-turbo",
+ "gpt-4-turbo-preview",
+ "gpt-4",
+ "gpt-3.5-turbo",
+ "gpt-3.5-turbo-0125"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "real_time_refresh": false,
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "gpt-4o-mini"
+ },
+ "n_messages": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Number of Messages",
+ "dynamic": false,
+ "info": "Number of messages to retrieve.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "n_messages",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 100
+ },
+ "openai_api_base": {
+ "_input_type": "StrInput",
+ "advanced": true,
+ "display_name": "OpenAI API Base",
+ "dynamic": false,
+ "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.",
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "openai_api_base",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "order": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Order",
+ "dynamic": false,
+ "info": "Order of the messages.",
+ "name": "order",
+ "options": [
+ "Ascending",
+ "Descending"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "Ascending"
+ },
+ "seed": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Seed",
+ "dynamic": false,
+ "info": "The seed controls the reproducibility of the job.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "seed",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 1
+ },
+ "sender": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Sender Type",
+ "dynamic": false,
+ "info": "Filter by sender type.",
+ "name": "sender",
+ "options": [
+ "Machine",
+ "User",
+ "Machine and User"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "Machine and User"
+ },
+ "sender_name": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Sender Name",
+ "dynamic": false,
+ "info": "Filter by sender name.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "sender_name",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "session_id": {
+ "_input_type": "MessageTextInput",
+ "advanced": true,
+ "display_name": "Session ID",
+ "dynamic": false,
+ "info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "session_id",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "system_prompt": {
+ "_input_type": "MultilineInput",
+ "advanced": false,
+ "display_name": "Agent Instructions",
+ "dynamic": false,
+ "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "system_prompt",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "You are an deal finder assistant that helps find and compare the prices of products across different e-commerce platforms. You must use the Tavily Search API to find the URLs of the ecommerce platforms that sell these products. Then use the AgentQL tool to extract the prices of the product in those websites. Make sure to include the name of the product, the shop name, and the price of the product. The price has to be retrieved, so if it can't don't include it.\n\nHere's how to write an AgentQL query:\n\nThe AgentQL query serves as the building block of your script. This guide shows you how AgentQL's query structure works and how to write a valid query.\n\n### Single term query\n\nA **single term query** enables you to retrieve a single element on the webpage. Here is an example of how you can write a single term query to retrieve a search box.\n\n```AgentQL\n{\n search_box\n}\n```\n\n### List term query\n\nA **list term query** enables you to retrieve a list of similar elements on the webpage. Here is an example of how you can write a list term query to retrieve a list of prices of apples.\n\n```AgentQL\n{\n apple_price[]\n}\n```\n\nYou can also specify the exact field you want to return in the list. Here is an example of how you can specify that you want the name and price from the list of products.\n\n```AgentQL\n{\n products[] {\n name\n price(integer)\n }\n}\n```\n\n### Combining single term queries and list term queries\n\nYou can query for both **single terms** and **list terms** by combining the preceding formats.\n\n```AgentQL\n{\n author\n date_of_birth\n book_titles[]\n}\n```\n\n### Giving context to queries\n\nThere two main ways you can provide additional context to your queries.\n\n#### Structural context\n\nYou can nest queries within parent containers to indicate that your target web element is in a particular section of the webpage.\n\n```AgentQL\n{\n footer {\n social_media_links[]\n }\n}\n```\n\n#### Semantic context\n\nYou can also provide a short description within parentheses to guide AgentQL in locating the right element(s).\n\n```AgentQL\n{\n footer {\n social_media_links(The icons that lead to Facebook, Snapchat, etc.)[]\n }\n}\n```\n\n### Syntax guidelines\n\nEnclose all AgentQL query terms within curly braces `{}`. The following query structure isn't valid because the term \"social_media_links\" is wrongly enclosed within parenthesis`()`.\n\n```AgentQL\n( # Should be {\n social_media_links(The icons that lead to Facebook, Snapchat, etc.)[]\n) # Should be }\n```\n\nYou can't include new lines in your semantic context. The following query structure isn't valid because the semantic context isn't contained within one line.\n\n```AgentQL\n{\n social_media_links(The icons that lead\n to Facebook, Snapchat, etc.)[]\n}\n```"
+ },
+ "temperature": {
+ "_input_type": "SliderInput",
+ "advanced": true,
+ "display_name": "Temperature",
+ "dynamic": false,
+ "info": "",
+ "max_label": "",
+ "max_label_icon": "",
+ "min_label": "",
+ "min_label_icon": "",
+ "name": "temperature",
+ "placeholder": "",
+ "range_spec": {
+ "max": 2,
+ "min": 0,
+ "step": 0.01,
+ "step_type": "float"
+ },
+ "required": false,
+ "show": true,
+ "slider_buttons": false,
+ "slider_buttons_options": [],
+ "slider_input": false,
+ "title_case": false,
+ "tool_mode": false,
+ "type": "slider",
+ "value": 0.1
+ },
+ "template": {
+ "_input_type": "MultilineInput",
+ "advanced": true,
+ "display_name": "Template",
+ "dynamic": false,
+ "info": "The template to use for formatting the data. It can contain the keys {text}, {sender} or any other key in the message data.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "template",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "{sender_name}: {text}"
+ },
+ "timeout": {
+ "_input_type": "IntInput",
+ "advanced": true,
+ "display_name": "Timeout",
+ "dynamic": false,
+ "info": "The timeout for requests to OpenAI completion API.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "timeout",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 700
+ },
+ "tools": {
+ "_input_type": "HandleInput",
+ "advanced": false,
+ "display_name": "Tools",
+ "dynamic": false,
+ "info": "These are the tools that the agent can use to help with tasks.",
+ "input_types": [
+ "Tool"
+ ],
+ "list": true,
+ "list_add_label": "Add More",
+ "name": "tools",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_metadata": true,
+ "type": "other",
+ "value": ""
+ },
+ "verbose": {
+ "_input_type": "BoolInput",
+ "advanced": true,
+ "display_name": "Verbose",
+ "dynamic": false,
+ "info": "",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "verbose",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "bool",
+ "value": true
+ }
+ },
+ "tool_mode": false
+ },
+ "showNode": true,
+ "type": "Agent"
+ },
+ "dragging": false,
+ "id": "Agent-7MSQT",
+ "measured": {
+ "height": 621,
+ "width": 320
+ },
+ "position": {
+ "x": 783.7651594706487,
+ "y": -83.86659665829183
+ },
+ "selected": false,
+ "type": "genericNode"
+ },
+ {
+ "data": {
+ "id": "note-atyJV",
+ "node": {
+ "description": "### 💡 Add your OpenAI API key here",
+ "display_name": "",
+ "documentation": "",
+ "template": {
+ "backgroundColor": "transparent"
+ }
+ },
+ "type": "note"
+ },
+ "dragging": false,
+ "id": "note-atyJV",
+ "measured": {
+ "height": 324,
+ "width": 324
+ },
+ "position": {
+ "x": 775.1028775592921,
+ "y": -131.5725508478389
+ },
+ "selected": false,
+ "type": "noteNode"
+ },
+ {
+ "data": {
+ "id": "note-jHwfH",
+ "node": {
+ "description": "### 💡 Add your AgentQL API key here",
+ "display_name": "",
+ "documentation": "",
+ "template": {
+ "backgroundColor": "transparent"
+ }
+ },
+ "type": "note"
+ },
+ "dragging": false,
+ "height": 346,
+ "id": "note-jHwfH",
+ "measured": {
+ "height": 346,
+ "width": 324
+ },
+ "position": {
+ "x": 328.21954223681814,
+ "y": -160.4106577664784
+ },
+ "selected": false,
+ "type": "noteNode"
+ },
+ {
+ "data": {
+ "id": "note-5TPRO",
+ "node": {
+ "description": "# Price Deal Finder \n\nThis flow extracts structured data from a URL.\n## Prerequisites\n\n* **[AgentQL API Key](https://dev.agentql.com/api-keys)**\n* **[OpenAI API Key](https://platform.openai.com/)**\n* **[TavilyAI Search API Key](https://tavily.com/)**\n\n## Quick Start\n\n1. Add your [AgentQL API Key](https://dev.agentql.com/api-keys) to the **AgentQL** component.\n2. Add your [OpenAI API Key](https://platform.openai.com/) to the **Agent** component.\n3. Add your [TavilyAI Search API Key](https://tavily.com/) to the **Tavily AI Search** component.\n4. Click **Playground** and enter a product in chat. For example, search \"Nintendo Switch - OLed Model - w/ White Joy-Con\")\n* The **Agent** component populates the **Tavily AI Search** component's **Search Query** field, and the **Agent QL** component's **URL** and **Query** fields. \n\n* The **Agent** returns a structured response to your searcn in the chat.",
+ "display_name": "",
+ "documentation": "",
+ "template": {}
+ },
+ "type": "note"
+ },
+ "dragging": false,
+ "height": 674,
+ "id": "note-5TPRO",
+ "measured": {
+ "height": 674,
+ "width": 467
+ },
+ "position": {
+ "x": -472.5459222813072,
+ "y": 102.70113417861305
+ },
+ "resizing": false,
+ "selected": false,
+ "type": "noteNode",
+ "width": 466
+ },
+ {
+ "data": {
+ "id": "note-eqJwa",
+ "node": {
+ "description": "### 💡 Add your Tavily AI Search key here",
+ "display_name": "",
+ "documentation": "",
+ "template": {
+ "backgroundColor": "transparent"
+ }
+ },
+ "type": "note"
+ },
+ "dragging": false,
+ "height": 324,
+ "id": "note-eqJwa",
+ "measured": {
+ "height": 324,
+ "width": 344
+ },
+ "position": {
+ "x": 331.0865722920669,
+ "y": 447.2225407807426
+ },
+ "resizing": false,
+ "selected": false,
+ "type": "noteNode",
+ "width": 345
+ }
+ ],
+ "viewport": {
+ "x": 443.6808096885552,
+ "y": 80.83479654841267,
+ "zoom": 0.7762365447780835
+ }
+ },
+ "description": "Searches and compares product prices across multiple e-commerce platforms. ",
+ "endpoint_name": null,
+ "id": "ab091b94-13c1-42af-9f9b-3689e99fb0bf",
+ "is_component": false,
+ "last_tested_version": "1.1.5",
+ "tags": [
+ "web-scraping",
+ "agents"
+ ],
+ "name": "Price Deal Finder"
+}
\ No newline at end of file
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json
index d55f8e39d5..99e7ccb41f 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json
@@ -7,28 +7,23 @@
"data": {
"sourceHandle": {
"dataType": "ChatInput",
- "id": "ChatInput-hasDY",
+ "id": "ChatInput-0hxgs",
"name": "message",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
- "id": "Prompt-GxcHe",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "id": "Prompt-xI9hs",
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
- "id": "reactflow__edge-ChatInput-hasDY{œdataTypeœ:œChatInputœ,œidœ:œChatInput-hasDYœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-GxcHe{œfieldNameœ:œinput_valueœ,œidœ:œPrompt-GxcHeœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
+ "id": "reactflow__edge-ChatInput-0hxgs{œdataTypeœ:œChatInputœ,œidœ:œChatInput-0hxgsœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-xI9hs{œfieldNameœ:œinput_valueœ,œidœ:œPrompt-xI9hsœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
"selected": false,
- "source": "ChatInput-hasDY",
- "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-hasDYœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Prompt-GxcHe",
- "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œPrompt-GxcHeœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
+ "source": "ChatInput-0hxgs",
+ "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-0hxgsœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Prompt-xI9hs",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œPrompt-xI9hsœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
},
{
"animated": false,
@@ -36,27 +31,23 @@
"data": {
"sourceHandle": {
"dataType": "Prompt",
- "id": "Prompt-oCyQS",
+ "id": "Prompt-Zc4Af",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
- "id": "Agent-7qOlO",
- "inputTypes": [
- "Message"
- ],
+ "id": "Agent-Gbt8L",
+ "inputTypes": ["Message"],
"type": "str"
}
},
- "id": "reactflow__edge-Prompt-oCyQS{œdataTypeœ:œPromptœ,œidœ:œPrompt-oCyQSœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-7qOlO{œfieldNameœ:œinput_valueœ,œidœ:œAgent-7qOlOœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "id": "reactflow__edge-Prompt-Zc4Af{œdataTypeœ:œPromptœ,œidœ:œPrompt-Zc4Afœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-Gbt8L{œfieldNameœ:œinput_valueœ,œidœ:œAgent-Gbt8Lœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
"selected": false,
- "source": "Prompt-oCyQS",
- "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-oCyQSœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Agent-7qOlO",
- "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-7qOlOœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "source": "Prompt-Zc4Af",
+ "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-Zc4Afœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Agent-Gbt8L",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-Gbt8Lœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"animated": false,
@@ -64,211 +55,177 @@
"data": {
"sourceHandle": {
"dataType": "Agent",
- "id": "Agent-7qOlO",
+ "id": "Agent-Gbt8L",
"name": "response",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "search_results",
- "id": "Prompt-GxcHe",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "id": "Prompt-xI9hs",
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
- "id": "reactflow__edge-Agent-7qOlO{œdataTypeœ:œAgentœ,œidœ:œAgent-7qOlOœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Prompt-GxcHe{œfieldNameœ:œsearch_resultsœ,œidœ:œPrompt-GxcHeœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
+ "id": "reactflow__edge-Agent-Gbt8L{œdataTypeœ:œAgentœ,œidœ:œAgent-Gbt8Lœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Prompt-xI9hs{œfieldNameœ:œsearch_resultsœ,œidœ:œPrompt-xI9hsœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
"selected": false,
- "source": "Agent-7qOlO",
- "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-7qOlOœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Prompt-GxcHe",
- "targetHandle": "{œfieldNameœ: œsearch_resultsœ, œidœ: œPrompt-GxcHeœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
+ "source": "Agent-Gbt8L",
+ "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-Gbt8Lœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Prompt-xI9hs",
+ "targetHandle": "{œfieldNameœ: œsearch_resultsœ, œidœ: œPrompt-xI9hsœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
},
{
"className": "",
"data": {
"sourceHandle": {
"dataType": "TavilySearchComponent",
- "id": "TavilySearchComponent-oJz7N",
+ "id": "TavilySearchComponent-622t2",
"name": "component_as_tool",
- "output_types": [
- "Tool"
- ]
+ "output_types": ["Tool"]
},
"targetHandle": {
"fieldName": "tools",
- "id": "Agent-7qOlO",
- "inputTypes": [
- "Tool"
- ],
+ "id": "Agent-Gbt8L",
+ "inputTypes": ["Tool"],
"type": "other"
}
},
- "id": "reactflow__edge-TavilySearchComponent-oJz7N{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-oJz7Nœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-7qOlO{œfieldNameœ:œtoolsœ,œidœ:œAgent-7qOlOœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}",
- "source": "TavilySearchComponent-oJz7N",
- "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-oJz7Nœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}",
- "target": "Agent-7qOlO",
- "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-7qOlOœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}"
+ "id": "reactflow__edge-TavilySearchComponent-622t2{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-622t2œ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-Gbt8L{œfieldNameœ:œtoolsœ,œidœ:œAgent-Gbt8Lœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}",
+ "source": "TavilySearchComponent-622t2",
+ "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-622t2œ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}",
+ "target": "Agent-Gbt8L",
+ "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-Gbt8Lœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}"
},
{
"className": "",
"data": {
"sourceHandle": {
"dataType": "Prompt",
- "id": "Prompt-2yPE7",
+ "id": "Prompt-bxgAA",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "system_message",
- "id": "OpenAIModel-VcHpk",
- "inputTypes": [
- "Message"
- ],
+ "id": "OpenAIModel-iiRQd",
+ "inputTypes": ["Message"],
"type": "str"
}
},
- "id": "reactflow__edge-Prompt-2yPE7{œdataTypeœ:œPromptœ,œidœ:œPrompt-2yPE7œ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-VcHpk{œfieldNameœ:œsystem_messageœ,œidœ:œOpenAIModel-VcHpkœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
- "source": "Prompt-2yPE7",
- "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-2yPE7œ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
- "target": "OpenAIModel-VcHpk",
- "targetHandle": "{œfieldNameœ: œsystem_messageœ, œidœ: œOpenAIModel-VcHpkœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-Prompt-bxgAA{œdataTypeœ:œPromptœ,œidœ:œPrompt-bxgAAœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-iiRQd{œfieldNameœ:œsystem_messageœ,œidœ:œOpenAIModel-iiRQdœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "Prompt-bxgAA",
+ "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-bxgAAœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "OpenAIModel-iiRQd",
+ "targetHandle": "{œfieldNameœ: œsystem_messageœ, œidœ: œOpenAIModel-iiRQdœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"className": "",
"data": {
"sourceHandle": {
"dataType": "ChatInput",
- "id": "ChatInput-hasDY",
+ "id": "ChatInput-0hxgs",
"name": "message",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
- "id": "OpenAIModel-VcHpk",
- "inputTypes": [
- "Message"
- ],
+ "id": "OpenAIModel-iiRQd",
+ "inputTypes": ["Message"],
"type": "str"
}
},
- "id": "reactflow__edge-ChatInput-hasDY{œdataTypeœ:œChatInputœ,œidœ:œChatInput-hasDYœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-VcHpk{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-VcHpkœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
- "source": "ChatInput-hasDY",
- "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-hasDYœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
- "target": "OpenAIModel-VcHpk",
- "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-VcHpkœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-ChatInput-0hxgs{œdataTypeœ:œChatInputœ,œidœ:œChatInput-0hxgsœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-iiRQd{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-iiRQdœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "ChatInput-0hxgs",
+ "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-0hxgsœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "OpenAIModel-iiRQd",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-iiRQdœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"className": "",
"data": {
"sourceHandle": {
"dataType": "OpenAIModel",
- "id": "OpenAIModel-VcHpk",
+ "id": "OpenAIModel-iiRQd",
"name": "text_output",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "previous_response",
- "id": "Prompt-oCyQS",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "id": "Prompt-Zc4Af",
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
- "id": "reactflow__edge-OpenAIModel-VcHpk{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-VcHpkœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-oCyQS{œfieldNameœ:œprevious_responseœ,œidœ:œPrompt-oCyQSœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
- "source": "OpenAIModel-VcHpk",
- "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-VcHpkœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Prompt-oCyQS",
- "targetHandle": "{œfieldNameœ: œprevious_responseœ, œidœ: œPrompt-oCyQSœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-OpenAIModel-iiRQd{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-iiRQdœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-Zc4Af{œfieldNameœ:œprevious_responseœ,œidœ:œPrompt-Zc4Afœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
+ "source": "OpenAIModel-iiRQd",
+ "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-iiRQdœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Prompt-Zc4Af",
+ "targetHandle": "{œfieldNameœ: œprevious_responseœ, œidœ: œPrompt-Zc4Afœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
},
{
"className": "",
"data": {
"sourceHandle": {
"dataType": "Prompt",
- "id": "Prompt-GxcHe",
+ "id": "Prompt-xI9hs",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
- "id": "OpenAIModel-zDrcf",
- "inputTypes": [
- "Message"
- ],
+ "id": "OpenAIModel-rQIeM",
+ "inputTypes": ["Message"],
"type": "str"
}
},
- "id": "reactflow__edge-Prompt-GxcHe{œdataTypeœ:œPromptœ,œidœ:œPrompt-GxcHeœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-zDrcf{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-zDrcfœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
- "source": "Prompt-GxcHe",
- "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-GxcHeœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
- "target": "OpenAIModel-zDrcf",
- "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-zDrcfœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-Prompt-xI9hs{œdataTypeœ:œPromptœ,œidœ:œPrompt-xI9hsœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-rQIeM{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-rQIeMœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "Prompt-xI9hs",
+ "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-xI9hsœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "OpenAIModel-rQIeM",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-rQIeMœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"className": "",
"data": {
"sourceHandle": {
"dataType": "Prompt",
- "id": "Prompt-OoSJu",
+ "id": "Prompt-ZbmDf",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "system_message",
- "id": "OpenAIModel-zDrcf",
- "inputTypes": [
- "Message"
- ],
+ "id": "OpenAIModel-rQIeM",
+ "inputTypes": ["Message"],
"type": "str"
}
},
- "id": "reactflow__edge-Prompt-OoSJu{œdataTypeœ:œPromptœ,œidœ:œPrompt-OoSJuœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-zDrcf{œfieldNameœ:œsystem_messageœ,œidœ:œOpenAIModel-zDrcfœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
- "source": "Prompt-OoSJu",
- "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-OoSJuœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
- "target": "OpenAIModel-zDrcf",
- "targetHandle": "{œfieldNameœ: œsystem_messageœ, œidœ: œOpenAIModel-zDrcfœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-Prompt-ZbmDf{œdataTypeœ:œPromptœ,œidœ:œPrompt-ZbmDfœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-rQIeM{œfieldNameœ:œsystem_messageœ,œidœ:œOpenAIModel-rQIeMœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "Prompt-ZbmDf",
+ "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-ZbmDfœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "OpenAIModel-rQIeM",
+ "targetHandle": "{œfieldNameœ: œsystem_messageœ, œidœ: œOpenAIModel-rQIeMœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"className": "",
"data": {
"sourceHandle": {
"dataType": "OpenAIModel",
- "id": "OpenAIModel-zDrcf",
+ "id": "OpenAIModel-rQIeM",
"name": "text_output",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
- "id": "ChatOutput-joWRG",
- "inputTypes": [
- "Message"
- ],
+ "id": "ChatOutput-C4LXq",
+ "inputTypes": ["Message"],
"type": "str"
}
},
- "id": "reactflow__edge-OpenAIModel-zDrcf{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-zDrcfœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-joWRG{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-joWRGœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
- "source": "OpenAIModel-zDrcf",
- "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-zDrcfœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
- "target": "ChatOutput-joWRG",
- "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-joWRGœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-OpenAIModel-rQIeM{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-rQIeMœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-C4LXq{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-C4LXqœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "OpenAIModel-rQIeM",
+ "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-rQIeMœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "ChatOutput-C4LXq",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-C4LXqœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
}
],
"nodes": [
@@ -276,25 +233,19 @@
"data": {
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
- "id": "Prompt-oCyQS",
+ "id": "Prompt-Zc4Af",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
- "template": [
- "previous_response"
- ]
+ "template": ["previous_response"]
},
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
"documentation": "",
"edited": false,
- "field_order": [
- "template"
- ],
+ "field_order": ["template"],
"frozen": false,
"icon": "prompts",
"legacy": false,
@@ -310,9 +261,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -345,10 +294,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -384,9 +330,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -407,7 +351,7 @@
},
"dragging": false,
"height": 347,
- "id": "Prompt-oCyQS",
+ "id": "Prompt-Zc4Af",
"measured": {
"height": 347,
"width": 320
@@ -426,11 +370,9 @@
},
{
"data": {
- "id": "ChatInput-hasDY",
+ "id": "ChatInput-0hxgs",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"category": "inputs",
"conditional_paths": [],
@@ -466,9 +408,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -481,9 +421,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -502,9 +440,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -605,10 +541,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -623,9 +556,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -644,9 +575,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -681,9 +610,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -702,7 +629,7 @@
},
"dragging": false,
"height": 234,
- "id": "ChatInput-hasDY",
+ "id": "ChatInput-0hxgs",
"measured": {
"height": 234,
"width": 320
@@ -723,11 +650,9 @@
"data": {
"description": "Display a chat message in the Playground.",
"display_name": "Chat Output",
- "id": "ChatOutput-joWRG",
+ "id": "ChatOutput-C4LXq",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -761,9 +686,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -776,9 +699,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -798,9 +719,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -838,9 +757,7 @@
"display_name": "Data Template",
"dynamic": false,
"info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "data_template",
@@ -860,9 +777,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Message to be passed as output.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -883,10 +798,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -902,9 +814,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -924,9 +834,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -962,9 +870,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -985,7 +891,7 @@
},
"dragging": true,
"height": 234,
- "id": "ChatOutput-joWRG",
+ "id": "ChatOutput-C4LXq",
"measured": {
"height": 234,
"width": 320
@@ -1006,26 +912,19 @@
"data": {
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
- "id": "Prompt-GxcHe",
+ "id": "Prompt-xI9hs",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
- "template": [
- "search_results",
- "input_value"
- ]
+ "template": ["search_results", "input_value"]
},
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
"documentation": "",
"edited": false,
- "field_order": [
- "template"
- ],
+ "field_order": ["template"],
"frozen": false,
"icon": "prompts",
"legacy": false,
@@ -1041,9 +940,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1076,10 +973,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1099,10 +993,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1138,9 +1029,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -1161,7 +1050,7 @@
},
"dragging": false,
"height": 433,
- "id": "Prompt-GxcHe",
+ "id": "Prompt-xI9hs",
"measured": {
"height": 433,
"width": 320
@@ -1180,7 +1069,7 @@
},
{
"data": {
- "id": "note-mVf0U",
+ "id": "note-opQtx",
"node": {
"description": "# Research Agent \n\nWelcome to the Research Agent! This flow helps you conduct in-depth research on various topics using AI-powered tools and analysis.\n\n## Instructions\n1. Enter Your Research Query\n - Type your research question or topic into the Chat Input node.\n - Be specific and clear about what you want to investigate.\n\n2. Generate Research Plan\n - The system will create a focused research plan based on your query.\n - This plan includes key search queries and priorities.\n\n3. Conduct Web Search\n - The Tavily AI Search tool will perform web searches using the generated queries.\n - It focuses on finding academic and reliable sources.\n\n4. Analyze and Synthesize\n - The AI agent will review the search results and create a comprehensive synthesis.\n - The report includes an executive summary, methodology, findings, and conclusions.\n\n5. Review the Output\n - Read the final report in the Chat Output node.\n - Use this information as a starting point for further research or decision-making.\n\nRemember: You can refine your initial query for more specific results! 🔍📊",
"display_name": "",
@@ -1193,7 +1082,7 @@
},
"dragging": false,
"height": 694,
- "id": "note-mVf0U",
+ "id": "note-opQtx",
"measured": {
"height": 694,
"width": 325
@@ -1219,11 +1108,9 @@
"data": {
"description": "Define the agent's instructions, then enter a task to complete using tools.",
"display_name": "Agent",
- "id": "Agent-7qOlO",
+ "id": "Agent-Gbt8L",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -1274,9 +1161,7 @@
"name": "response",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1305,9 +1190,7 @@
"display_name": "Agent Description [Deprecated]",
"dynamic": false,
"info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1358,9 +1241,7 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -1369,7 +1250,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"code": {
"advanced": true,
@@ -1411,9 +1292,7 @@
"display_name": "Input",
"dynamic": false,
"info": "The input provided by the user for the agent to process.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -1505,9 +1384,7 @@
"display_name": "External Memory",
"dynamic": false,
"info": "Retrieve messages from an external memory. If empty, it will use the Langflow tables.",
- "input_types": [
- "Memory"
- ],
+ "input_types": ["Memory"],
"list": false,
"name": "memory",
"placeholder": "",
@@ -1601,10 +1478,7 @@
"dynamic": false,
"info": "Order of the messages.",
"name": "order",
- "options": [
- "Ascending",
- "Descending"
- ],
+ "options": ["Ascending", "Descending"],
"placeholder": "",
"required": false,
"show": true,
@@ -1638,11 +1512,7 @@
"dynamic": false,
"info": "Filter by sender type.",
"name": "sender",
- "options": [
- "Machine",
- "User",
- "Machine and User"
- ],
+ "options": ["Machine", "User", "Machine and User"],
"placeholder": "",
"required": false,
"show": true,
@@ -1658,9 +1528,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Filter by sender name.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -1680,9 +1548,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -1702,9 +1568,7 @@
"display_name": "Agent Instructions",
"dynamic": false,
"info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1741,9 +1605,7 @@
"display_name": "Template",
"dynamic": false,
"info": "The template to use for formatting the data. It can contain the keys {text}, {sender} or any other key in the message data.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1782,9 +1644,7 @@
"display_name": "Tools",
"dynamic": false,
"info": "These are the tools that the agent can use to help with tasks.",
- "input_types": [
- "Tool"
- ],
+ "input_types": ["Tool"],
"list": true,
"name": "tools",
"placeholder": "",
@@ -1818,7 +1678,7 @@
},
"dragging": false,
"height": 658,
- "id": "Agent-7qOlO",
+ "id": "Agent-Gbt8L",
"measured": {
"height": 658,
"width": 320
@@ -1839,11 +1699,9 @@
"data": {
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
- "id": "Prompt-2yPE7",
+ "id": "Prompt-bxgAA",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
@@ -1853,9 +1711,7 @@
"display_name": "Prompt",
"documentation": "",
"edited": false,
- "field_order": [
- "template"
- ],
+ "field_order": ["template"],
"frozen": false,
"icon": "prompts",
"legacy": false,
@@ -1871,9 +1727,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1922,9 +1776,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -1945,7 +1797,7 @@
},
"dragging": false,
"height": 260,
- "id": "Prompt-2yPE7",
+ "id": "Prompt-bxgAA",
"measured": {
"height": 260,
"width": 320
@@ -1966,11 +1818,9 @@
"data": {
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
- "id": "Prompt-OoSJu",
+ "id": "Prompt-ZbmDf",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
@@ -1980,9 +1830,7 @@
"display_name": "Prompt",
"documentation": "",
"edited": false,
- "field_order": [
- "template"
- ],
+ "field_order": ["template"],
"frozen": false,
"icon": "prompts",
"legacy": false,
@@ -1998,9 +1846,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -2049,9 +1895,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -2072,7 +1916,7 @@
},
"dragging": false,
"height": 260,
- "id": "Prompt-OoSJu",
+ "id": "Prompt-ZbmDf",
"measured": {
"height": 260,
"width": 320
@@ -2091,7 +1935,7 @@
},
{
"data": {
- "id": "note-0T0JR",
+ "id": "note-6tIRa",
"node": {
"description": "# 🔑 Tavily AI Search Needs API Key\n\nYou can get 1000 searches/month free [here](https://tavily.com/) ",
"display_name": "",
@@ -2104,7 +1948,7 @@
},
"dragging": false,
"height": 325,
- "id": "note-0T0JR",
+ "id": "note-6tIRa",
"measured": {
"height": 325,
"width": 326
@@ -2123,14 +1967,10 @@
},
{
"data": {
- "id": "TavilySearchComponent-oJz7N",
+ "id": "TavilySearchComponent-622t2",
"node": {
- "base_classes": [
- "Data",
- "Message"
- ],
+ "base_classes": ["Data", "Message"],
"beta": false,
- "category": "tools",
"conditional_paths": [],
"custom_fields": {},
"description": "**Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.",
@@ -2142,13 +1982,13 @@
"query",
"search_depth",
"topic",
+ "time_range",
"max_results",
"include_images",
"include_answer"
],
"frozen": false,
"icon": "TavilyIcon",
- "key": "TavilySearchComponent",
"legacy": false,
"metadata": {},
"minimized": false,
@@ -2163,14 +2003,12 @@
"name": "component_as_tool",
"required_inputs": null,
"selected": "Tool",
- "types": [
- "Tool"
- ],
+ "tool_mode": true,
+ "types": ["Tool"],
"value": "__UNDEFINED__"
}
],
"pinned": false,
- "score": 0.0075846556637275304,
"template": {
"_type": "Component",
"api_key": {
@@ -2179,10 +2017,8 @@
"display_name": "Tavily API Key",
"dynamic": false,
"info": "Your Tavily API Key.",
- "input_types": [
- "Message"
- ],
- "load_from_db": false,
+ "input_types": ["Message"],
+ "load_from_db": true,
"name": "api_key",
"password": true,
"placeholder": "",
@@ -2190,7 +2026,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "TAVILY_API_KEY"
},
"code": {
"advanced": true,
@@ -2208,7 +2044,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily AI Search\"\n description = \"\"\"**Tavily AI** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"fetch_content\"),\n Output(display_name=\"Text\", name=\"text\", method=\"fetch_content_text\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n }\n\n with httpx.Client() as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n data_results.append(\n Data(\n text=content,\n data={\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n },\n )\n )\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_text(self) -> Message:\n data = self.fetch_content()\n result_string = data_to_text(\"{text}\", data)\n self.status = result_string\n return Message(text=result_string)\n"
+ "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily AI Search\"\n description = \"\"\"**Tavily AI** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n DropdownInput(\n name=\"time_range\",\n display_name=\"Time Range\",\n info=\"The time range back from the current date to include in the search results.\",\n options=[\"day\", \"week\", \"month\", \"year\"],\n value=None,\n advanced=True,\n combobox=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"fetch_content\"),\n Output(display_name=\"Text\", name=\"text\", method=\"fetch_content_text\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n \"time_range\": self.time_range,\n }\n\n with httpx.Client() as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n data_results.append(\n Data(\n text=content,\n data={\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n },\n )\n )\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_text(self) -> Message:\n data = self.fetch_content()\n result_string = data_to_text(\"{text}\", data)\n self.status = result_string\n return Message(text=result_string)\n"
},
"include_answer": {
"_input_type": "BoolInput",
@@ -2270,9 +2106,7 @@
"display_name": "Search Query",
"dynamic": false,
"info": "The search query you want to execute with Tavily.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -2291,14 +2125,13 @@
"_input_type": "DropdownInput",
"advanced": true,
"combobox": false,
+ "dialog_inputs": {},
"display_name": "Search Depth",
"dynamic": false,
"info": "The depth of the search.",
"name": "search_depth",
- "options": [
- "basic",
- "advanced"
- ],
+ "options": ["basic", "advanced"],
+ "options_metadata": [],
"placeholder": "",
"required": false,
"show": true,
@@ -2308,6 +2141,25 @@
"type": "str",
"value": "advanced"
},
+ "time_range": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": true,
+ "dialog_inputs": {},
+ "display_name": "Time Range",
+ "dynamic": false,
+ "info": "The time range back from the current date to include in the search results.",
+ "name": "time_range",
+ "options": ["day", "week", "month", "year"],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str"
+ },
"tools_metadata": {
"_input_type": "TableInput",
"advanced": false,
@@ -2333,10 +2185,7 @@
"description": "Modify tool names and descriptions to help agents understand when to use each tool.",
"field_parsers": {
"commands": "commands",
- "name": [
- "snake_case",
- "no_blank"
- ]
+ "name": ["snake_case", "no_blank"]
},
"hide_options": true
},
@@ -2349,6 +2198,7 @@
"edit_mode": "inline",
"filterable": false,
"formatter": "text",
+ "hidden": false,
"name": "name",
"sortable": false,
"type": "text"
@@ -2360,6 +2210,7 @@
"edit_mode": "popover",
"filterable": false,
"formatter": "text",
+ "hidden": false,
"name": "description",
"sortable": false,
"type": "text"
@@ -2371,6 +2222,7 @@
"edit_mode": "inline",
"filterable": false,
"formatter": "text",
+ "hidden": true,
"name": "tags",
"sortable": false,
"type": "text"
@@ -2387,16 +2239,12 @@
{
"description": "fetch_content(api_key: Message) - **Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.",
"name": "TavilySearchComponent-fetch_content",
- "tags": [
- "TavilySearchComponent-fetch_content"
- ]
+ "tags": ["TavilySearchComponent-fetch_content"]
},
{
"description": "fetch_content_text(api_key: Message) - **Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.",
"name": "TavilySearchComponent-fetch_content_text",
- "tags": [
- "TavilySearchComponent-fetch_content_text"
- ]
+ "tags": ["TavilySearchComponent-fetch_content_text"]
}
]
},
@@ -2404,14 +2252,13 @@
"_input_type": "DropdownInput",
"advanced": true,
"combobox": false,
+ "dialog_inputs": {},
"display_name": "Search Topic",
"dynamic": false,
"info": "The category of the search.",
"name": "topic",
- "options": [
- "general",
- "news"
- ],
+ "options": ["general", "news"],
+ "options_metadata": [],
"placeholder": "",
"required": false,
"show": true,
@@ -2428,7 +2275,7 @@
"type": "TavilySearchComponent"
},
"dragging": false,
- "id": "TavilySearchComponent-oJz7N",
+ "id": "TavilySearchComponent-622t2",
"measured": {
"height": 435,
"width": 320
@@ -2442,12 +2289,9 @@
},
{
"data": {
- "id": "OpenAIModel-VcHpk",
+ "id": "OpenAIModel-iiRQd",
"node": {
- "base_classes": [
- "LanguageModel",
- "Message"
- ],
+ "base_classes": ["LanguageModel", "Message"],
"beta": false,
"category": "models",
"conditional_paths": [],
@@ -2486,9 +2330,7 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -2497,14 +2339,10 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
- "required_inputs": [
- "api_key"
- ],
+ "required_inputs": ["api_key"],
"selected": "LanguageModel",
"tool_mode": true,
- "types": [
- "LanguageModel"
- ],
+ "types": ["LanguageModel"],
"value": "__UNDEFINED__"
}
],
@@ -2518,10 +2356,8 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
- "load_from_db": true,
+ "input_types": ["Message"],
+ "load_from_db": false,
"name": "api_key",
"password": true,
"placeholder": "",
@@ -2529,7 +2365,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"code": {
"advanced": true,
@@ -2555,9 +2391,7 @@
"display_name": "Input",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -2739,9 +2573,7 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -2810,7 +2642,7 @@
"type": "OpenAIModel"
},
"dragging": false,
- "id": "OpenAIModel-VcHpk",
+ "id": "OpenAIModel-iiRQd",
"measured": {
"height": 653,
"width": 320
@@ -2824,12 +2656,9 @@
},
{
"data": {
- "id": "OpenAIModel-zDrcf",
+ "id": "OpenAIModel-rQIeM",
"node": {
- "base_classes": [
- "LanguageModel",
- "Message"
- ],
+ "base_classes": ["LanguageModel", "Message"],
"beta": false,
"category": "models",
"conditional_paths": [],
@@ -2868,9 +2697,7 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -2879,14 +2706,10 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
- "required_inputs": [
- "api_key"
- ],
+ "required_inputs": ["api_key"],
"selected": "LanguageModel",
"tool_mode": true,
- "types": [
- "LanguageModel"
- ],
+ "types": ["LanguageModel"],
"value": "__UNDEFINED__"
}
],
@@ -2900,10 +2723,8 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
- "load_from_db": true,
+ "input_types": ["Message"],
+ "load_from_db": false,
"name": "api_key",
"password": true,
"placeholder": "",
@@ -2911,7 +2732,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"code": {
"advanced": true,
@@ -2937,9 +2758,7 @@
"display_name": "Input",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -3121,9 +2940,7 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -3192,7 +3009,7 @@
"type": "OpenAIModel"
},
"dragging": false,
- "id": "OpenAIModel-zDrcf",
+ "id": "OpenAIModel-rQIeM",
"measured": {
"height": 653,
"width": 320
@@ -3206,9 +3023,9 @@
}
],
"viewport": {
- "x": -135.40378221384628,
- "y": 346.1173837865683,
- "zoom": 0.42682994266054
+ "x": -142.70651359434498,
+ "y": 380.220352308604,
+ "zoom": 0.4057953245174196
}
},
"description": "Agent that generates focused plans, conducts web searches, and synthesizes findings into comprehensive reports.",
@@ -3219,8 +3036,5 @@
"is_component": false,
"last_tested_version": "1.0.19.post2",
"name": "Research Agent",
- "tags": [
- "assistants",
- "agents"
- ]
-}
\ No newline at end of file
+ "tags": ["assistants", "agents"]
+}
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/SEO Keyword Generator.json b/src/backend/base/langflow/initial_setup/starter_projects/SEO Keyword Generator.json
index c370ebf5c4..a753473d0c 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/SEO Keyword Generator.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/SEO Keyword Generator.json
@@ -8,16 +8,12 @@
"dataType": "Prompt",
"id": "Prompt-a6SIY",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "system_message",
"id": "OpenAIModel-brPVM",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -35,16 +31,12 @@
"dataType": "Prompt",
"id": "Prompt-jkCpO",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "OpenAIModel-brPVM",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -62,16 +54,12 @@
"dataType": "OpenAIModel",
"id": "OpenAIModel-brPVM",
"name": "text_output",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "ChatOutput-oE2ic",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -90,9 +78,7 @@
"display_name": "Prompt",
"id": "Prompt-jkCpO",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
@@ -109,9 +95,7 @@
"display_name": "Prompt",
"documentation": "",
"edited": false,
- "field_order": [
- "template"
- ],
+ "field_order": ["template"],
"frozen": false,
"icon": "prompts",
"legacy": false,
@@ -127,9 +111,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -162,10 +144,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -185,10 +164,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -208,10 +184,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -231,10 +204,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -254,10 +224,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -277,10 +244,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -316,9 +280,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -397,9 +359,7 @@
"display_name": "Prompt",
"id": "Prompt-a6SIY",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
@@ -409,9 +369,7 @@
"display_name": "Prompt",
"documentation": "",
"edited": false,
- "field_order": [
- "template"
- ],
+ "field_order": ["template"],
"frozen": false,
"icon": "prompts",
"legacy": false,
@@ -427,9 +385,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -478,9 +434,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -524,9 +478,7 @@
"display_name": "Chat Output",
"id": "ChatOutput-oE2ic",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -560,9 +512,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -575,9 +525,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -597,9 +545,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -637,9 +583,7 @@
"display_name": "Data Template",
"dynamic": false,
"info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "data_template",
@@ -659,9 +603,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Message to be passed as output.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -682,10 +624,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -701,9 +640,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -723,9 +660,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -761,9 +696,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -835,10 +768,7 @@
"data": {
"id": "OpenAIModel-brPVM",
"node": {
- "base_classes": [
- "LanguageModel",
- "Message"
- ],
+ "base_classes": ["LanguageModel", "Message"],
"beta": false,
"category": "models",
"conditional_paths": [],
@@ -877,9 +807,7 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -888,14 +816,10 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
- "required_inputs": [
- "api_key"
- ],
+ "required_inputs": ["api_key"],
"selected": "LanguageModel",
"tool_mode": true,
- "types": [
- "LanguageModel"
- ],
+ "types": ["LanguageModel"],
"value": "__UNDEFINED__"
}
],
@@ -909,9 +833,7 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -920,7 +842,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"code": {
"advanced": true,
@@ -946,9 +868,7 @@
"display_name": "Input",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1130,9 +1050,7 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -1228,8 +1146,5 @@
"is_component": false,
"last_tested_version": "1.0.19.post2",
"name": "SEO Keyword Generator",
- "tags": [
- "chatbots",
- "assistants"
- ]
-}
\ No newline at end of file
+ "tags": ["chatbots", "assistants"]
+}
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/SaaS Pricing.json b/src/backend/base/langflow/initial_setup/starter_projects/SaaS Pricing.json
index f093d56dd9..217c1962e5 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/SaaS Pricing.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/SaaS Pricing.json
@@ -109,9 +109,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -338,9 +336,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -654,9 +650,7 @@
"name": "response",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -745,7 +739,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"code": {
"advanced": true,
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents .json b/src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents .json
index eed7e0e550..943b69d725 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents .json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents .json
@@ -7,26 +7,22 @@
"data": {
"sourceHandle": {
"dataType": "Prompt",
- "id": "Prompt-xirI8",
+ "id": "Prompt-0tvfj",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "system_prompt",
- "id": "Agent-9YXRo",
- "inputTypes": [
- "Message"
- ],
+ "id": "Agent-uHv68",
+ "inputTypes": ["Message"],
"type": "str"
}
},
- "id": "reactflow__edge-Prompt-xirI8{œdataTypeœ:œPromptœ,œidœ:œPrompt-xirI8œ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-9YXRo{œfieldNameœ:œsystem_promptœ,œidœ:œAgent-9YXRoœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
- "source": "Prompt-xirI8",
- "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-xirI8œ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Agent-9YXRo",
- "targetHandle": "{œfieldNameœ: œsystem_promptœ, œidœ: œAgent-9YXRoœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-Prompt-0tvfj{œdataTypeœ:œPromptœ,œidœ:œPrompt-0tvfjœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-uHv68{œfieldNameœ:œsystem_promptœ,œidœ:œAgent-uHv68œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "Prompt-0tvfj",
+ "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-0tvfjœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Agent-uHv68",
+ "targetHandle": "{œfieldNameœ: œsystem_promptœ, œidœ: œAgent-uHv68œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"animated": false,
@@ -34,26 +30,22 @@
"data": {
"sourceHandle": {
"dataType": "Prompt",
- "id": "Prompt-f4paU",
+ "id": "Prompt-YbDgD",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "system_prompt",
- "id": "Agent-RmOB2",
- "inputTypes": [
- "Message"
- ],
+ "id": "Agent-uO2c7",
+ "inputTypes": ["Message"],
"type": "str"
}
},
- "id": "reactflow__edge-Prompt-f4paU{œdataTypeœ:œPromptœ,œidœ:œPrompt-f4paUœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-RmOB2{œfieldNameœ:œsystem_promptœ,œidœ:œAgent-RmOB2œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
- "source": "Prompt-f4paU",
- "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-f4paUœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Agent-RmOB2",
- "targetHandle": "{œfieldNameœ: œsystem_promptœ, œidœ: œAgent-RmOB2œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-Prompt-YbDgD{œdataTypeœ:œPromptœ,œidœ:œPrompt-YbDgDœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-uO2c7{œfieldNameœ:œsystem_promptœ,œidœ:œAgent-uO2c7œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "Prompt-YbDgD",
+ "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-YbDgDœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Agent-uO2c7",
+ "targetHandle": "{œfieldNameœ: œsystem_promptœ, œidœ: œAgent-uO2c7œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"animated": false,
@@ -61,26 +53,22 @@
"data": {
"sourceHandle": {
"dataType": "Agent",
- "id": "Agent-9YXRo",
+ "id": "Agent-uHv68",
"name": "response",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
- "id": "ChatOutput-DqyyQ",
- "inputTypes": [
- "Message"
- ],
+ "id": "ChatOutput-aOzn2",
+ "inputTypes": ["Message"],
"type": "str"
}
},
- "id": "reactflow__edge-Agent-9YXRo{œdataTypeœ:œAgentœ,œidœ:œAgent-9YXRoœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-DqyyQ{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-DqyyQœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
- "source": "Agent-9YXRo",
- "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-9YXRoœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
- "target": "ChatOutput-DqyyQ",
- "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-DqyyQœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-Agent-uHv68{œdataTypeœ:œAgentœ,œidœ:œAgent-uHv68œ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-aOzn2{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-aOzn2œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "Agent-uHv68",
+ "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-uHv68œ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "ChatOutput-aOzn2",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-aOzn2œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"animated": false,
@@ -88,27 +76,22 @@
"data": {
"sourceHandle": {
"dataType": "Agent",
- "id": "Agent-RmOB2",
+ "id": "Agent-uO2c7",
"name": "response",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "finance_agent_output",
- "id": "Prompt-xirI8",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "id": "Prompt-0tvfj",
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
- "id": "reactflow__edge-Agent-RmOB2{œdataTypeœ:œAgentœ,œidœ:œAgent-RmOB2œ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Prompt-xirI8{œfieldNameœ:œfinance_agent_outputœ,œidœ:œPrompt-xirI8œ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
- "source": "Agent-RmOB2",
- "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-RmOB2œ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Prompt-xirI8",
- "targetHandle": "{œfieldNameœ: œfinance_agent_outputœ, œidœ: œPrompt-xirI8œ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-Agent-uO2c7{œdataTypeœ:œAgentœ,œidœ:œAgent-uO2c7œ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Prompt-0tvfj{œfieldNameœ:œfinance_agent_outputœ,œidœ:œPrompt-0tvfjœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
+ "source": "Agent-uO2c7",
+ "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-uO2c7œ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Prompt-0tvfj",
+ "targetHandle": "{œfieldNameœ: œfinance_agent_outputœ, œidœ: œPrompt-0tvfjœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
},
{
"animated": false,
@@ -116,26 +99,22 @@
"data": {
"sourceHandle": {
"dataType": "ChatInput",
- "id": "ChatInput-TQ1li",
+ "id": "ChatInput-yzskz",
"name": "message",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
- "id": "Agent-TmQ5O",
- "inputTypes": [
- "Message"
- ],
+ "id": "Agent-6Gznl",
+ "inputTypes": ["Message"],
"type": "str"
}
},
- "id": "reactflow__edge-ChatInput-TQ1li{œdataTypeœ:œChatInputœ,œidœ:œChatInput-TQ1liœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-TmQ5O{œfieldNameœ:œinput_valueœ,œidœ:œAgent-TmQ5Oœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
- "source": "ChatInput-TQ1li",
- "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-TQ1liœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Agent-TmQ5O",
- "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-TmQ5Oœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-ChatInput-yzskz{œdataTypeœ:œChatInputœ,œidœ:œChatInput-yzskzœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-6Gznl{œfieldNameœ:œinput_valueœ,œidœ:œAgent-6Gznlœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "ChatInput-yzskz",
+ "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-yzskzœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Agent-6Gznl",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-6Gznlœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"animated": false,
@@ -143,26 +122,22 @@
"data": {
"sourceHandle": {
"dataType": "Prompt",
- "id": "Prompt-3fyqW",
+ "id": "Prompt-Sxdul",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "system_prompt",
- "id": "Agent-TmQ5O",
- "inputTypes": [
- "Message"
- ],
+ "id": "Agent-6Gznl",
+ "inputTypes": ["Message"],
"type": "str"
}
},
- "id": "reactflow__edge-Prompt-3fyqW{œdataTypeœ:œPromptœ,œidœ:œPrompt-3fyqWœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-TmQ5O{œfieldNameœ:œsystem_promptœ,œidœ:œAgent-TmQ5Oœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
- "source": "Prompt-3fyqW",
- "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-3fyqWœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Agent-TmQ5O",
- "targetHandle": "{œfieldNameœ: œsystem_promptœ, œidœ: œAgent-TmQ5Oœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-Prompt-Sxdul{œdataTypeœ:œPromptœ,œidœ:œPrompt-Sxdulœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-6Gznl{œfieldNameœ:œsystem_promptœ,œidœ:œAgent-6Gznlœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "Prompt-Sxdul",
+ "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-Sxdulœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Agent-6Gznl",
+ "targetHandle": "{œfieldNameœ: œsystem_promptœ, œidœ: œAgent-6Gznlœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"animated": false,
@@ -170,26 +145,22 @@
"data": {
"sourceHandle": {
"dataType": "Agent",
- "id": "Agent-TmQ5O",
+ "id": "Agent-6Gznl",
"name": "response",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
- "id": "Agent-RmOB2",
- "inputTypes": [
- "Message"
- ],
+ "id": "Agent-uO2c7",
+ "inputTypes": ["Message"],
"type": "str"
}
},
- "id": "reactflow__edge-Agent-TmQ5O{œdataTypeœ:œAgentœ,œidœ:œAgent-TmQ5Oœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Agent-RmOB2{œfieldNameœ:œinput_valueœ,œidœ:œAgent-RmOB2œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
- "source": "Agent-TmQ5O",
- "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-TmQ5Oœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Agent-RmOB2",
- "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-RmOB2œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-Agent-6Gznl{œdataTypeœ:œAgentœ,œidœ:œAgent-6Gznlœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Agent-uO2c7{œfieldNameœ:œinput_valueœ,œidœ:œAgent-uO2c7œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "Agent-6Gznl",
+ "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-6Gznlœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Agent-uO2c7",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-uO2c7œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"animated": false,
@@ -197,105 +168,88 @@
"data": {
"sourceHandle": {
"dataType": "Agent",
- "id": "Agent-TmQ5O",
+ "id": "Agent-6Gznl",
"name": "response",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "research_agent_output",
- "id": "Prompt-xirI8",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "id": "Prompt-0tvfj",
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
- "id": "reactflow__edge-Agent-TmQ5O{œdataTypeœ:œAgentœ,œidœ:œAgent-TmQ5Oœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Prompt-xirI8{œfieldNameœ:œresearch_agent_outputœ,œidœ:œPrompt-xirI8œ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
- "source": "Agent-TmQ5O",
- "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-TmQ5Oœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Prompt-xirI8",
- "targetHandle": "{œfieldNameœ: œresearch_agent_outputœ, œidœ: œPrompt-xirI8œ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-Agent-6Gznl{œdataTypeœ:œAgentœ,œidœ:œAgent-6Gznlœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Prompt-0tvfj{œfieldNameœ:œresearch_agent_outputœ,œidœ:œPrompt-0tvfjœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
+ "source": "Agent-6Gznl",
+ "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-6Gznlœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Prompt-0tvfj",
+ "targetHandle": "{œfieldNameœ: œresearch_agent_outputœ, œidœ: œPrompt-0tvfjœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
},
{
"className": "",
"data": {
"sourceHandle": {
"dataType": "CalculatorComponent",
- "id": "CalculatorComponent-82dCo",
+ "id": "CalculatorComponent-WMC2W",
"name": "component_as_tool",
- "output_types": [
- "Tool"
- ]
+ "output_types": ["Tool"]
},
"targetHandle": {
"fieldName": "tools",
- "id": "Agent-9YXRo",
- "inputTypes": [
- "Tool"
- ],
+ "id": "Agent-uHv68",
+ "inputTypes": ["Tool"],
"type": "other"
}
},
- "id": "reactflow__edge-CalculatorComponent-82dCo{œdataTypeœ:œCalculatorComponentœ,œidœ:œCalculatorComponent-82dCoœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-9YXRo{œfieldNameœ:œtoolsœ,œidœ:œAgent-9YXRoœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}",
- "source": "CalculatorComponent-82dCo",
- "sourceHandle": "{œdataTypeœ: œCalculatorComponentœ, œidœ: œCalculatorComponent-82dCoœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}",
- "target": "Agent-9YXRo",
- "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-9YXRoœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}"
+ "id": "reactflow__edge-CalculatorComponent-WMC2W{œdataTypeœ:œCalculatorComponentœ,œidœ:œCalculatorComponent-WMC2Wœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-uHv68{œfieldNameœ:œtoolsœ,œidœ:œAgent-uHv68œ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}",
+ "source": "CalculatorComponent-WMC2W",
+ "sourceHandle": "{œdataTypeœ: œCalculatorComponentœ, œidœ: œCalculatorComponent-WMC2Wœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}",
+ "target": "Agent-uHv68",
+ "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-uHv68œ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}"
},
{
"className": "",
"data": {
"sourceHandle": {
"dataType": "YfinanceComponent",
- "id": "YfinanceComponent-P0VBm",
+ "id": "YfinanceComponent-BIM81",
"name": "component_as_tool",
- "output_types": [
- "Tool"
- ]
+ "output_types": ["Tool"]
},
"targetHandle": {
"fieldName": "tools",
- "id": "Agent-RmOB2",
- "inputTypes": [
- "Tool"
- ],
+ "id": "Agent-uO2c7",
+ "inputTypes": ["Tool"],
"type": "other"
}
},
- "id": "reactflow__edge-YfinanceComponent-P0VBm{œdataTypeœ:œYfinanceComponentœ,œidœ:œYfinanceComponent-P0VBmœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-RmOB2{œfieldNameœ:œtoolsœ,œidœ:œAgent-RmOB2œ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}",
- "source": "YfinanceComponent-P0VBm",
- "sourceHandle": "{œdataTypeœ: œYfinanceComponentœ, œidœ: œYfinanceComponent-P0VBmœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}",
- "target": "Agent-RmOB2",
- "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-RmOB2œ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}"
+ "id": "reactflow__edge-YfinanceComponent-BIM81{œdataTypeœ:œYfinanceComponentœ,œidœ:œYfinanceComponent-BIM81œ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-uO2c7{œfieldNameœ:œtoolsœ,œidœ:œAgent-uO2c7œ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}",
+ "source": "YfinanceComponent-BIM81",
+ "sourceHandle": "{œdataTypeœ: œYfinanceComponentœ, œidœ: œYfinanceComponent-BIM81œ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}",
+ "target": "Agent-uO2c7",
+ "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-uO2c7œ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}"
},
{
"className": "",
"data": {
"sourceHandle": {
"dataType": "TavilySearchComponent",
- "id": "TavilySearchComponent-ZgS55",
+ "id": "TavilySearchComponent-YUDsR",
"name": "component_as_tool",
- "output_types": [
- "Tool"
- ]
+ "output_types": ["Tool"]
},
"targetHandle": {
"fieldName": "tools",
- "id": "Agent-TmQ5O",
- "inputTypes": [
- "Tool"
- ],
+ "id": "Agent-6Gznl",
+ "inputTypes": ["Tool"],
"type": "other"
}
},
- "id": "reactflow__edge-TavilySearchComponent-ZgS55{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-ZgS55œ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-TmQ5O{œfieldNameœ:œtoolsœ,œidœ:œAgent-TmQ5Oœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}",
- "source": "TavilySearchComponent-ZgS55",
- "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-ZgS55œ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}",
- "target": "Agent-TmQ5O",
- "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-TmQ5Oœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}"
+ "id": "reactflow__edge-TavilySearchComponent-YUDsR{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-YUDsRœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-6Gznl{œfieldNameœ:œtoolsœ,œidœ:œAgent-6Gznlœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}",
+ "source": "TavilySearchComponent-YUDsR",
+ "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-YUDsRœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}",
+ "target": "Agent-6Gznl",
+ "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-6Gznlœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}"
}
],
"nodes": [
@@ -303,11 +257,9 @@
"data": {
"description": "Display a chat message in the Playground.",
"display_name": "Chat Output",
- "id": "ChatOutput-DqyyQ",
+ "id": "ChatOutput-aOzn2",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -341,9 +293,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -356,9 +306,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -378,9 +326,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -418,9 +364,7 @@
"display_name": "Data Template",
"dynamic": false,
"info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "data_template",
@@ -440,9 +384,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Message to be passed as output.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -463,10 +405,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -482,9 +421,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -504,9 +441,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -542,9 +477,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -565,10 +498,10 @@
},
"dragging": false,
"height": 234,
- "id": "ChatOutput-DqyyQ",
+ "id": "ChatOutput-aOzn2",
"measured": {
"height": 234,
- "width": 360
+ "width": 320
},
"position": {
"x": 1239.222567317785,
@@ -586,11 +519,9 @@
"data": {
"description": "Define the agent's instructions, then enter a task to complete using tools.",
"display_name": "Finance Agent",
- "id": "Agent-RmOB2",
+ "id": "Agent-uO2c7",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -641,9 +572,7 @@
"name": "response",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -672,9 +601,7 @@
"display_name": "Agent Description [Deprecated]",
"dynamic": false,
"info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -725,9 +652,7 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -778,9 +703,7 @@
"display_name": "Input",
"dynamic": false,
"info": "The input provided by the user for the agent to process.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -872,9 +795,7 @@
"display_name": "External Memory",
"dynamic": false,
"info": "Retrieve messages from an external memory. If empty, it will use the Langflow tables.",
- "input_types": [
- "Memory"
- ],
+ "input_types": ["Memory"],
"list": false,
"name": "memory",
"placeholder": "",
@@ -968,10 +889,7 @@
"dynamic": false,
"info": "Order of the messages.",
"name": "order",
- "options": [
- "Ascending",
- "Descending"
- ],
+ "options": ["Ascending", "Descending"],
"placeholder": "",
"required": false,
"show": true,
@@ -1005,11 +923,7 @@
"dynamic": false,
"info": "Filter by sender type.",
"name": "sender",
- "options": [
- "Machine",
- "User",
- "Machine and User"
- ],
+ "options": ["Machine", "User", "Machine and User"],
"placeholder": "",
"required": false,
"show": true,
@@ -1025,9 +939,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Filter by sender name.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -1047,9 +959,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -1069,9 +979,7 @@
"display_name": "Agent Instructions",
"dynamic": false,
"info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1108,9 +1016,7 @@
"display_name": "Template",
"dynamic": false,
"info": "The template to use for formatting the data. It can contain the keys {text}, {sender} or any other key in the message data.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1149,9 +1055,7 @@
"display_name": "Tools",
"dynamic": false,
"info": "These are the tools that the agent can use to help with tasks.",
- "input_types": [
- "Tool"
- ],
+ "input_types": ["Tool"],
"list": true,
"name": "tools",
"placeholder": "",
@@ -1185,10 +1089,10 @@
},
"dragging": false,
"height": 650,
- "id": "Agent-RmOB2",
+ "id": "Agent-uO2c7",
"measured": {
"height": 650,
- "width": 360
+ "width": 320
},
"position": {
"x": 45.70736046026991,
@@ -1206,11 +1110,9 @@
"data": {
"description": "Define the agent's instructions, then enter a task to complete using tools.",
"display_name": "Analysis & Editor Agent",
- "id": "Agent-9YXRo",
+ "id": "Agent-uHv68",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -1261,9 +1163,7 @@
"name": "response",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1292,9 +1192,7 @@
"display_name": "Agent Description [Deprecated]",
"dynamic": false,
"info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1345,9 +1243,7 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -1398,9 +1294,7 @@
"display_name": "Input",
"dynamic": false,
"info": "The input provided by the user for the agent to process.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -1492,9 +1386,7 @@
"display_name": "External Memory",
"dynamic": false,
"info": "Retrieve messages from an external memory. If empty, it will use the Langflow tables.",
- "input_types": [
- "Memory"
- ],
+ "input_types": ["Memory"],
"list": false,
"name": "memory",
"placeholder": "",
@@ -1588,10 +1480,7 @@
"dynamic": false,
"info": "Order of the messages.",
"name": "order",
- "options": [
- "Ascending",
- "Descending"
- ],
+ "options": ["Ascending", "Descending"],
"placeholder": "",
"required": false,
"show": true,
@@ -1625,11 +1514,7 @@
"dynamic": false,
"info": "Filter by sender type.",
"name": "sender",
- "options": [
- "Machine",
- "User",
- "Machine and User"
- ],
+ "options": ["Machine", "User", "Machine and User"],
"placeholder": "",
"required": false,
"show": true,
@@ -1645,9 +1530,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Filter by sender name.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -1667,9 +1550,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -1689,9 +1570,7 @@
"display_name": "Agent Instructions",
"dynamic": false,
"info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1728,9 +1607,7 @@
"display_name": "Template",
"dynamic": false,
"info": "The template to use for formatting the data. It can contain the keys {text}, {sender} or any other key in the message data.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1769,9 +1646,7 @@
"display_name": "Tools",
"dynamic": false,
"info": "These are the tools that the agent can use to help with tasks.",
- "input_types": [
- "Tool"
- ],
+ "input_types": ["Tool"],
"list": true,
"name": "tools",
"placeholder": "",
@@ -1805,10 +1680,10 @@
},
"dragging": false,
"height": 650,
- "id": "Agent-9YXRo",
+ "id": "Agent-uHv68",
"measured": {
"height": 650,
- "width": 360
+ "width": 320
},
"position": {
"x": 815.1900903820148,
@@ -1826,11 +1701,9 @@
"data": {
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
- "id": "Prompt-3fyqW",
+ "id": "Prompt-Sxdul",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
@@ -1841,9 +1714,7 @@
"documentation": "",
"edited": false,
"error": null,
- "field_order": [
- "template"
- ],
+ "field_order": ["template"],
"frozen": true,
"full_path": null,
"icon": "prompts",
@@ -1864,9 +1735,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1915,9 +1784,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -1938,10 +1805,10 @@
},
"dragging": false,
"height": 260,
- "id": "Prompt-3fyqW",
+ "id": "Prompt-Sxdul",
"measured": {
"height": 260,
- "width": 360
+ "width": 320
},
"position": {
"x": -1142.2312935529987,
@@ -1959,11 +1826,9 @@
"data": {
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
- "id": "Prompt-f4paU",
+ "id": "Prompt-YbDgD",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
@@ -1974,9 +1839,7 @@
"documentation": "",
"edited": false,
"error": null,
- "field_order": [
- "template"
- ],
+ "field_order": ["template"],
"frozen": false,
"full_path": null,
"icon": "prompts",
@@ -1997,9 +1860,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -2048,9 +1909,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -2071,10 +1930,10 @@
},
"dragging": false,
"height": 260,
- "id": "Prompt-f4paU",
+ "id": "Prompt-YbDgD",
"measured": {
"height": 260,
- "width": 360
+ "width": 320
},
"position": {
"x": -344.9674638932195,
@@ -2092,27 +1951,20 @@
"data": {
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
- "id": "Prompt-xirI8",
+ "id": "Prompt-0tvfj",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
- "template": [
- "research_agent_output",
- "finance_agent_output"
- ]
+ "template": ["research_agent_output", "finance_agent_output"]
},
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
"documentation": "",
"edited": false,
"error": null,
- "field_order": [
- "template"
- ],
+ "field_order": ["template"],
"frozen": false,
"full_path": null,
"icon": "prompts",
@@ -2133,9 +1985,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -2168,10 +2018,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -2191,10 +2038,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -2230,9 +2074,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -2253,10 +2095,10 @@
},
"dragging": false,
"height": 433,
- "id": "Prompt-xirI8",
+ "id": "Prompt-0tvfj",
"measured": {
"height": 433,
- "width": 360
+ "width": 320
},
"position": {
"x": 416.02309796632085,
@@ -2272,11 +2114,9 @@
},
{
"data": {
- "id": "ChatInput-TQ1li",
+ "id": "ChatInput-yzskz",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -2310,9 +2150,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -2325,9 +2163,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -2347,9 +2183,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -2452,10 +2286,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -2471,9 +2302,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -2493,9 +2322,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -2531,9 +2358,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -2554,10 +2379,10 @@
},
"dragging": false,
"height": 234,
- "id": "ChatInput-TQ1li",
+ "id": "ChatInput-yzskz",
"measured": {
"height": 234,
- "width": 360
+ "width": 320
},
"position": {
"x": -1510.6054210793818,
@@ -2573,7 +2398,7 @@
},
{
"data": {
- "id": "note-j0zav",
+ "id": "note-925JF",
"node": {
"description": "# Sequential Tasks Agents\n\n## Overview\nThis flow demonstrates how to chain multiple AI agents for comprehensive research and analysis. Each agent specializes in different aspects of the research process, building upon the previous agent's work.\n\n## How to Use the Flow\n\n1. **Input Your Query** 🎯\n - Be specific and clear\n - Include key aspects you want analyzed\n - Examples:\n ```\n Good: \"Should I invest in Tesla (TSLA)? Focus on AI development impact\"\n Bad: \"Tell me about Tesla\"\n ```\n\n2. **Research Agent Process** 🔍\n - Utilizes Tavily Search for comprehensive research\n\n\n3. **Specialized Analysis** 📊\n - Each agent adds unique value:\n ```\n Research Agent → Deep Research & Context\n ↓\n Finance Agent → Data Analysis & Metrics\n ↓\n Editor Agent → Final Synthesis & Report\n ```\n\n4. **Output Format** 📝\n - Structured report\n - Embedded images and charts\n - Data-backed insights\n - Clear recommendations\n\n## Pro Tips\n\n### Query Construction\n- Include specific points of interest\n- Mention required metrics or data points\n- Specify time frames if relevant\n\n### Flow Customization\n- Modify agent prompts for different use cases\n- Add or remove tools as needed\n\n## Common Applications\n- Investment Research\n- Market Analysis\n- Competitive Intelligence\n- Industry Reports\n- Technology Impact Studies\n\n⚡ **Best Practice**: Start with a test query to understand the flow's capabilities before running complex analyses.\n\n---\n*Note: This flow template uses financial analysis as an example but can be adapted for any research-intensive task requiring multiple perspectives and data sources.*",
"display_name": "",
@@ -2584,10 +2409,10 @@
},
"dragging": false,
"height": 800,
- "id": "note-j0zav",
+ "id": "note-925JF",
"measured": {
"height": 800,
- "width": 328
+ "width": 601
},
"position": {
"x": -2122.739127560837,
@@ -2608,7 +2433,7 @@
},
{
"data": {
- "id": "note-pUC9D",
+ "id": "note-nQe4N",
"node": {
"description": "## What Are Sequential Task Agents?\nA system where multiple AI agents work in sequence, each specializing in specific tasks and passing their output to the next agent in the chain. Think of it as an assembly line where each agent adds value to the final result.\n\n## How It Works\n1. **First Agent** → **Second Agent** → **Third Agent** → **Final Output**\n - Each agent receives input from the previous one\n - Processes and enhances the information\n - Passes refined output forward\n\n## Key Benefits\n- **Specialization**: Each agent focuses on specific tasks\n- **Progressive Refinement**: Information gets enhanced at each step\n- **Structured Output**: Final result combines multiple perspectives\n- **Quality Control**: Each agent validates and improves previous work\n\n## Building Your Own Sequence\n1. **Plan Your Chain**\n - Identify distinct tasks\n - Determine logical order\n - Define input/output requirements\n\n2. **Configure Agents**\n - Give each agent clear instructions\n - Ensure compatible outputs/inputs\n - Set appropriate tools for each agent\n\n3. **Connect the Flow**\n - Link agents in proper order\n - Test data flow between agents\n - Verify final output format\n\n## Example Applications\n- Research → Analysis → Report Writing\n- Data Collection → Processing → Visualization\n- Content Research → Writing → Editing\n- Market Analysis → Financial Review → Investment Advice\n\n⭐ **Pro Tip**: The strength of sequential agents comes from how well they complement each other's capabilities.\n\nThis template uses financial analysis as an example, but you can adapt it for any multi-step process requiring different expertise at each stage.",
"display_name": "",
@@ -2621,10 +2446,10 @@
},
"dragging": false,
"height": 800,
- "id": "note-pUC9D",
+ "id": "note-nQe4N",
"measured": {
"height": 800,
- "width": 328
+ "width": 601
},
"position": {
"x": -1456.0688717707517,
@@ -2647,11 +2472,9 @@
"data": {
"description": "Define the agent's instructions, then enter a task to complete using tools.",
"display_name": "Researcher Agent",
- "id": "Agent-TmQ5O",
+ "id": "Agent-6Gznl",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -2702,9 +2525,7 @@
"name": "response",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -2733,9 +2554,7 @@
"display_name": "Agent Description [Deprecated]",
"dynamic": false,
"info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -2786,9 +2605,7 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -2839,9 +2656,7 @@
"display_name": "Input",
"dynamic": false,
"info": "The input provided by the user for the agent to process.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -2933,9 +2748,7 @@
"display_name": "External Memory",
"dynamic": false,
"info": "Retrieve messages from an external memory. If empty, it will use the Langflow tables.",
- "input_types": [
- "Memory"
- ],
+ "input_types": ["Memory"],
"list": false,
"name": "memory",
"placeholder": "",
@@ -3029,10 +2842,7 @@
"dynamic": false,
"info": "Order of the messages.",
"name": "order",
- "options": [
- "Ascending",
- "Descending"
- ],
+ "options": ["Ascending", "Descending"],
"placeholder": "",
"required": false,
"show": true,
@@ -3066,11 +2876,7 @@
"dynamic": false,
"info": "Filter by sender type.",
"name": "sender",
- "options": [
- "Machine",
- "User",
- "Machine and User"
- ],
+ "options": ["Machine", "User", "Machine and User"],
"placeholder": "",
"required": false,
"show": true,
@@ -3086,9 +2892,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Filter by sender name.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -3108,9 +2912,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -3130,9 +2932,7 @@
"display_name": "Agent Instructions",
"dynamic": false,
"info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -3169,9 +2969,7 @@
"display_name": "Template",
"dynamic": false,
"info": "The template to use for formatting the data. It can contain the keys {text}, {sender} or any other key in the message data.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -3210,9 +3008,7 @@
"display_name": "Tools",
"dynamic": false,
"info": "These are the tools that the agent can use to help with tasks.",
- "input_types": [
- "Tool"
- ],
+ "input_types": ["Tool"],
"list": true,
"name": "tools",
"placeholder": "",
@@ -3246,10 +3042,10 @@
},
"dragging": false,
"height": 650,
- "id": "Agent-TmQ5O",
+ "id": "Agent-6Gznl",
"measured": {
"height": 650,
- "width": 360
+ "width": 320
},
"position": {
"x": -715.1798010873374,
@@ -3265,7 +3061,7 @@
},
{
"data": {
- "id": "note-NgTrE",
+ "id": "note-Lh7q4",
"node": {
"description": "## Get your API key at [https://tavily.com](https://tavily.com)\n",
"display_name": "",
@@ -3278,10 +3074,10 @@
},
"dragging": false,
"height": 324,
- "id": "note-NgTrE",
+ "id": "note-Lh7q4",
"measured": {
"height": 324,
- "width": 328
+ "width": 348
},
"position": {
"x": -1144.3898055225054,
@@ -3302,7 +3098,7 @@
},
{
"data": {
- "id": "note-7I7gz",
+ "id": "note-7B1PU",
"node": {
"description": "## Configure the agent by obtaining your OpenAI API key from [platform.openai.com](https://platform.openai.com). Under \"Model Provider\", choose:\n- OpenAI: Default, requires only API key\n- Anthropic/Azure/Groq/NVIDIA/SambaNova: Each requires their own API keys\n- Custom: Use your own model endpoint + authentication\n\nSelect model and input API key before running the flow.",
"display_name": "",
@@ -3315,10 +3111,10 @@
},
"dragging": false,
"height": 324,
- "id": "note-7I7gz",
+ "id": "note-7B1PU",
"measured": {
"height": 324,
- "width": 328
+ "width": 371
},
"position": {
"x": -739.4383746675942,
@@ -3339,12 +3135,9 @@
},
{
"data": {
- "id": "YfinanceComponent-P0VBm",
+ "id": "YfinanceComponent-BIM81",
"node": {
- "base_classes": [
- "Data",
- "Message"
- ],
+ "base_classes": ["Data", "Message"],
"beta": false,
"category": "tools",
"conditional_paths": [],
@@ -3353,11 +3146,7 @@
"display_name": "Yahoo Finance",
"documentation": "",
"edited": false,
- "field_order": [
- "symbol",
- "method",
- "num_news"
- ],
+ "field_order": ["symbol", "method", "num_news"],
"frozen": false,
"icon": "trending-up",
"key": "YfinanceComponent",
@@ -3374,9 +3163,7 @@
"name": "component_as_tool",
"required_inputs": null,
"selected": "Tool",
- "types": [
- "Tool"
- ],
+ "types": ["Tool"],
"value": "__UNDEFINED__"
}
],
@@ -3470,9 +3257,7 @@
"display_name": "Stock Symbol",
"dynamic": false,
"info": "The stock symbol to retrieve data for (e.g., AAPL, GOOG).",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -3512,10 +3297,7 @@
"description": "Modify tool names and descriptions to help agents understand when to use each tool.",
"field_parsers": {
"commands": "commands",
- "name": [
- "snake_case",
- "no_blank"
- ]
+ "name": ["snake_case", "no_blank"]
},
"hide_options": true
},
@@ -3566,16 +3348,12 @@
{
"description": "fetch_content() - Uses [yfinance](https://pypi.org/project/yfinance/) (unofficial package) to access financial data and market information from Yahoo Finance.",
"name": "YfinanceComponent-fetch_content",
- "tags": [
- "YfinanceComponent-fetch_content"
- ]
+ "tags": ["YfinanceComponent-fetch_content"]
},
{
"description": "fetch_content_text() - Uses [yfinance](https://pypi.org/project/yfinance/) (unofficial package) to access financial data and market information from Yahoo Finance.",
"name": "YfinanceComponent-fetch_content_text",
- "tags": [
- "YfinanceComponent-fetch_content_text"
- ]
+ "tags": ["YfinanceComponent-fetch_content_text"]
}
]
}
@@ -3586,10 +3364,10 @@
"type": "YfinanceComponent"
},
"dragging": true,
- "id": "YfinanceComponent-P0VBm",
+ "id": "YfinanceComponent-BIM81",
"measured": {
- "height": 581,
- "width": 360
+ "height": 517,
+ "width": 320
},
"position": {
"x": -347.05382068428014,
@@ -3600,11 +3378,9 @@
},
{
"data": {
- "id": "CalculatorComponent-82dCo",
+ "id": "CalculatorComponent-WMC2W",
"node": {
- "base_classes": [
- "Data"
- ],
+ "base_classes": ["Data"],
"beta": false,
"category": "tools",
"conditional_paths": [],
@@ -3613,9 +3389,7 @@
"display_name": "Calculator",
"documentation": "",
"edited": false,
- "field_order": [
- "expression"
- ],
+ "field_order": ["expression"],
"frozen": false,
"icon": "calculator",
"key": "CalculatorComponent",
@@ -3632,9 +3406,7 @@
"name": "component_as_tool",
"required_inputs": null,
"selected": "Tool",
- "types": [
- "Tool"
- ],
+ "types": ["Tool"],
"value": "__UNDEFINED__"
}
],
@@ -3666,9 +3438,7 @@
"display_name": "Expression",
"dynamic": false,
"info": "The arithmetic expression to evaluate (e.g., '4*4*(33/22)+12-20').",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -3708,10 +3478,7 @@
"description": "Modify tool names and descriptions to help agents understand when to use each tool.",
"field_parsers": {
"commands": "commands",
- "name": [
- "snake_case",
- "no_blank"
- ]
+ "name": ["snake_case", "no_blank"]
},
"hide_options": true
},
@@ -3762,9 +3529,7 @@
{
"description": "evaluate_expression() - Perform basic arithmetic operations on a given expression.",
"name": "CalculatorComponent-evaluate_expression",
- "tags": [
- "CalculatorComponent-evaluate_expression"
- ]
+ "tags": ["CalculatorComponent-evaluate_expression"]
}
]
}
@@ -3775,10 +3540,10 @@
"type": "CalculatorComponent"
},
"dragging": false,
- "id": "CalculatorComponent-82dCo",
+ "id": "CalculatorComponent-WMC2W",
"measured": {
- "height": 374,
- "width": 360
+ "height": 333,
+ "width": 320
},
"position": {
"x": 418.5430081507146,
@@ -3789,14 +3554,10 @@
},
{
"data": {
- "id": "TavilySearchComponent-ZgS55",
+ "id": "TavilySearchComponent-YUDsR",
"node": {
- "base_classes": [
- "Data",
- "Message"
- ],
+ "base_classes": ["Data", "Message"],
"beta": false,
- "category": "tools",
"conditional_paths": [],
"custom_fields": {},
"description": "**Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.",
@@ -3808,13 +3569,13 @@
"query",
"search_depth",
"topic",
+ "time_range",
"max_results",
"include_images",
"include_answer"
],
"frozen": false,
"icon": "TavilyIcon",
- "key": "TavilySearchComponent",
"legacy": false,
"metadata": {},
"minimized": false,
@@ -3829,14 +3590,12 @@
"name": "component_as_tool",
"required_inputs": null,
"selected": "Tool",
- "types": [
- "Tool"
- ],
+ "tool_mode": true,
+ "types": ["Tool"],
"value": "__UNDEFINED__"
}
],
"pinned": false,
- "score": 0.0075846556637275304,
"template": {
"_type": "Component",
"api_key": {
@@ -3845,9 +3604,7 @@
"display_name": "Tavily API Key",
"dynamic": false,
"info": "Your Tavily API Key.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -3856,7 +3613,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "TAVILY_API_KEY"
},
"code": {
"advanced": true,
@@ -3874,7 +3631,7 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily AI Search\"\n description = \"\"\"**Tavily AI** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"fetch_content\"),\n Output(display_name=\"Text\", name=\"text\", method=\"fetch_content_text\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n }\n\n with httpx.Client() as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n data_results.append(\n Data(\n text=content,\n data={\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n },\n )\n )\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_text(self) -> Message:\n data = self.fetch_content()\n result_string = data_to_text(\"{text}\", data)\n self.status = result_string\n return Message(text=result_string)\n"
+ "value": "import httpx\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SecretStrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily AI Search\"\n description = \"\"\"**Tavily AI** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n DropdownInput(\n name=\"time_range\",\n display_name=\"Time Range\",\n info=\"The time range back from the current date to include in the search results.\",\n options=[\"day\", \"week\", \"month\", \"year\"],\n value=None,\n advanced=True,\n combobox=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"fetch_content\"),\n Output(display_name=\"Text\", name=\"text\", method=\"fetch_content_text\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n \"time_range\": self.time_range,\n }\n\n with httpx.Client() as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n data_results.append(\n Data(\n text=content,\n data={\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n },\n )\n )\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_text(self) -> Message:\n data = self.fetch_content()\n result_string = data_to_text(\"{text}\", data)\n self.status = result_string\n return Message(text=result_string)\n"
},
"include_answer": {
"_input_type": "BoolInput",
@@ -3936,9 +3693,7 @@
"display_name": "Search Query",
"dynamic": false,
"info": "The search query you want to execute with Tavily.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -3957,14 +3712,13 @@
"_input_type": "DropdownInput",
"advanced": true,
"combobox": false,
+ "dialog_inputs": {},
"display_name": "Search Depth",
"dynamic": false,
"info": "The depth of the search.",
"name": "search_depth",
- "options": [
- "basic",
- "advanced"
- ],
+ "options": ["basic", "advanced"],
+ "options_metadata": [],
"placeholder": "",
"required": false,
"show": true,
@@ -3974,6 +3728,25 @@
"type": "str",
"value": "advanced"
},
+ "time_range": {
+ "_input_type": "DropdownInput",
+ "advanced": true,
+ "combobox": true,
+ "dialog_inputs": {},
+ "display_name": "Time Range",
+ "dynamic": false,
+ "info": "The time range back from the current date to include in the search results.",
+ "name": "time_range",
+ "options": ["day", "week", "month", "year"],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str"
+ },
"tools_metadata": {
"_input_type": "TableInput",
"advanced": false,
@@ -3999,10 +3772,7 @@
"description": "Modify tool names and descriptions to help agents understand when to use each tool.",
"field_parsers": {
"commands": "commands",
- "name": [
- "snake_case",
- "no_blank"
- ]
+ "name": ["snake_case", "no_blank"]
},
"hide_options": true
},
@@ -4015,6 +3785,7 @@
"edit_mode": "inline",
"filterable": false,
"formatter": "text",
+ "hidden": false,
"name": "name",
"sortable": false,
"type": "text"
@@ -4026,6 +3797,7 @@
"edit_mode": "popover",
"filterable": false,
"formatter": "text",
+ "hidden": false,
"name": "description",
"sortable": false,
"type": "text"
@@ -4037,6 +3809,7 @@
"edit_mode": "inline",
"filterable": false,
"formatter": "text",
+ "hidden": true,
"name": "tags",
"sortable": false,
"type": "text"
@@ -4053,16 +3826,12 @@
{
"description": "fetch_content(api_key: Message) - **Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.",
"name": "TavilySearchComponent-fetch_content",
- "tags": [
- "TavilySearchComponent-fetch_content"
- ]
+ "tags": ["TavilySearchComponent-fetch_content"]
},
{
"description": "fetch_content_text(api_key: Message) - **Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.",
"name": "TavilySearchComponent-fetch_content_text",
- "tags": [
- "TavilySearchComponent-fetch_content_text"
- ]
+ "tags": ["TavilySearchComponent-fetch_content_text"]
}
]
},
@@ -4070,14 +3839,13 @@
"_input_type": "DropdownInput",
"advanced": true,
"combobox": false,
+ "dialog_inputs": {},
"display_name": "Search Topic",
"dynamic": false,
"info": "The category of the search.",
"name": "topic",
- "options": [
- "general",
- "news"
- ],
+ "options": ["general", "news"],
+ "options_metadata": [],
"placeholder": "",
"required": false,
"show": true,
@@ -4094,10 +3862,10 @@
"type": "TavilySearchComponent"
},
"dragging": false,
- "id": "TavilySearchComponent-ZgS55",
+ "id": "TavilySearchComponent-YUDsR",
"measured": {
- "height": 489,
- "width": 360
+ "height": 435,
+ "width": 320
},
"position": {
"x": -1138.848513020278,
@@ -4108,9 +3876,9 @@
}
],
"viewport": {
- "x": 905.1150074113123,
- "y": 872.5950106358109,
- "zoom": 0.3920220111611041
+ "x": 775.7505727867583,
+ "y": 1003.6897614169809,
+ "zoom": 0.3362831883623481
}
},
"description": "This Agent is designed to systematically execute a series of tasks following a meticulously predefined sequence. By adhering to this structured order, the Agent ensures that each task is completed efficiently and effectively, optimizing overall performance and maintaining a high level of accuracy.",
@@ -4121,9 +3889,5 @@
"is_component": false,
"last_tested_version": "1.0.19.post2",
"name": "Sequential Tasks Agents",
- "tags": [
- "assistants",
- "agents",
- "web-scraping"
- ]
-}
\ No newline at end of file
+ "tags": ["assistants", "agents", "web-scraping"]
+}
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json
index 717eecbf51..f5a2feaae9 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json
@@ -152,9 +152,7 @@
"name": "response",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -243,7 +241,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"code": {
"advanced": true,
@@ -720,9 +718,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1002,9 +998,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json b/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json
index c33c0d32ea..eec0557197 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json
@@ -199,9 +199,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -479,9 +477,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -760,9 +756,7 @@
"name": "response",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -851,7 +845,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"code": {
"advanced": true,
@@ -1353,9 +1347,7 @@
"name": "response",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1444,7 +1436,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"code": {
"advanced": true,
@@ -1946,9 +1938,7 @@
"name": "response",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -2037,7 +2027,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"code": {
"advanced": true,
@@ -3101,7 +3091,7 @@
"dynamic": false,
"info": "",
"input_types": ["Message"],
- "load_from_db": false,
+ "load_from_db": true,
"name": "api_key",
"password": true,
"placeholder": "",
@@ -3109,7 +3099,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "SEARCHAPI_API_KEY"
},
"code": {
"advanced": true,
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Twitter Thread Generator.json b/src/backend/base/langflow/initial_setup/starter_projects/Twitter Thread Generator.json
index df79c9928f..c2d3e5468e 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Twitter Thread Generator.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Twitter Thread Generator.json
@@ -9,17 +9,12 @@
"dataType": "TextInput",
"id": "TextInput-eClq5",
"name": "text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "CONTENT_GUIDELINES",
"id": "Prompt-AWZtN",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
@@ -38,17 +33,12 @@
"dataType": "TextInput",
"id": "TextInput-IpoG7",
"name": "text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "OUTPUT_FORMAT",
"id": "Prompt-AWZtN",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
@@ -67,17 +57,12 @@
"dataType": "TextInput",
"id": "TextInput-npraC",
"name": "text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "OUTPUT_LANGUAGE",
"id": "Prompt-AWZtN",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
@@ -96,17 +81,12 @@
"dataType": "TextInput",
"id": "TextInput-EZaR7",
"name": "text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "PROFILE_DETAILS",
"id": "Prompt-AWZtN",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
@@ -125,17 +105,12 @@
"dataType": "TextInput",
"id": "TextInput-fKGcs",
"name": "text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "PROFILE_TYPE",
"id": "Prompt-AWZtN",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
@@ -154,17 +129,12 @@
"dataType": "TextInput",
"id": "TextInput-92vEK",
"name": "text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "TONE_AND_STYLE",
"id": "Prompt-AWZtN",
- "inputTypes": [
- "Message",
- "Text"
- ],
+ "inputTypes": ["Message", "Text"],
"type": "str"
}
},
@@ -182,16 +152,12 @@
"dataType": "ChatInput",
"id": "ChatInput-ECcN8",
"name": "message",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "OpenAIModel-p0R9m",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -209,16 +175,12 @@
"dataType": "Prompt",
"id": "Prompt-AWZtN",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "system_message",
"id": "OpenAIModel-p0R9m",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -236,16 +198,12 @@
"dataType": "OpenAIModel",
"id": "OpenAIModel-p0R9m",
"name": "text_output",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
"id": "ChatOutput-0jDYx",
- "inputTypes": [
- "Message"
- ],
+ "inputTypes": ["Message"],
"type": "str"
}
},
@@ -262,9 +220,7 @@
"data": {
"id": "ChatInput-ECcN8",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -298,9 +254,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -313,9 +267,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -334,9 +286,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -437,10 +387,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -455,9 +402,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -476,9 +421,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -513,9 +456,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -555,9 +496,7 @@
"data": {
"id": "TextInput-eClq5",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -565,9 +504,7 @@
"display_name": "Content Guidelines",
"documentation": "",
"edited": false,
- "field_order": [
- "input_value"
- ],
+ "field_order": ["input_value"],
"frozen": false,
"icon": "type",
"legacy": false,
@@ -583,9 +520,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -616,9 +551,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Text to be passed as input.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -661,9 +594,7 @@
"display_name": "Chat Output",
"id": "ChatOutput-0jDYx",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -697,9 +628,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -712,9 +641,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -734,9 +661,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -774,9 +699,7 @@
"display_name": "Data Template",
"dynamic": false,
"info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "data_template",
@@ -796,9 +719,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Message to be passed as output.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -819,10 +740,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -838,9 +756,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -860,9 +776,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -898,9 +812,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -942,9 +854,7 @@
"data": {
"id": "TextInput-IpoG7",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -952,9 +862,7 @@
"display_name": "Output Format",
"documentation": "",
"edited": false,
- "field_order": [
- "input_value"
- ],
+ "field_order": ["input_value"],
"frozen": false,
"icon": "type",
"legacy": false,
@@ -970,9 +878,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1003,9 +909,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Text to be passed as input.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1046,9 +950,7 @@
"data": {
"id": "TextInput-npraC",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -1056,9 +958,7 @@
"display_name": "Output Language",
"documentation": "",
"edited": false,
- "field_order": [
- "input_value"
- ],
+ "field_order": ["input_value"],
"frozen": false,
"icon": "type",
"legacy": false,
@@ -1074,9 +974,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1107,9 +1005,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Text to be passed as input.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1150,9 +1046,7 @@
"data": {
"id": "TextInput-EZaR7",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -1160,9 +1054,7 @@
"display_name": "Profile Details",
"documentation": "",
"edited": false,
- "field_order": [
- "input_value"
- ],
+ "field_order": ["input_value"],
"frozen": false,
"icon": "type",
"legacy": false,
@@ -1178,9 +1070,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1211,9 +1101,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Text to be passed as input.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1254,9 +1142,7 @@
"data": {
"id": "TextInput-92vEK",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -1264,9 +1150,7 @@
"display_name": "Tone And Style",
"documentation": "",
"edited": false,
- "field_order": [
- "input_value"
- ],
+ "field_order": ["input_value"],
"frozen": false,
"icon": "type",
"legacy": false,
@@ -1282,9 +1166,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1315,9 +1197,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Text to be passed as input.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1358,9 +1238,7 @@
"data": {
"id": "TextInput-fKGcs",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -1368,9 +1246,7 @@
"display_name": "Profile Type",
"documentation": "",
"edited": false,
- "field_order": [
- "input_value"
- ],
+ "field_order": ["input_value"],
"frozen": false,
"icon": "type",
"legacy": false,
@@ -1386,9 +1262,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1419,9 +1293,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Text to be passed as input.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1501,9 +1373,7 @@
"display_name": "Prompt",
"id": "Prompt-AWZtN",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
@@ -1520,9 +1390,7 @@
"display_name": "Prompt",
"documentation": "",
"edited": false,
- "field_order": [
- "template"
- ],
+ "field_order": ["template"],
"frozen": false,
"icon": "prompts",
"legacy": false,
@@ -1538,9 +1406,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1554,10 +1420,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1577,10 +1440,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1600,10 +1460,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1623,10 +1480,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1646,10 +1500,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1669,10 +1520,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -1727,9 +1575,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -1771,10 +1617,7 @@
"data": {
"id": "OpenAIModel-p0R9m",
"node": {
- "base_classes": [
- "LanguageModel",
- "Message"
- ],
+ "base_classes": ["LanguageModel", "Message"],
"beta": false,
"category": "models",
"conditional_paths": [],
@@ -1813,9 +1656,7 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -1824,14 +1665,10 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
- "required_inputs": [
- "api_key"
- ],
+ "required_inputs": ["api_key"],
"selected": "LanguageModel",
"tool_mode": true,
- "types": [
- "LanguageModel"
- ],
+ "types": ["LanguageModel"],
"value": "__UNDEFINED__"
}
],
@@ -1845,9 +1682,7 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -1856,7 +1691,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"code": {
"advanced": true,
@@ -1882,9 +1717,7 @@
"display_name": "Input",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -2066,9 +1899,7 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -2164,8 +1995,5 @@
"is_component": false,
"last_tested_version": "1.0.19.post2",
"name": "Twitter Thread Generator",
- "tags": [
- "chatbots",
- "content-generation"
- ]
-}
\ No newline at end of file
+ "tags": ["chatbots", "content-generation"]
+}
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Vector Store RAG.json b/src/backend/base/langflow/initial_setup/starter_projects/Vector Store RAG.json
index 2e999c0968..216c9cfb7c 100644
--- a/src/backend/base/langflow/initial_setup/starter_projects/Vector Store RAG.json
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Vector Store RAG.json
@@ -7,15 +7,13 @@
"data": {
"sourceHandle": {
"dataType": "ParseData",
- "id": "ParseData-9zsFp",
+ "id": "ParseData-cwmU0",
"name": "text",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "context",
- "id": "Prompt-mqa6n",
+ "id": "Prompt-wBjYe",
"inputTypes": [
"Message",
"Text"
@@ -23,11 +21,11 @@
"type": "str"
}
},
- "id": "reactflow__edge-ParseData-9zsFp{œdataTypeœ:œParseDataœ,œidœ:œParseData-9zsFpœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-mqa6n{œfieldNameœ:œcontextœ,œidœ:œPrompt-mqa6nœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
- "source": "ParseData-9zsFp",
- "sourceHandle": "{œdataTypeœ: œParseDataœ, œidœ: œParseData-9zsFpœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Prompt-mqa6n",
- "targetHandle": "{œfieldNameœ: œcontextœ, œidœ: œPrompt-mqa6nœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-ParseData-cwmU0{œdataTypeœ:œParseDataœ,œidœ:œParseData-cwmU0œ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-wBjYe{œfieldNameœ:œcontextœ,œidœ:œPrompt-wBjYeœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
+ "source": "ParseData-cwmU0",
+ "sourceHandle": "{œdataTypeœ: œParseDataœ, œidœ: œParseData-cwmU0œ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Prompt-wBjYe",
+ "targetHandle": "{œfieldNameœ: œcontextœ, œidœ: œPrompt-wBjYeœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
},
{
"animated": false,
@@ -35,15 +33,13 @@
"data": {
"sourceHandle": {
"dataType": "ChatInput",
- "id": "ChatInput-Jy5aI",
+ "id": "ChatInput-IRziS",
"name": "message",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "question",
- "id": "Prompt-mqa6n",
+ "id": "Prompt-wBjYe",
"inputTypes": [
"Message",
"Text"
@@ -51,11 +47,11 @@
"type": "str"
}
},
- "id": "reactflow__edge-ChatInput-Jy5aI{œdataTypeœ:œChatInputœ,œidœ:œChatInput-Jy5aIœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-mqa6n{œfieldNameœ:œquestionœ,œidœ:œPrompt-mqa6nœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
- "source": "ChatInput-Jy5aI",
- "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-Jy5aIœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
- "target": "Prompt-mqa6n",
- "targetHandle": "{œfieldNameœ: œquestionœ, œidœ: œPrompt-mqa6nœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-ChatInput-IRziS{œdataTypeœ:œChatInputœ,œidœ:œChatInput-IRziSœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-wBjYe{œfieldNameœ:œquestionœ,œidœ:œPrompt-wBjYeœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
+ "source": "ChatInput-IRziS",
+ "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-IRziSœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Prompt-wBjYe",
+ "targetHandle": "{œfieldNameœ: œquestionœ, œidœ: œPrompt-wBjYeœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
},
{
"animated": false,
@@ -63,208 +59,187 @@
"data": {
"sourceHandle": {
"dataType": "File",
- "id": "File-i8StI",
+ "id": "File-4yyks",
"name": "data",
- "output_types": [
- "Data"
- ]
+ "output_types": ["Data"]
},
"targetHandle": {
"fieldName": "data_inputs",
- "id": "SplitText-DakpR",
+ "id": "SplitText-HWKil",
"inputTypes": [
"Data"
],
"type": "other"
}
},
- "id": "reactflow__edge-File-i8StI{œdataTypeœ:œFileœ,œidœ:œFile-i8StIœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}-SplitText-DakpR{œfieldNameœ:œdata_inputsœ,œidœ:œSplitText-DakpRœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}",
- "source": "File-i8StI",
- "sourceHandle": "{œdataTypeœ: œFileœ, œidœ: œFile-i8StIœ, œnameœ: œdataœ, œoutput_typesœ: [œDataœ]}",
- "target": "SplitText-DakpR",
- "targetHandle": "{œfieldNameœ: œdata_inputsœ, œidœ: œSplitText-DakpRœ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}"
+ "id": "reactflow__edge-File-4yyks{œdataTypeœ:œFileœ,œidœ:œFile-4yyksœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}-SplitText-HWKil{œfieldNameœ:œdata_inputsœ,œidœ:œSplitText-HWKilœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}",
+ "source": "File-4yyks",
+ "sourceHandle": "{œdataTypeœ: œFileœ, œidœ: œFile-4yyksœ, œnameœ: œdataœ, œoutput_typesœ: [œDataœ]}",
+ "target": "SplitText-HWKil",
+ "targetHandle": "{œfieldNameœ: œdata_inputsœ, œidœ: œSplitText-HWKilœ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}"
},
{
"className": "",
"data": {
"sourceHandle": {
"dataType": "Prompt",
- "id": "Prompt-mqa6n",
+ "id": "Prompt-wBjYe",
"name": "prompt",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
- "id": "OpenAIModel-VVLPR",
+ "id": "OpenAIModel-XJ1BC",
"inputTypes": [
"Message"
],
"type": "str"
}
},
- "id": "reactflow__edge-Prompt-mqa6n{œdataTypeœ:œPromptœ,œidœ:œPrompt-mqa6nœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-VVLPR{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-VVLPRœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
- "source": "Prompt-mqa6n",
- "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-mqa6nœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
- "target": "OpenAIModel-VVLPR",
- "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-VVLPRœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-Prompt-wBjYe{œdataTypeœ:œPromptœ,œidœ:œPrompt-wBjYeœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-XJ1BC{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-XJ1BCœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "Prompt-wBjYe",
+ "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-wBjYeœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "OpenAIModel-XJ1BC",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-XJ1BCœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"className": "",
"data": {
"sourceHandle": {
"dataType": "OpenAIModel",
- "id": "OpenAIModel-VVLPR",
+ "id": "OpenAIModel-XJ1BC",
"name": "text_output",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "input_value",
- "id": "ChatOutput-EujCa",
+ "id": "ChatOutput-D2eyW",
"inputTypes": [
"Message"
],
"type": "str"
}
},
- "id": "reactflow__edge-OpenAIModel-VVLPR{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-VVLPRœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-EujCa{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-EujCaœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
- "source": "OpenAIModel-VVLPR",
- "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-VVLPRœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
- "target": "ChatOutput-EujCa",
- "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-EujCaœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "id": "reactflow__edge-OpenAIModel-XJ1BC{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-XJ1BCœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-D2eyW{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-D2eyWœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "OpenAIModel-XJ1BC",
+ "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-XJ1BCœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "ChatOutput-D2eyW",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-D2eyWœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
- "className": "",
"data": {
"sourceHandle": {
"dataType": "OpenAIEmbeddings",
- "id": "OpenAIEmbeddings-BF7iH",
+ "id": "OpenAIEmbeddings-xoSJQ",
"name": "embeddings",
- "output_types": [
- "Embeddings"
- ]
+ "output_types": ["Embeddings"]
},
"targetHandle": {
"fieldName": "embedding_model",
- "id": "AstraDB-Qdaes",
+ "id": "AstraDB-HXAXh",
"inputTypes": [
"Embeddings"
],
"type": "other"
}
},
- "id": "reactflow__edge-OpenAIEmbeddings-BF7iH{œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-BF7iHœ,œnameœ:œembeddingsœ,œoutput_typesœ:[œEmbeddingsœ]}-AstraDB-Qdaes{œfieldNameœ:œembedding_modelœ,œidœ:œAstraDB-Qdaesœ,œinputTypesœ:[œEmbeddingsœ],œtypeœ:œotherœ}",
- "source": "OpenAIEmbeddings-BF7iH",
- "sourceHandle": "{œdataTypeœ: œOpenAIEmbeddingsœ, œidœ: œOpenAIEmbeddings-BF7iHœ, œnameœ: œembeddingsœ, œoutput_typesœ: [œEmbeddingsœ]}",
- "target": "AstraDB-Qdaes",
- "targetHandle": "{œfieldNameœ: œembedding_modelœ, œidœ: œAstraDB-Qdaesœ, œinputTypesœ: [œEmbeddingsœ], œtypeœ: œotherœ}"
+ "id": "xy-edge__OpenAIEmbeddings-xoSJQ{œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-xoSJQœ,œnameœ:œembeddingsœ,œoutput_typesœ:[œEmbeddingsœ]}-AstraDB-HXAXh{œfieldNameœ:œembedding_modelœ,œidœ:œAstraDB-HXAXhœ,œinputTypesœ:[œEmbeddingsœ],œtypeœ:œotherœ}",
+ "source": "OpenAIEmbeddings-xoSJQ",
+ "sourceHandle": "{œdataTypeœ: œOpenAIEmbeddingsœ, œidœ: œOpenAIEmbeddings-xoSJQœ, œnameœ: œembeddingsœ, œoutput_typesœ: [œEmbeddingsœ]}",
+ "target": "AstraDB-HXAXh",
+ "targetHandle": "{œfieldNameœ: œembedding_modelœ, œidœ: œAstraDB-HXAXhœ, œinputTypesœ: [œEmbeddingsœ], œtypeœ: œotherœ}"
},
{
- "className": "",
"data": {
"sourceHandle": {
"dataType": "ChatInput",
- "id": "ChatInput-Jy5aI",
+ "id": "ChatInput-IRziS",
"name": "message",
- "output_types": [
- "Message"
- ]
+ "output_types": ["Message"]
},
"targetHandle": {
"fieldName": "search_query",
- "id": "AstraDB-Qdaes",
+ "id": "AstraDB-HXAXh",
"inputTypes": [
"Message"
],
"type": "str"
}
},
- "id": "reactflow__edge-ChatInput-Jy5aI{œdataTypeœ:œChatInputœ,œidœ:œChatInput-Jy5aIœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-AstraDB-Qdaes{œfieldNameœ:œsearch_queryœ,œidœ:œAstraDB-Qdaesœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
- "source": "ChatInput-Jy5aI",
- "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-Jy5aIœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
- "target": "AstraDB-Qdaes",
- "targetHandle": "{œfieldNameœ: œsearch_queryœ, œidœ: œAstraDB-Qdaesœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ "id": "xy-edge__ChatInput-IRziS{œdataTypeœ:œChatInputœ,œidœ:œChatInput-IRziSœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-AstraDB-HXAXh{œfieldNameœ:œsearch_queryœ,œidœ:œAstraDB-HXAXhœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "source": "ChatInput-IRziS",
+ "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-IRziSœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "AstraDB-HXAXh",
+ "targetHandle": "{œfieldNameœ: œsearch_queryœ, œidœ: œAstraDB-HXAXhœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
- "className": "",
"data": {
"sourceHandle": {
"dataType": "AstraDB",
- "id": "AstraDB-Qdaes",
+ "id": "AstraDB-HXAXh",
"name": "search_results",
- "output_types": [
- "Data"
- ]
+ "output_types": ["Data"]
},
"targetHandle": {
"fieldName": "data",
- "id": "ParseData-9zsFp",
+ "id": "ParseData-cwmU0",
"inputTypes": [
"Data"
],
"type": "other"
}
},
- "id": "reactflow__edge-AstraDB-Qdaes{œdataTypeœ:œAstraDBœ,œidœ:œAstraDB-Qdaesœ,œnameœ:œsearch_resultsœ,œoutput_typesœ:[œDataœ]}-ParseData-9zsFp{œfieldNameœ:œdataœ,œidœ:œParseData-9zsFpœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}",
- "source": "AstraDB-Qdaes",
- "sourceHandle": "{œdataTypeœ: œAstraDBœ, œidœ: œAstraDB-Qdaesœ, œnameœ: œsearch_resultsœ, œoutput_typesœ: [œDataœ]}",
- "target": "ParseData-9zsFp",
- "targetHandle": "{œfieldNameœ: œdataœ, œidœ: œParseData-9zsFpœ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}"
+ "id": "xy-edge__AstraDB-HXAXh{œdataTypeœ:œAstraDBœ,œidœ:œAstraDB-HXAXhœ,œnameœ:œsearch_resultsœ,œoutput_typesœ:[œDataœ]}-ParseData-cwmU0{œfieldNameœ:œdataœ,œidœ:œParseData-cwmU0œ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}",
+ "source": "AstraDB-HXAXh",
+ "sourceHandle": "{œdataTypeœ: œAstraDBœ, œidœ: œAstraDB-HXAXhœ, œnameœ: œsearch_resultsœ, œoutput_typesœ: [œDataœ]}",
+ "target": "ParseData-cwmU0",
+ "targetHandle": "{œfieldNameœ: œdataœ, œidœ: œParseData-cwmU0œ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}"
},
{
- "className": "",
"data": {
"sourceHandle": {
"dataType": "OpenAIEmbeddings",
- "id": "OpenAIEmbeddings-KNVHv",
+ "id": "OpenAIEmbeddings-d7EtR",
"name": "embeddings",
- "output_types": [
- "Embeddings"
- ]
+ "output_types": ["Embeddings"]
},
"targetHandle": {
"fieldName": "embedding_model",
- "id": "AstraDB-sPWXd",
+ "id": "AstraDB-nMlxo",
"inputTypes": [
"Embeddings"
],
"type": "other"
}
},
- "id": "reactflow__edge-OpenAIEmbeddings-KNVHv{œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-KNVHvœ,œnameœ:œembeddingsœ,œoutput_typesœ:[œEmbeddingsœ]}-AstraDB-sPWXd{œfieldNameœ:œembedding_modelœ,œidœ:œAstraDB-sPWXdœ,œinputTypesœ:[œEmbeddingsœ],œtypeœ:œotherœ}",
- "source": "OpenAIEmbeddings-KNVHv",
- "sourceHandle": "{œdataTypeœ: œOpenAIEmbeddingsœ, œidœ: œOpenAIEmbeddings-KNVHvœ, œnameœ: œembeddingsœ, œoutput_typesœ: [œEmbeddingsœ]}",
- "target": "AstraDB-sPWXd",
- "targetHandle": "{œfieldNameœ: œembedding_modelœ, œidœ: œAstraDB-sPWXdœ, œinputTypesœ: [œEmbeddingsœ], œtypeœ: œotherœ}"
+ "id": "xy-edge__OpenAIEmbeddings-d7EtR{œdataTypeœ:œOpenAIEmbeddingsœ,œidœ:œOpenAIEmbeddings-d7EtRœ,œnameœ:œembeddingsœ,œoutput_typesœ:[œEmbeddingsœ]}-AstraDB-nMlxo{œfieldNameœ:œembedding_modelœ,œidœ:œAstraDB-nMlxoœ,œinputTypesœ:[œEmbeddingsœ],œtypeœ:œotherœ}",
+ "source": "OpenAIEmbeddings-d7EtR",
+ "sourceHandle": "{œdataTypeœ: œOpenAIEmbeddingsœ, œidœ: œOpenAIEmbeddings-d7EtRœ, œnameœ: œembeddingsœ, œoutput_typesœ: [œEmbeddingsœ]}",
+ "target": "AstraDB-nMlxo",
+ "targetHandle": "{œfieldNameœ: œembedding_modelœ, œidœ: œAstraDB-nMlxoœ, œinputTypesœ: [œEmbeddingsœ], œtypeœ: œotherœ}"
},
{
- "className": "",
"data": {
"sourceHandle": {
"dataType": "SplitText",
- "id": "SplitText-DakpR",
+ "id": "SplitText-HWKil",
"name": "chunks",
- "output_types": [
- "Data"
- ]
+ "output_types": ["Data"]
},
"targetHandle": {
"fieldName": "ingest_data",
- "id": "AstraDB-sPWXd",
+ "id": "AstraDB-nMlxo",
"inputTypes": [
"Data"
],
"type": "other"
}
},
- "id": "reactflow__edge-SplitText-DakpR{œdataTypeœ:œSplitTextœ,œidœ:œSplitText-DakpRœ,œnameœ:œchunksœ,œoutput_typesœ:[œDataœ]}-AstraDB-sPWXd{œfieldNameœ:œingest_dataœ,œidœ:œAstraDB-sPWXdœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}",
- "source": "SplitText-DakpR",
- "sourceHandle": "{œdataTypeœ: œSplitTextœ, œidœ: œSplitText-DakpRœ, œnameœ: œchunksœ, œoutput_typesœ: [œDataœ]}",
- "target": "AstraDB-sPWXd",
- "targetHandle": "{œfieldNameœ: œingest_dataœ, œidœ: œAstraDB-sPWXdœ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}"
+ "id": "xy-edge__SplitText-HWKil{œdataTypeœ:œSplitTextœ,œidœ:œSplitText-HWKilœ,œnameœ:œchunksœ,œoutput_typesœ:[œDataœ]}-AstraDB-nMlxo{œfieldNameœ:œingest_dataœ,œidœ:œAstraDB-nMlxoœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}",
+ "source": "SplitText-HWKil",
+ "sourceHandle": "{œdataTypeœ: œSplitTextœ, œidœ: œSplitText-HWKilœ, œnameœ: œchunksœ, œoutput_typesœ: [œDataœ]}",
+ "target": "AstraDB-nMlxo",
+ "targetHandle": "{œfieldNameœ: œingest_dataœ, œidœ: œAstraDB-nMlxoœ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}"
}
],
"nodes": [
@@ -272,11 +247,9 @@
"data": {
"description": "Get chat inputs from the Playground.",
"display_name": "Chat Input",
- "id": "ChatInput-Jy5aI",
+ "id": "ChatInput-IRziS",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -307,9 +280,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -322,9 +293,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -343,9 +312,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -442,10 +409,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -459,9 +423,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -479,9 +441,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -515,9 +475,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -536,7 +494,7 @@
},
"dragging": false,
"height": 234,
- "id": "ChatInput-Jy5aI",
+ "id": "ChatInput-IRziS",
"measured": {
"height": 234,
"width": 320
@@ -557,11 +515,9 @@
"data": {
"description": "Convert Data into plain text following a specified template.",
"display_name": "Parse Data",
- "id": "ParseData-9zsFp",
+ "id": "ParseData-cwmU0",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -569,16 +525,14 @@
"display_name": "Parse Data",
"documentation": "",
"edited": false,
- "field_order": [
- "data",
- "template",
- "sep"
- ],
+ "field_order": ["data", "template", "sep"],
"frozen": false,
"icon": "message-square",
"legacy": false,
"lf_version": "1.1.1",
- "metadata": {},
+ "metadata": {
+ "legacy_name": "Parse Data"
+ },
"output_types": [],
"outputs": [
{
@@ -589,9 +543,7 @@
"name": "text",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -602,9 +554,7 @@
"name": "data_list",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -627,16 +577,14 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n\n inputs = [\n DataInput(name=\"data\", display_name=\"Data\", info=\"The data to convert to text.\", is_list=True, required=True),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
+ "value": "from langflow.custom import Component\nfrom langflow.helpers.data import data_to_text, data_to_text_list\nfrom langflow.io import DataInput, MultilineInput, Output, StrInput\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass ParseDataComponent(Component):\n display_name = \"Data to Message\"\n description = \"Convert Data objects into Messages using any {field_name} from input data.\"\n icon = \"message-square\"\n name = \"ParseData\"\n metadata = {\n \"legacy_name\": \"Parse Data\",\n }\n\n inputs = [\n DataInput(\n name=\"data\",\n display_name=\"Data\",\n info=\"The data to convert to text.\",\n is_list=True,\n required=True,\n ),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {data} or any other key in the Data.\",\n value=\"{text}\",\n required=True,\n ),\n StrInput(name=\"sep\", display_name=\"Separator\", advanced=True, value=\"\\n\"),\n ]\n\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"text\",\n info=\"Data as a single Message, with each input Data separated by Separator\",\n method=\"parse_data\",\n ),\n Output(\n display_name=\"Data List\",\n name=\"data_list\",\n info=\"Data as a list of new Data, each having `text` formatted by Template\",\n method=\"parse_data_as_list\",\n ),\n ]\n\n def _clean_args(self) -> tuple[list[Data], str, str]:\n data = self.data if isinstance(self.data, list) else [self.data]\n template = self.template\n sep = self.sep\n return data, template, sep\n\n def parse_data(self) -> Message:\n data, template, sep = self._clean_args()\n result_string = data_to_text(template, data, sep)\n self.status = result_string\n return Message(text=result_string)\n\n def parse_data_as_list(self) -> list[Data]:\n data, template, _ = self._clean_args()\n text_list, data_list = data_to_text_list(template, data)\n for item, text in zip(data_list, text_list, strict=True):\n item.set_text(text)\n self.status = data_list\n return data_list\n"
},
"data": {
"advanced": false,
"display_name": "Data",
"dynamic": false,
"info": "The data to convert to text.",
- "input_types": [
- "Data"
- ],
+ "input_types": ["Data"],
"list": true,
"name": "data",
"placeholder": "",
@@ -669,9 +617,7 @@
"display_name": "Template",
"dynamic": false,
"info": "The template to use for formatting the data. It can contain the keys {text}, {data} or any other key in the Data.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -691,7 +637,7 @@
},
"dragging": false,
"height": 350,
- "id": "ParseData-9zsFp",
+ "id": "ParseData-cwmU0",
"measured": {
"height": 350,
"width": 320
@@ -712,27 +658,20 @@
"data": {
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
- "id": "Prompt-mqa6n",
+ "id": "Prompt-wBjYe",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {
- "template": [
- "context",
- "question"
- ]
+ "template": ["context", "question"]
},
"description": "Create a prompt template with dynamic variables.",
"display_name": "Prompt",
"documentation": "",
"edited": false,
"error": null,
- "field_order": [
- "template"
- ],
+ "field_order": ["template"],
"frozen": false,
"full_path": null,
"icon": "prompts",
@@ -753,9 +692,7 @@
"name": "prompt",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -788,10 +725,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -811,10 +745,7 @@
"fileTypes": [],
"file_path": "",
"info": "",
- "input_types": [
- "Message",
- "Text"
- ],
+ "input_types": ["Message", "Text"],
"list": false,
"load_from_db": false,
"multiline": true,
@@ -848,9 +779,7 @@
"display_name": "Tool Placeholder",
"dynamic": false,
"info": "A placeholder input for tool mode.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tool_placeholder",
@@ -871,7 +800,7 @@
},
"dragging": false,
"height": 433,
- "id": "Prompt-mqa6n",
+ "id": "Prompt-wBjYe",
"measured": {
"height": 433,
"width": 320
@@ -892,11 +821,9 @@
"data": {
"description": "Split text into chunks based on specified criteria.",
"display_name": "Split Text",
- "id": "SplitText-DakpR",
+ "id": "SplitText-HWKil",
"node": {
- "base_classes": [
- "Data"
- ],
+ "base_classes": ["Data"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -925,9 +852,7 @@
"name": "chunks",
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
},
{
@@ -938,9 +863,7 @@
"name": "dataframe",
"selected": "DataFrame",
"tool_mode": true,
- "types": [
- "DataFrame"
- ],
+ "types": ["DataFrame"],
"value": "__UNDEFINED__"
}
],
@@ -1000,9 +923,7 @@
"display_name": "Data Inputs",
"dynamic": false,
"info": "The data to split.",
- "input_types": [
- "Data"
- ],
+ "input_types": ["Data"],
"list": true,
"name": "data_inputs",
"placeholder": "",
@@ -1018,9 +939,7 @@
"display_name": "Separator",
"dynamic": false,
"info": "The character to split on. Defaults to newline.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "separator",
@@ -1039,7 +958,7 @@
},
"dragging": false,
"height": 475,
- "id": "SplitText-DakpR",
+ "id": "SplitText-HWKil",
"measured": {
"height": 475,
"width": 320
@@ -1058,7 +977,7 @@
},
{
"data": {
- "id": "note-Z3QTX",
+ "id": "note-fi4dw",
"node": {
"description": "## 🐕 2. Retriever Flow\n\nThis flow answers your questions with contextual data retrieved from your vector database.\n\nOpen the **Playground** and ask, \n\n```\nWhat is this document about?\n```\n",
"display_name": "",
@@ -1071,7 +990,7 @@
},
"dragging": false,
"height": 324,
- "id": "note-Z3QTX",
+ "id": "note-fi4dw",
"measured": {
"height": 324,
"width": 325
@@ -1095,7 +1014,7 @@
},
{
"data": {
- "id": "note-o6eiV",
+ "id": "note-KK8E2",
"node": {
"description": "## 📖 README\n\nLoad your data into a vector database with the 📚 **Load Data** flow, and then use your data as chat context with the 🐕 **Retriever** flow.\n\n**🚨 Add your OpenAI API key as a global variable to easily add it to all of the OpenAI components in this flow.** \n\n**Quick start**\n1. Run the 📚 **Load Data** flow.\n2. Run the 🐕 **Retriever** flow.\n\n**Next steps** \n\n- Experiment by changing the prompt and the loaded data to see how the bot's responses change. \n\nFor more info, see the [Langflow docs](https://docs.langflow.org/starter-projects-vector-store-rag).",
"display_name": "Read Me",
@@ -1108,10 +1027,10 @@
},
"dragging": false,
"height": 324,
- "id": "note-o6eiV",
+ "id": "note-KK8E2",
"measured": {
"height": 324,
- "width": 324
+ "width": 325
},
"position": {
"x": 94.28986613312418,
@@ -1134,11 +1053,9 @@
"data": {
"description": "Display a chat message in the Playground.",
"display_name": "Chat Output",
- "id": "ChatOutput-EujCa",
+ "id": "ChatOutput-D2eyW",
"node": {
- "base_classes": [
- "Message"
- ],
+ "base_classes": ["Message"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -1172,9 +1089,7 @@
"name": "message",
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
}
],
@@ -1187,9 +1102,7 @@
"display_name": "Background Color",
"dynamic": false,
"info": "The background color of the icon.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "background_color",
@@ -1209,9 +1122,7 @@
"display_name": "Icon",
"dynamic": false,
"info": "The icon of the message.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "chat_icon",
@@ -1249,9 +1160,7 @@
"display_name": "Data Template",
"dynamic": false,
"info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "data_template",
@@ -1271,9 +1180,7 @@
"display_name": "Text",
"dynamic": false,
"info": "Message to be passed as output.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "input_value",
@@ -1294,10 +1201,7 @@
"dynamic": false,
"info": "Type of sender.",
"name": "sender",
- "options": [
- "Machine",
- "User"
- ],
+ "options": ["Machine", "User"],
"placeholder": "",
"required": false,
"show": true,
@@ -1313,9 +1217,7 @@
"display_name": "Sender Name",
"dynamic": false,
"info": "Name of the sender.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "sender_name",
@@ -1335,9 +1237,7 @@
"display_name": "Session ID",
"dynamic": false,
"info": "The session ID of the chat. If empty, the current session ID parameter will be used.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "session_id",
@@ -1373,9 +1273,7 @@
"display_name": "Text Color",
"dynamic": false,
"info": "The text color of the name",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "text_color",
@@ -1396,7 +1294,7 @@
},
"dragging": false,
"height": 234,
- "id": "ChatOutput-EujCa",
+ "id": "ChatOutput-D2eyW",
"measured": {
"height": 234,
"width": 320
@@ -1415,11 +1313,9 @@
},
{
"data": {
- "id": "OpenAIEmbeddings-BF7iH",
+ "id": "OpenAIEmbeddings-xoSJQ",
"node": {
- "base_classes": [
- "Embeddings"
- ],
+ "base_classes": ["Embeddings"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -1463,14 +1359,10 @@
"display_name": "Embeddings",
"method": "build_embeddings",
"name": "embeddings",
- "required_inputs": [
- "openai_api_key"
- ],
+ "required_inputs": ["openai_api_key"],
"selected": "Embeddings",
"tool_mode": true,
- "types": [
- "Embeddings"
- ],
+ "types": ["Embeddings"],
"value": "__UNDEFINED__"
}
],
@@ -1499,9 +1391,7 @@
"display_name": "Client",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "client",
@@ -1571,9 +1461,7 @@
"display_name": "Deployment",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "deployment",
@@ -1679,9 +1567,7 @@
"display_name": "OpenAI API Base",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_api_base",
@@ -1701,9 +1587,7 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "openai_api_key",
"password": true,
@@ -1712,7 +1596,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"openai_api_type": {
"_input_type": "MessageTextInput",
@@ -1720,9 +1604,7 @@
"display_name": "OpenAI API Type",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_api_type",
@@ -1742,9 +1624,7 @@
"display_name": "OpenAI API Version",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_api_version",
@@ -1764,9 +1644,7 @@
"display_name": "OpenAI Organization",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_organization",
@@ -1786,9 +1664,7 @@
"display_name": "OpenAI Proxy",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_proxy",
@@ -1872,9 +1748,7 @@
"display_name": "TikToken Model Name",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tiktoken_model_name",
@@ -1895,7 +1769,7 @@
},
"dragging": false,
"height": 320,
- "id": "OpenAIEmbeddings-BF7iH",
+ "id": "OpenAIEmbeddings-xoSJQ",
"measured": {
"height": 320,
"width": 320
@@ -1914,7 +1788,7 @@
},
{
"data": {
- "id": "note-7sR5R",
+ "id": "note-NTe8U",
"node": {
"description": "## 📚 1. Load Data Flow\n\nRun this first! Load data from a local file and embed it into the vector database.\n\nSelect a Database and a Collection, or create new ones. \n\nClick ▶️ **Run component** on the **Astra DB** component to load your data.\n\n* If you're using OSS Langflow, add your Astra DB Application Token to the Astra DB component.\n\n#### Next steps:\n Experiment by changing the prompt and the contextual data to see how the retrieval flow's responses change.",
"display_name": "",
@@ -1927,10 +1801,10 @@
},
"dragging": false,
"height": 324,
- "id": "note-7sR5R",
+ "id": "note-NTe8U",
"measured": {
"height": 324,
- "width": 324
+ "width": 325
},
"position": {
"x": 955.3277857006676,
@@ -1941,7 +1815,7 @@
"y": 1552.171191793604
},
"resizing": false,
- "selected": true,
+ "selected": false,
"style": {
"height": 324,
"width": 324
@@ -1951,11 +1825,9 @@
},
{
"data": {
- "id": "OpenAIEmbeddings-KNVHv",
+ "id": "OpenAIEmbeddings-d7EtR",
"node": {
- "base_classes": [
- "Embeddings"
- ],
+ "base_classes": ["Embeddings"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -1999,14 +1871,10 @@
"display_name": "Embeddings",
"method": "build_embeddings",
"name": "embeddings",
- "required_inputs": [
- "openai_api_key"
- ],
+ "required_inputs": ["openai_api_key"],
"selected": "Embeddings",
"tool_mode": true,
- "types": [
- "Embeddings"
- ],
+ "types": ["Embeddings"],
"value": "__UNDEFINED__"
}
],
@@ -2035,9 +1903,7 @@
"display_name": "Client",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "client",
@@ -2107,9 +1973,7 @@
"display_name": "Deployment",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "deployment",
@@ -2215,9 +2079,7 @@
"display_name": "OpenAI API Base",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_api_base",
@@ -2237,9 +2099,7 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "openai_api_key",
"password": true,
@@ -2248,7 +2108,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"openai_api_type": {
"_input_type": "MessageTextInput",
@@ -2256,9 +2116,7 @@
"display_name": "OpenAI API Type",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_api_type",
@@ -2278,9 +2136,7 @@
"display_name": "OpenAI API Version",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_api_version",
@@ -2300,9 +2156,7 @@
"display_name": "OpenAI Organization",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_organization",
@@ -2322,9 +2176,7 @@
"display_name": "OpenAI Proxy",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "openai_proxy",
@@ -2408,9 +2260,7 @@
"display_name": "TikToken Model Name",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"load_from_db": false,
"name": "tiktoken_model_name",
@@ -2431,7 +2281,7 @@
},
"dragging": false,
"height": 320,
- "id": "OpenAIEmbeddings-KNVHv",
+ "id": "OpenAIEmbeddings-d7EtR",
"measured": {
"height": 320,
"width": 320
@@ -2450,11 +2300,9 @@
},
{
"data": {
- "id": "File-i8StI",
+ "id": "File-4yyks",
"node": {
- "base_classes": [
- "Data"
- ],
+ "base_classes": ["Data"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -2484,9 +2332,7 @@
"required_inputs": [],
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
}
],
@@ -2549,10 +2395,7 @@
"display_name": "Server File Path",
"dynamic": false,
"info": "Data object with a 'file_path' property pointing to server file or a Message object with a path to the file. Supercedes 'Path' but supports same file types.",
- "input_types": [
- "Data",
- "Message"
- ],
+ "input_types": ["Data", "Message"],
"list": true,
"name": "file_path",
"placeholder": "",
@@ -2676,7 +2519,7 @@
},
"dragging": false,
"height": 367,
- "id": "File-i8StI",
+ "id": "File-4yyks",
"measured": {
"height": 367,
"width": 320
@@ -2695,7 +2538,7 @@
},
{
"data": {
- "id": "note-LxvwE",
+ "id": "note-KLxcd",
"node": {
"description": "### 💡 Add your OpenAI API key here 👇",
"display_name": "",
@@ -2708,7 +2551,7 @@
},
"dragging": false,
"height": 324,
- "id": "note-LxvwE",
+ "id": "note-KLxcd",
"measured": {
"height": 324,
"width": 324
@@ -2727,7 +2570,7 @@
},
{
"data": {
- "id": "note-PkcXs",
+ "id": "note-rKy2s",
"node": {
"description": "### 💡 Add your OpenAI API key here 👇",
"display_name": "",
@@ -2740,7 +2583,7 @@
},
"dragging": false,
"height": 324,
- "id": "note-PkcXs",
+ "id": "note-rKy2s",
"measured": {
"height": 324,
"width": 324
@@ -2759,7 +2602,7 @@
},
{
"data": {
- "id": "note-vhWhj",
+ "id": "note-cjRCD",
"node": {
"description": "### 💡 Add your OpenAI API key here 👇",
"display_name": "",
@@ -2772,7 +2615,7 @@
},
"dragging": false,
"height": 324,
- "id": "note-vhWhj",
+ "id": "note-cjRCD",
"measured": {
"height": 324,
"width": 324
@@ -2791,12 +2634,9 @@
},
{
"data": {
- "id": "OpenAIModel-VVLPR",
+ "id": "OpenAIModel-XJ1BC",
"node": {
- "base_classes": [
- "LanguageModel",
- "Message"
- ],
+ "base_classes": ["LanguageModel", "Message"],
"beta": false,
"category": "models",
"conditional_paths": [],
@@ -2835,9 +2675,7 @@
"required_inputs": [],
"selected": "Message",
"tool_mode": true,
- "types": [
- "Message"
- ],
+ "types": ["Message"],
"value": "__UNDEFINED__"
},
{
@@ -2846,14 +2684,10 @@
"display_name": "Language Model",
"method": "build_model",
"name": "model_output",
- "required_inputs": [
- "api_key"
- ],
+ "required_inputs": ["api_key"],
"selected": "LanguageModel",
"tool_mode": true,
- "types": [
- "LanguageModel"
- ],
+ "types": ["LanguageModel"],
"value": "__UNDEFINED__"
}
],
@@ -2867,9 +2701,7 @@
"display_name": "OpenAI API Key",
"dynamic": false,
"info": "The OpenAI API Key to use for the OpenAI model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"load_from_db": true,
"name": "api_key",
"password": true,
@@ -2878,7 +2710,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "OPENAI_API_KEY"
},
"code": {
"advanced": true,
@@ -2904,9 +2736,7 @@
"display_name": "Input",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -3088,9 +2918,7 @@
"display_name": "System Message",
"dynamic": false,
"info": "System message to pass to the model.",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -3159,9 +2987,9 @@
"type": "OpenAIModel"
},
"dragging": false,
- "id": "OpenAIModel-VVLPR",
+ "id": "OpenAIModel-XJ1BC",
"measured": {
- "height": 653,
+ "height": 656,
"width": 320
},
"position": {
@@ -3173,12 +3001,9 @@
},
{
"data": {
- "id": "AstraDB-Qdaes",
+ "id": "AstraDB-HXAXh",
"node": {
- "base_classes": [
- "Data",
- "DataFrame"
- ],
+ "base_classes": ["Data", "DataFrame"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -3189,6 +3014,7 @@
"field_order": [
"token",
"environment",
+ "database_name",
"api_endpoint",
"collection_name",
"keyspace",
@@ -3200,6 +3026,7 @@
"search_type",
"search_score_threshold",
"advanced_search_filter",
+ "autodetect_collection",
"content_field",
"deletion_field",
"ignore_invalid_documents",
@@ -3219,15 +3046,13 @@
"method": "search_documents",
"name": "search_results",
"required_inputs": [
- "api_endpoint",
"collection_name",
+ "database_name",
"token"
],
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
},
{
@@ -3239,9 +3064,7 @@
"required_inputs": [],
"selected": "DataFrame",
"tool_mode": true,
- "types": [
- "DataFrame"
- ],
+ "types": ["DataFrame"],
"value": "__UNDEFINED__"
}
],
@@ -3268,20 +3091,17 @@
"value": {}
},
"api_endpoint": {
- "_input_type": "DropdownInput",
- "advanced": false,
- "combobox": true,
- "dialog_inputs": {},
- "display_name": "Database",
+ "_input_type": "StrInput",
+ "advanced": true,
+ "display_name": "Astra DB API Endpoint",
"dynamic": false,
- "info": "The Database / API Endpoint for the Astra DB instance.",
- "name": "Database",
- "options": [],
- "options_metadata": [],
+ "info": "The API Endpoint for the Astra DB instance. Supercedes database selection.",
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "api_endpoint",
"placeholder": "",
- "real_time_refresh": true,
- "refresh_button": true,
- "required": true,
+ "required": false,
"show": true,
"title_case": false,
"tool_mode": false,
@@ -3342,13 +3162,115 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "import os\nfrom collections import defaultdict\nfrom dataclasses import dataclass, field\n\nfrom astrapy import AstraDBAdmin, DataAPIClient, Database\nfrom langchain_astradb import AstraDBVectorStore, CollectionVectorServiceOptions\n\nfrom langflow.base.vectorstores.model import LCVectorStoreComponent, check_cached_vector_store\nfrom langflow.helpers import docs_to_data\nfrom langflow.inputs import FloatInput, NestedDictInput\nfrom langflow.io import (\n BoolInput,\n DropdownInput,\n HandleInput,\n IntInput,\n SecretStrInput,\n StrInput,\n)\nfrom langflow.schema import Data\nfrom langflow.utils.version import get_version_info\n\n\nclass AstraDBVectorStoreComponent(LCVectorStoreComponent):\n display_name: str = \"Astra DB\"\n description: str = \"Ingest and search documents in Astra DB\"\n documentation: str = \"https://docs.datastax.com/en/langflow/astra-components.html\"\n name = \"AstraDB\"\n icon: str = \"AstraDB\"\n\n _cached_vector_store: AstraDBVectorStore | None = None\n\n @dataclass\n class NewDatabaseInput:\n functionality: str = \"create\"\n fields: dict[str, dict] = field(\n default_factory=lambda: {\n \"data\": {\n \"node\": {\n \"description\": \"Create a new database in Astra DB.\",\n \"display_name\": \"Create New Database\",\n \"field_order\": [\"new_database_name\", \"cloud_provider\", \"region\"],\n \"template\": {\n \"new_database_name\": StrInput(\n name=\"new_database_name\",\n display_name=\"New Database Name\",\n info=\"Name of the new database to create in Astra DB.\",\n required=True,\n ),\n \"cloud_provider\": DropdownInput(\n name=\"cloud_provider\",\n display_name=\"Cloud Provider\",\n info=\"Cloud provider for the new database.\",\n options=[\"Amazon Web Services\", \"Google Cloud Platform\", \"Microsoft Azure\"],\n required=True,\n ),\n \"region\": DropdownInput(\n name=\"region\",\n display_name=\"Region\",\n info=\"Region for the new database.\",\n options=[],\n required=True,\n ),\n },\n },\n }\n }\n )\n\n @dataclass\n class NewCollectionInput:\n functionality: str = \"create\"\n fields: dict[str, dict] = field(\n default_factory=lambda: {\n \"data\": {\n \"node\": {\n \"description\": \"Create a new collection in Astra DB.\",\n \"display_name\": \"Create New Collection\",\n \"field_order\": [\n \"new_collection_name\",\n \"embedding_generation_provider\",\n \"embedding_generation_model\",\n ],\n \"template\": {\n \"new_collection_name\": StrInput(\n name=\"new_collection_name\",\n display_name=\"New Collection Name\",\n info=\"Name of the new collection to create in Astra DB.\",\n required=True,\n ),\n \"embedding_generation_provider\": DropdownInput(\n name=\"embedding_generation_provider\",\n display_name=\"Embedding Generation Provider\",\n info=\"Provider to use for generating embeddings.\",\n options=[],\n required=True,\n ),\n \"embedding_generation_model\": DropdownInput(\n name=\"embedding_generation_model\",\n display_name=\"Embedding Generation Model\",\n info=\"Model to use for generating embeddings.\",\n options=[],\n required=True,\n ),\n },\n },\n }\n }\n )\n\n inputs = [\n SecretStrInput(\n name=\"token\",\n display_name=\"Astra DB Application Token\",\n info=\"Authentication token for accessing Astra DB.\",\n value=\"ASTRA_DB_APPLICATION_TOKEN\",\n required=True,\n real_time_refresh=True,\n input_types=[],\n ),\n StrInput(\n name=\"environment\",\n display_name=\"Environment\",\n info=\"The environment for the Astra DB API Endpoint.\",\n advanced=True,\n real_time_refresh=True,\n ),\n DropdownInput(\n name=\"api_endpoint\",\n display_name=\"Database\",\n info=\"The Database / API Endpoint for the Astra DB instance.\",\n required=True,\n refresh_button=True,\n real_time_refresh=True,\n combobox=True,\n ),\n StrInput(\n name=\"d_api_endpoint\",\n display_name=\"Database API Endpoint\",\n info=\"The API Endpoint for the Astra DB instance. Supercedes database selection.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"collection_name\",\n display_name=\"Collection\",\n info=\"The name of the collection within Astra DB where the vectors will be stored.\",\n required=True,\n refresh_button=True,\n real_time_refresh=True,\n # dialog_inputs=asdict(NewCollectionInput()),\n combobox=True,\n ),\n StrInput(\n name=\"keyspace\",\n display_name=\"Keyspace\",\n info=\"Optional keyspace within Astra DB to use for the collection.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"embedding_choice\",\n display_name=\"Embedding Model or Astra Vectorize\",\n info=\"Choose an embedding model or use Astra Vectorize.\",\n options=[\"Embedding Model\", \"Astra Vectorize\"],\n value=\"Embedding Model\",\n advanced=True,\n real_time_refresh=True,\n ),\n HandleInput(\n name=\"embedding_model\",\n display_name=\"Embedding Model\",\n input_types=[\"Embeddings\"],\n info=\"Specify the Embedding Model. Not required for Astra Vectorize collections.\",\n required=False,\n ),\n *LCVectorStoreComponent.inputs,\n IntInput(\n name=\"number_of_results\",\n display_name=\"Number of Search Results\",\n info=\"Number of search results to return.\",\n advanced=True,\n value=4,\n ),\n DropdownInput(\n name=\"search_type\",\n display_name=\"Search Type\",\n info=\"Search type to use\",\n options=[\"Similarity\", \"Similarity with score threshold\", \"MMR (Max Marginal Relevance)\"],\n value=\"Similarity\",\n advanced=True,\n ),\n FloatInput(\n name=\"search_score_threshold\",\n display_name=\"Search Score Threshold\",\n info=\"Minimum similarity score threshold for search results. \"\n \"(when using 'Similarity with score threshold')\",\n value=0,\n advanced=True,\n ),\n NestedDictInput(\n name=\"advanced_search_filter\",\n display_name=\"Search Metadata Filter\",\n info=\"Optional dictionary of filters to apply to the search query.\",\n advanced=True,\n ),\n BoolInput(\n name=\"autodetect_collection\",\n display_name=\"Autodetect Collection\",\n info=\"Boolean flag to determine whether to autodetect the collection.\",\n advanced=True,\n value=True,\n ),\n StrInput(\n name=\"content_field\",\n display_name=\"Content Field\",\n info=\"Field to use as the text content field for the vector store.\",\n advanced=True,\n ),\n StrInput(\n name=\"deletion_field\",\n display_name=\"Deletion Based On Field\",\n info=\"When this parameter is provided, documents in the target collection with \"\n \"metadata field values matching the input metadata field value will be deleted \"\n \"before new data is loaded.\",\n advanced=True,\n ),\n BoolInput(\n name=\"ignore_invalid_documents\",\n display_name=\"Ignore Invalid Documents\",\n info=\"Boolean flag to determine whether to ignore invalid documents at runtime.\",\n advanced=True,\n ),\n NestedDictInput(\n name=\"astradb_vectorstore_kwargs\",\n display_name=\"AstraDBVectorStore Parameters\",\n info=\"Optional dictionary of additional parameters for the AstraDBVectorStore.\",\n advanced=True,\n ),\n ]\n\n @classmethod\n def map_cloud_providers(cls):\n return {\n \"Amazon Web Services\": {\n \"id\": \"aws\",\n \"regions\": [\"us-east-2\", \"ap-south-1\", \"eu-west-1\"],\n },\n \"Google Cloud Platform\": {\n \"id\": \"gcp\",\n \"regions\": [\"us-east1\"],\n },\n \"Microsoft Azure\": {\n \"id\": \"azure\",\n \"regions\": [\"westus3\"],\n },\n }\n\n @classmethod\n def create_database_api(\n cls,\n token: str,\n new_database_name: str,\n cloud_provider: str,\n region: str,\n ):\n client = DataAPIClient(token=token)\n\n # Get the admin object\n admin_client = client.get_admin(token=token)\n\n # Call the create database function\n return admin_client.create_database(\n name=new_database_name,\n cloud_provider=cloud_provider,\n region=region,\n )\n\n @classmethod\n def create_collection_api(\n cls,\n token: str,\n database_name: str,\n new_collection_name: str,\n dimension: int | None = None,\n embedding_generation_provider: str | None = None,\n embedding_generation_model: str | None = None,\n ):\n client = DataAPIClient(token=token)\n api_endpoint = cls.get_api_endpoint_static(token=token, database_name=database_name)\n\n # Get the database object\n database = client.get_database(api_endpoint=api_endpoint, token=token)\n\n # Build vectorize options, if needed\n vectorize_options = None\n if not dimension:\n vectorize_options = CollectionVectorServiceOptions(\n provider=embedding_generation_provider,\n model_name=embedding_generation_model,\n authentication=None,\n parameters=None,\n )\n\n # Create the collection\n return database.create_collection(\n name=new_collection_name,\n dimension=dimension,\n service=vectorize_options,\n )\n\n @classmethod\n def get_database_list_static(cls, token: str, environment: str | None = None):\n client = DataAPIClient(token=token, environment=environment)\n\n # Get the admin object\n admin_client = client.get_admin(token=token)\n\n # Get the list of databases\n db_list = list(admin_client.list_databases())\n\n # Set the environment properly\n env_string = \"\"\n if environment and environment != \"prod\":\n env_string = f\"-{environment}\"\n\n # Generate the api endpoint for each database\n db_info_dict = {}\n for db in db_list:\n try:\n api_endpoint = f\"https://{db.info.id}-{db.info.region}.apps.astra{env_string}.datastax.com\"\n db_info_dict[db.info.name] = {\n \"api_endpoint\": api_endpoint,\n \"collections\": len(\n list(\n client.get_database(\n api_endpoint=api_endpoint, token=token, keyspace=db.info.keyspace\n ).list_collection_names(keyspace=db.info.keyspace)\n )\n ),\n }\n except Exception: # noqa: BLE001, S110\n pass\n\n return db_info_dict\n\n def get_database_list(self):\n return self.get_database_list_static(token=self.token, environment=self.environment)\n\n @classmethod\n def get_api_endpoint_static(\n cls,\n token: str,\n environment: str | None = None,\n api_endpoint: str | None = None,\n database_name: str | None = None,\n ):\n # If the api_endpoint is set, return it\n if api_endpoint:\n return api_endpoint\n\n # Check if the database_name is like a url\n if database_name and database_name.startswith(\"https://\"):\n return database_name\n\n # If the database is not set, nothing we can do.\n if not database_name:\n return None\n\n # Otherwise, get the URL from the database list\n return cls.get_database_list_static(token=token, environment=environment).get(database_name).get(\"api_endpoint\")\n\n def get_api_endpoint(self, *, api_endpoint: str | None = None):\n return self.get_api_endpoint_static(\n token=self.token,\n environment=self.environment,\n api_endpoint=api_endpoint or self.d_api_endpoint,\n database_name=self.api_endpoint,\n )\n\n def get_keyspace(self):\n keyspace = self.keyspace\n\n if keyspace:\n return keyspace.strip()\n\n return None\n\n def get_database_object(self, api_endpoint: str | None = None):\n try:\n client = DataAPIClient(token=self.token, environment=self.environment)\n\n return client.get_database(\n api_endpoint=self.get_api_endpoint(api_endpoint=api_endpoint),\n token=self.token,\n keyspace=self.get_keyspace(),\n )\n except Exception as e:\n msg = f\"Error fetching database object: {e}\"\n raise ValueError(msg) from e\n\n def collection_data(self, collection_name: str, database: Database | None = None):\n try:\n if not database:\n client = DataAPIClient(token=self.token, environment=self.environment)\n\n database = client.get_database(\n api_endpoint=self.get_api_endpoint(),\n token=self.token,\n keyspace=self.get_keyspace(),\n )\n\n collection = database.get_collection(collection_name, keyspace=self.get_keyspace())\n\n return collection.estimated_document_count()\n except Exception as e: # noqa: BLE001\n self.log(f\"Error checking collection data: {e}\")\n\n return None\n\n def get_vectorize_providers(self):\n try:\n self.log(\"Dynamically updating list of Vectorize providers.\")\n\n # Get the admin object\n admin = AstraDBAdmin(token=self.token)\n db_admin = admin.get_database_admin(api_endpoint=self.get_api_endpoint())\n\n # Get the list of embedding providers\n embedding_providers = db_admin.find_embedding_providers().as_dict()\n\n vectorize_providers_mapping = {}\n # Map the provider display name to the provider key and models\n for provider_key, provider_data in embedding_providers[\"embeddingProviders\"].items():\n display_name = provider_data[\"displayName\"]\n models = [model[\"name\"] for model in provider_data[\"models\"]]\n\n # TODO: https://astra.datastax.com/api/v2/graphql\n vectorize_providers_mapping[display_name] = [provider_key, models]\n\n # Sort the resulting dictionary\n return defaultdict(list, dict(sorted(vectorize_providers_mapping.items())))\n except Exception as e: # noqa: BLE001\n self.log(f\"Error fetching Vectorize providers: {e}\")\n\n return {}\n\n def _initialize_database_options(self):\n try:\n return [\n {\n \"name\": name,\n \"collections\": info[\"collections\"],\n \"api_endpoint\": info[\"api_endpoint\"],\n }\n for name, info in self.get_database_list().items()\n ]\n except Exception as e:\n msg = f\"Error fetching database options: {e}\"\n raise ValueError(msg) from e\n\n def _initialize_collection_options(self, api_endpoint: str | None = None):\n # Retrieve the database object\n database = self.get_database_object(api_endpoint=api_endpoint)\n\n # Get the list of collections\n collection_list = list(database.list_collections(keyspace=self.get_keyspace()))\n\n # Return the list of collections and metadata associated\n return [\n {\n \"name\": col.name,\n \"records\": self.collection_data(collection_name=col.name, database=database),\n \"provider\": (\n col.options.vector.service.provider if col.options.vector and col.options.vector.service else None\n ),\n \"icon\": \"\",\n \"model\": (\n col.options.vector.service.model_name if col.options.vector and col.options.vector.service else None\n ),\n }\n for col in collection_list\n ]\n\n def reset_collection_list(self, build_config: dict):\n # Get the list of options we have based on the token provided\n collection_options = self._initialize_collection_options()\n\n # If we retrieved options based on the token, show the dropdown\n build_config[\"collection_name\"][\"options\"] = [col[\"name\"] for col in collection_options]\n build_config[\"collection_name\"][\"options_metadata\"] = [\n {k: v for k, v in col.items() if k not in [\"name\"]} for col in collection_options\n ]\n\n # Reset the selected collection\n build_config[\"collection_name\"][\"value\"] = \"\"\n\n return build_config\n\n def reset_database_list(self, build_config: dict):\n # Get the list of options we have based on the token provided\n database_options = self._initialize_database_options()\n\n # If we retrieved options based on the token, show the dropdown\n build_config[\"api_endpoint\"][\"options\"] = [db[\"name\"] for db in database_options]\n build_config[\"api_endpoint\"][\"options_metadata\"] = [\n {k: v for k, v in db.items() if k not in [\"name\"]} for db in database_options\n ]\n\n # Reset the selected database\n build_config[\"api_endpoint\"][\"value\"] = \"\"\n\n return build_config\n\n def reset_build_config(self, build_config: dict):\n # Reset the list of databases we have based on the token provided\n build_config[\"api_endpoint\"][\"options\"] = []\n build_config[\"api_endpoint\"][\"options_metadata\"] = []\n build_config[\"api_endpoint\"][\"value\"] = \"\"\n build_config[\"api_endpoint\"][\"name\"] = \"Database\"\n\n # Reset the list of collections and metadata associated\n build_config[\"collection_name\"][\"options\"] = []\n build_config[\"collection_name\"][\"options_metadata\"] = []\n build_config[\"collection_name\"][\"value\"] = \"\"\n\n return build_config\n\n def update_build_config(self, build_config: dict, field_value: str, field_name: str | None = None):\n # When the component first executes, this is the update refresh call\n first_run = field_name == \"collection_name\" and not field_value and not build_config[\"api_endpoint\"][\"options\"]\n\n # If the token has not been provided, simply return\n if not self.token:\n return self.reset_build_config(build_config)\n\n # If this is the first execution of the component, reset and build database list\n if first_run or field_name in [\"token\", \"environment\"]:\n # Reset the build config to ensure we are starting fresh\n build_config = self.reset_build_config(build_config)\n build_config = self.reset_database_list(build_config)\n\n # Get list of regions for a given cloud provider\n \"\"\"\n cloud_provider = (\n build_config[\"api_endpoint\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\"cloud_provider\"][\n \"value\"\n ]\n or \"Amazon Web Services\"\n )\n build_config[\"api_endpoint\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\"region\"][\n \"options\"\n ] = self.map_cloud_providers()[cloud_provider][\"regions\"]\n \"\"\"\n\n return build_config\n\n # Refresh the collection name options\n if field_name == \"api_endpoint\":\n # If missing, refresh the database options\n if not build_config[\"api_endpoint\"][\"options\"] or not field_value:\n return self.update_build_config(build_config, field_value=self.token, field_name=\"token\")\n\n # Set the underlying api endpoint value of the database\n if field_value in build_config[\"api_endpoint\"][\"options\"]:\n index_of_name = build_config[\"api_endpoint\"][\"options\"].index(field_value)\n build_config[\"d_api_endpoint\"][\"value\"] = build_config[\"api_endpoint\"][\"options_metadata\"][\n index_of_name\n ][\"api_endpoint\"]\n else:\n build_config[\"d_api_endpoint\"][\"value\"] = \"\"\n\n # Reset the list of collections we have based on the token provided\n return self.reset_collection_list(build_config)\n\n # Hide embedding model option if opriona_metadata provider is not null\n if field_name == \"collection_name\" and field_value:\n # Assume we will be autodetecting the collection:\n build_config[\"autodetect_collection\"][\"value\"] = True\n\n # Set the options for collection name to be the field value if its a new collection\n if field_value not in build_config[\"collection_name\"][\"options\"]:\n # Add the new collection to the list of options\n build_config[\"collection_name\"][\"options\"].append(field_value)\n build_config[\"collection_name\"][\"options_metadata\"].append(\n {\"records\": 0, \"provider\": None, \"icon\": \"\", \"model\": None}\n )\n\n # Ensure that autodetect collection is set to False, since its a new collection\n build_config[\"autodetect_collection\"][\"value\"] = False\n\n # Find the position of the selected collection to align with metadata\n index_of_name = build_config[\"collection_name\"][\"options\"].index(field_value)\n value_of_provider = build_config[\"collection_name\"][\"options_metadata\"][index_of_name][\"provider\"]\n\n # If we were able to determine the Vectorize provider, set it accordingly\n if value_of_provider:\n build_config[\"embedding_model\"][\"advanced\"] = True\n build_config[\"embedding_choice\"][\"value\"] = \"Astra Vectorize\"\n else:\n build_config[\"embedding_model\"][\"advanced\"] = False\n build_config[\"embedding_choice\"][\"value\"] = \"Embedding Model\"\n\n # For the final step, get the list of vectorize providers\n \"\"\"\n vectorize_providers = self.get_vectorize_providers()\n if not vectorize_providers:\n return build_config\n\n # Allow the user to see the embedding provider options\n provider_options = build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_provider\"\n ][\"options\"]\n if not provider_options:\n # If the collection is set, allow user to see embedding options\n build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_provider\"\n ][\"options\"] = [\"Bring your own\", \"Nvidia\", *[key for key in vectorize_providers if key != \"Nvidia\"]]\n\n # And allow the user to see the models based on a selected provider\n model_options = build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_model\"\n ][\"options\"]\n if not model_options:\n embedding_provider = build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_provider\"\n ][\"value\"]\n\n build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_model\"\n ][\"options\"] = vectorize_providers.get(embedding_provider, [[], []])[1]\n \"\"\"\n\n return build_config\n\n @check_cached_vector_store\n def build_vector_store(self):\n try:\n from langchain_astradb import AstraDBVectorStore\n except ImportError as e:\n msg = (\n \"Could not import langchain Astra DB integration package. \"\n \"Please install it with `pip install langchain-astradb`.\"\n )\n raise ImportError(msg) from e\n\n # Get the embedding model and additional params\n embedding_params = (\n {\"embedding\": self.embedding_model}\n if self.embedding_model and self.embedding_choice == \"Embedding Model\"\n else {}\n )\n\n # Get the additional parameters\n additional_params = self.astradb_vectorstore_kwargs or {}\n\n # Get Langflow version and platform information\n __version__ = get_version_info()[\"version\"]\n langflow_prefix = \"\"\n if os.getenv(\"AWS_EXECUTION_ENV\") == \"AWS_ECS_FARGATE\": # TODO: More precise way of detecting\n langflow_prefix = \"ds-\"\n\n # Get the database object\n database = self.get_database_object(api_endpoint=self.d_api_endpoint)\n autodetect = self.collection_name in database.list_collection_names() and self.autodetect_collection\n\n # Bundle up the auto-detect parameters\n autodetect_params = {\n \"autodetect_collection\": autodetect,\n \"content_field\": (\n self.content_field\n if self.content_field and embedding_params\n else (\n \"page_content\"\n if embedding_params\n and self.collection_data(collection_name=self.collection_name, database=database) == 0\n else None\n )\n ),\n \"ignore_invalid_documents\": self.ignore_invalid_documents,\n }\n\n # Attempt to build the Vector Store object\n try:\n vector_store = AstraDBVectorStore(\n # Astra DB Authentication Parameters\n token=self.token,\n api_endpoint=database.api_endpoint,\n namespace=database.keyspace,\n collection_name=self.collection_name,\n environment=self.environment,\n # Astra DB Usage Tracking Parameters\n ext_callers=[(f\"{langflow_prefix}langflow\", __version__)],\n # Astra DB Vector Store Parameters\n **autodetect_params,\n **embedding_params,\n **additional_params,\n )\n except Exception as e:\n msg = f\"Error initializing AstraDBVectorStore: {e}\"\n raise ValueError(msg) from e\n\n # Add documents to the vector store\n self._add_documents_to_vector_store(vector_store)\n\n return vector_store\n\n def _add_documents_to_vector_store(self, vector_store) -> None:\n documents = []\n for _input in self.ingest_data or []:\n if isinstance(_input, Data):\n documents.append(_input.to_lc_document())\n else:\n msg = \"Vector Store Inputs must be Data objects.\"\n raise TypeError(msg)\n\n if documents and self.deletion_field:\n self.log(f\"Deleting documents where {self.deletion_field}\")\n try:\n database = self.get_database_object(api_endpoint=self.d_api_endpoint)\n collection = database.get_collection(self.collection_name, keyspace=database.keyspace)\n delete_values = list({doc.metadata[self.deletion_field] for doc in documents})\n self.log(f\"Deleting documents where {self.deletion_field} matches {delete_values}.\")\n collection.delete_many({f\"metadata.{self.deletion_field}\": {\"$in\": delete_values}})\n except Exception as e:\n msg = f\"Error deleting documents from AstraDBVectorStore based on '{self.deletion_field}': {e}\"\n raise ValueError(msg) from e\n\n if documents:\n self.log(f\"Adding {len(documents)} documents to the Vector Store.\")\n try:\n vector_store.add_documents(documents)\n except Exception as e:\n msg = f\"Error adding documents to AstraDBVectorStore: {e}\"\n raise ValueError(msg) from e\n else:\n self.log(\"No documents to add to the Vector Store.\")\n\n def _map_search_type(self) -> str:\n search_type_mapping = {\n \"Similarity with score threshold\": \"similarity_score_threshold\",\n \"MMR (Max Marginal Relevance)\": \"mmr\",\n }\n\n return search_type_mapping.get(self.search_type, \"similarity\")\n\n def _build_search_args(self):\n query = self.search_query if isinstance(self.search_query, str) and self.search_query.strip() else None\n\n if query:\n args = {\n \"query\": query,\n \"search_type\": self._map_search_type(),\n \"k\": self.number_of_results,\n \"score_threshold\": self.search_score_threshold,\n }\n elif self.advanced_search_filter:\n args = {\n \"n\": self.number_of_results,\n }\n else:\n return {}\n\n filter_arg = self.advanced_search_filter or {}\n if filter_arg:\n args[\"filter\"] = filter_arg\n\n return args\n\n def search_documents(self, vector_store=None) -> list[Data]:\n vector_store = vector_store or self.build_vector_store()\n\n self.log(f\"Search input: {self.search_query}\")\n self.log(f\"Search type: {self.search_type}\")\n self.log(f\"Number of results: {self.number_of_results}\")\n\n try:\n search_args = self._build_search_args()\n except Exception as e:\n msg = f\"Error in AstraDBVectorStore._build_search_args: {e}\"\n raise ValueError(msg) from e\n\n if not search_args:\n self.log(\"No search input or filters provided. Skipping search.\")\n return []\n\n docs = []\n search_method = \"search\" if \"query\" in search_args else \"metadata_search\"\n\n try:\n self.log(f\"Calling vector_store.{search_method} with args: {search_args}\")\n docs = getattr(vector_store, search_method)(**search_args)\n except Exception as e:\n msg = f\"Error performing {search_method} in AstraDBVectorStore: {e}\"\n raise ValueError(msg) from e\n\n self.log(f\"Retrieved documents: {len(docs)}\")\n\n data = docs_to_data(docs)\n self.log(f\"Converted documents to data: {len(data)}\")\n self.status = data\n\n return data\n\n def get_retriever_kwargs(self):\n search_args = self._build_search_args()\n\n return {\n \"search_type\": self._map_search_type(),\n \"search_kwargs\": search_args,\n }\n"
+ "value": "from collections import defaultdict\nfrom dataclasses import asdict, dataclass, field\n\nfrom astrapy import AstraDBAdmin, DataAPIClient, Database\nfrom astrapy.info import CollectionDescriptor\nfrom langchain_astradb import AstraDBVectorStore, CollectionVectorServiceOptions\n\nfrom langflow.base.vectorstores.model import LCVectorStoreComponent, check_cached_vector_store\nfrom langflow.helpers import docs_to_data\nfrom langflow.inputs import FloatInput, NestedDictInput\nfrom langflow.io import (\n BoolInput,\n DropdownInput,\n HandleInput,\n IntInput,\n SecretStrInput,\n StrInput,\n)\nfrom langflow.schema import Data\nfrom langflow.utils.version import get_version_info\n\n\nclass AstraDBVectorStoreComponent(LCVectorStoreComponent):\n display_name: str = \"Astra DB\"\n description: str = \"Ingest and search documents in Astra DB\"\n documentation: str = \"https://docs.datastax.com/en/langflow/astra-components.html\"\n name = \"AstraDB\"\n icon: str = \"AstraDB\"\n\n _cached_vector_store: AstraDBVectorStore | None = None\n\n @dataclass\n class NewDatabaseInput:\n functionality: str = \"create\"\n fields: dict[str, dict] = field(\n default_factory=lambda: {\n \"data\": {\n \"node\": {\n \"name\": \"create_database\",\n \"description\": \"\",\n \"display_name\": \"Create new database\",\n \"field_order\": [\"new_database_name\", \"cloud_provider\", \"region\"],\n \"template\": {\n \"new_database_name\": StrInput(\n name=\"new_database_name\",\n display_name=\"Name\",\n info=\"Name of the new database to create in Astra DB.\",\n required=True,\n ),\n \"cloud_provider\": DropdownInput(\n name=\"cloud_provider\",\n display_name=\"Cloud provider\",\n info=\"Cloud provider for the new database.\",\n options=[\"Amazon Web Services\", \"Google Cloud Platform\", \"Microsoft Azure\"],\n required=True,\n real_time_refresh=True,\n ),\n \"region\": DropdownInput(\n name=\"region\",\n display_name=\"Region\",\n info=\"Region for the new database.\",\n options=[],\n required=True,\n ),\n },\n },\n }\n }\n )\n\n @dataclass\n class NewCollectionInput:\n functionality: str = \"create\"\n fields: dict[str, dict] = field(\n default_factory=lambda: {\n \"data\": {\n \"node\": {\n \"name\": \"create_collection\",\n \"description\": \"\",\n \"display_name\": \"Create new collection\",\n \"field_order\": [\n \"new_collection_name\",\n \"embedding_generation_provider\",\n \"embedding_generation_model\",\n ],\n \"template\": {\n \"new_collection_name\": StrInput(\n name=\"new_collection_name\",\n display_name=\"Name\",\n info=\"Name of the new collection to create in Astra DB.\",\n required=True,\n ),\n \"embedding_generation_provider\": DropdownInput(\n name=\"embedding_generation_provider\",\n display_name=\"Embedding generation method\",\n info=\"Provider to use for generating embeddings.\",\n real_time_refresh=True,\n required=True,\n options=[\"Bring your own\", \"Nvidia\"],\n ),\n \"embedding_generation_model\": DropdownInput(\n name=\"embedding_generation_model\",\n display_name=\"Embedding model\",\n info=\"Model to use for generating embeddings.\",\n required=True,\n options=[],\n ),\n \"dimension\": IntInput(\n name=\"dimension\",\n display_name=\"Dimensions (Required only for `Bring your own`)\",\n info=\"Dimensions of the embeddings to generate.\",\n required=False,\n value=1024,\n ),\n },\n },\n }\n }\n )\n\n inputs = [\n SecretStrInput(\n name=\"token\",\n display_name=\"Astra DB Application Token\",\n info=\"Authentication token for accessing Astra DB.\",\n value=\"ASTRA_DB_APPLICATION_TOKEN\",\n required=True,\n real_time_refresh=True,\n input_types=[],\n ),\n StrInput(\n name=\"environment\",\n display_name=\"Environment\",\n info=\"The environment for the Astra DB API Endpoint.\",\n advanced=True,\n real_time_refresh=True,\n ),\n DropdownInput(\n name=\"database_name\",\n display_name=\"Database\",\n info=\"The Database name for the Astra DB instance.\",\n required=True,\n refresh_button=True,\n real_time_refresh=True,\n dialog_inputs=asdict(NewDatabaseInput()),\n combobox=True,\n ),\n StrInput(\n name=\"api_endpoint\",\n display_name=\"Astra DB API Endpoint\",\n info=\"The API Endpoint for the Astra DB instance. Supercedes database selection.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"collection_name\",\n display_name=\"Collection\",\n info=\"The name of the collection within Astra DB where the vectors will be stored.\",\n required=True,\n refresh_button=True,\n real_time_refresh=True,\n dialog_inputs=asdict(NewCollectionInput()),\n combobox=True,\n advanced=True,\n ),\n StrInput(\n name=\"keyspace\",\n display_name=\"Keyspace\",\n info=\"Optional keyspace within Astra DB to use for the collection.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"embedding_choice\",\n display_name=\"Embedding Model or Astra Vectorize\",\n info=\"Choose an embedding model or use Astra Vectorize.\",\n options=[\"Embedding Model\", \"Astra Vectorize\"],\n value=\"Embedding Model\",\n advanced=True,\n real_time_refresh=True,\n ),\n HandleInput(\n name=\"embedding_model\",\n display_name=\"Embedding Model\",\n input_types=[\"Embeddings\"],\n info=\"Specify the Embedding Model. Not required for Astra Vectorize collections.\",\n required=False,\n ),\n *LCVectorStoreComponent.inputs,\n IntInput(\n name=\"number_of_results\",\n display_name=\"Number of Search Results\",\n info=\"Number of search results to return.\",\n advanced=True,\n value=4,\n ),\n DropdownInput(\n name=\"search_type\",\n display_name=\"Search Type\",\n info=\"Search type to use\",\n options=[\"Similarity\", \"Similarity with score threshold\", \"MMR (Max Marginal Relevance)\"],\n value=\"Similarity\",\n advanced=True,\n ),\n FloatInput(\n name=\"search_score_threshold\",\n display_name=\"Search Score Threshold\",\n info=\"Minimum similarity score threshold for search results. \"\n \"(when using 'Similarity with score threshold')\",\n value=0,\n advanced=True,\n ),\n NestedDictInput(\n name=\"advanced_search_filter\",\n display_name=\"Search Metadata Filter\",\n info=\"Optional dictionary of filters to apply to the search query.\",\n advanced=True,\n ),\n BoolInput(\n name=\"autodetect_collection\",\n display_name=\"Autodetect Collection\",\n info=\"Boolean flag to determine whether to autodetect the collection.\",\n advanced=True,\n value=True,\n ),\n StrInput(\n name=\"content_field\",\n display_name=\"Content Field\",\n info=\"Field to use as the text content field for the vector store.\",\n advanced=True,\n ),\n StrInput(\n name=\"deletion_field\",\n display_name=\"Deletion Based On Field\",\n info=\"When this parameter is provided, documents in the target collection with \"\n \"metadata field values matching the input metadata field value will be deleted \"\n \"before new data is loaded.\",\n advanced=True,\n ),\n BoolInput(\n name=\"ignore_invalid_documents\",\n display_name=\"Ignore Invalid Documents\",\n info=\"Boolean flag to determine whether to ignore invalid documents at runtime.\",\n advanced=True,\n ),\n NestedDictInput(\n name=\"astradb_vectorstore_kwargs\",\n display_name=\"AstraDBVectorStore Parameters\",\n info=\"Optional dictionary of additional parameters for the AstraDBVectorStore.\",\n advanced=True,\n ),\n ]\n\n @classmethod\n def map_cloud_providers(cls):\n # TODO: Programmatically fetch the regions for each cloud provider\n return {\n \"Amazon Web Services\": {\n \"id\": \"aws\",\n \"regions\": [\"us-east-2\", \"ap-south-1\", \"eu-west-1\"],\n },\n \"Google Cloud Platform\": {\n \"id\": \"gcp\",\n \"regions\": [\"us-east1\"],\n },\n \"Microsoft Azure\": {\n \"id\": \"azure\",\n \"regions\": [\"westus3\"],\n },\n }\n\n @classmethod\n def get_vectorize_providers(cls, token: str, environment: str | None = None, api_endpoint: str | None = None):\n try:\n # Get the admin object\n admin = AstraDBAdmin(token=token, environment=environment)\n db_admin = admin.get_database_admin(api_endpoint=api_endpoint)\n\n # Get the list of embedding providers\n embedding_providers = db_admin.find_embedding_providers().as_dict()\n\n vectorize_providers_mapping = {}\n # Map the provider display name to the provider key and models\n for provider_key, provider_data in embedding_providers[\"embeddingProviders\"].items():\n # Get the provider display name and models\n display_name = provider_data[\"displayName\"]\n models = [model[\"name\"] for model in provider_data[\"models\"]]\n\n # Build our mapping\n vectorize_providers_mapping[display_name] = [provider_key, models]\n\n # Sort the resulting dictionary\n return defaultdict(list, dict(sorted(vectorize_providers_mapping.items())))\n except Exception as e:\n msg = f\"Error fetching vectorize providers: {e}\"\n raise ValueError(msg) from e\n\n @classmethod\n async def create_database_api(\n cls,\n new_database_name: str,\n cloud_provider: str,\n region: str,\n token: str,\n environment: str | None = None,\n keyspace: str | None = None,\n ):\n client = DataAPIClient(token=token, environment=environment)\n\n # Get the admin object\n admin_client = client.get_admin(token=token)\n\n # Call the create database function\n return await admin_client.async_create_database(\n name=new_database_name,\n cloud_provider=cls.map_cloud_providers()[cloud_provider][\"id\"],\n region=region,\n keyspace=keyspace,\n wait_until_active=False,\n )\n\n @classmethod\n async def create_collection_api(\n cls,\n new_collection_name: str,\n token: str,\n api_endpoint: str,\n environment: str | None = None,\n keyspace: str | None = None,\n dimension: int | None = None,\n embedding_generation_provider: str | None = None,\n embedding_generation_model: str | None = None,\n ):\n # Create the data API client\n client = DataAPIClient(token=token)\n\n # Get the database object\n database = client.get_async_database(api_endpoint=api_endpoint, token=token)\n\n # Build vectorize options, if needed\n vectorize_options = None\n if not dimension:\n vectorize_options = CollectionVectorServiceOptions(\n provider=cls.get_vectorize_providers(\n token=token, environment=environment, api_endpoint=api_endpoint\n ).get(embedding_generation_provider, [None, []])[0],\n model_name=embedding_generation_model,\n )\n\n # Create the collection\n return await database.create_collection(\n name=new_collection_name,\n keyspace=keyspace,\n dimension=dimension,\n service=vectorize_options,\n )\n\n @classmethod\n def get_database_list_static(cls, token: str, environment: str | None = None):\n client = DataAPIClient(token=token, environment=environment)\n\n # Get the admin object\n admin_client = client.get_admin(token=token)\n\n # Get the list of databases\n db_list = list(admin_client.list_databases())\n\n # Set the environment properly\n env_string = \"\"\n if environment and environment != \"prod\":\n env_string = f\"-{environment}\"\n\n # Generate the api endpoint for each database\n db_info_dict = {}\n for db in db_list:\n try:\n # Get the API endpoint for the database\n api_endpoint = f\"https://{db.info.id}-{db.info.region}.apps.astra{env_string}.datastax.com\"\n\n # Get the number of collections\n try:\n num_collections = len(\n list(\n client.get_database(\n api_endpoint=api_endpoint, token=token, keyspace=db.info.keyspace\n ).list_collection_names(keyspace=db.info.keyspace)\n )\n )\n except Exception: # noqa: BLE001\n num_collections = 0\n if db.status != \"PENDING\":\n continue\n\n # Add the database to the dictionary\n db_info_dict[db.info.name] = {\n \"api_endpoint\": api_endpoint,\n \"collections\": num_collections,\n \"status\": db.status if db.status != \"ACTIVE\" else None,\n }\n except Exception: # noqa: BLE001, S110\n pass\n\n return db_info_dict\n\n def get_database_list(self):\n return self.get_database_list_static(token=self.token, environment=self.environment)\n\n @classmethod\n def get_api_endpoint_static(\n cls,\n token: str,\n environment: str | None = None,\n api_endpoint: str | None = None,\n database_name: str | None = None,\n ):\n # If the api_endpoint is set, return it\n if api_endpoint:\n return api_endpoint\n\n # Check if the database_name is like a url\n if database_name and database_name.startswith(\"https://\"):\n return database_name\n\n # If the database is not set, nothing we can do.\n if not database_name:\n return None\n\n # Grab the database object\n db = cls.get_database_list_static(token=token, environment=environment).get(database_name)\n if not db:\n return None\n\n # Otherwise, get the URL from the database list\n return db.get(\"api_endpoint\")\n\n def get_api_endpoint(self):\n return self.get_api_endpoint_static(\n token=self.token,\n environment=self.environment,\n api_endpoint=self.api_endpoint,\n database_name=self.database_name,\n )\n\n def get_keyspace(self):\n keyspace = self.keyspace\n\n if keyspace:\n return keyspace.strip()\n\n return None\n\n def get_database_object(self, api_endpoint: str | None = None):\n try:\n client = DataAPIClient(token=self.token, environment=self.environment)\n\n return client.get_database(\n api_endpoint=api_endpoint or self.get_api_endpoint(),\n token=self.token,\n keyspace=self.get_keyspace(),\n )\n except Exception as e:\n msg = f\"Error fetching database object: {e}\"\n raise ValueError(msg) from e\n\n def collection_data(self, collection_name: str, database: Database | None = None):\n try:\n if not database:\n client = DataAPIClient(token=self.token, environment=self.environment)\n\n database = client.get_database(\n api_endpoint=self.get_api_endpoint(),\n token=self.token,\n keyspace=self.get_keyspace(),\n )\n\n collection = database.get_collection(collection_name, keyspace=self.get_keyspace())\n\n return collection.estimated_document_count()\n except Exception as e: # noqa: BLE001\n self.log(f\"Error checking collection data: {e}\")\n\n return None\n\n def _initialize_database_options(self):\n try:\n return [\n {\n \"name\": name,\n \"status\": info[\"status\"],\n \"collections\": info[\"collections\"],\n \"api_endpoint\": info[\"api_endpoint\"],\n \"icon\": \"data\",\n }\n for name, info in self.get_database_list().items()\n ]\n except Exception as e:\n msg = f\"Error fetching database options: {e}\"\n raise ValueError(msg) from e\n\n @classmethod\n def get_provider_icon(cls, collection: CollectionDescriptor | None = None, provider_name: str | None = None) -> str:\n # Get the provider name from the collection\n provider_name = provider_name or (\n collection.options.vector.service.provider\n if collection and collection.options and collection.options.vector and collection.options.vector.service\n else None\n )\n\n # If there is no provider, use the vector store icon\n if not provider_name or provider_name == \"bring your own\":\n return \"vectorstores\"\n\n # Special case for certain models\n # TODO: Add more icons\n if provider_name == \"nvidia\":\n return \"NVIDIA\"\n if provider_name == \"openai\":\n return \"OpenAI\"\n\n # Title case on the provider for the icon if no special case\n return provider_name.title()\n\n def _initialize_collection_options(self, api_endpoint: str | None = None):\n # Nothing to generate if we don't have an API endpoint yet\n api_endpoint = api_endpoint or self.get_api_endpoint()\n if not api_endpoint:\n return []\n\n # Retrieve the database object\n database = self.get_database_object(api_endpoint=api_endpoint)\n\n # Get the list of collections\n collection_list = list(database.list_collections(keyspace=self.get_keyspace()))\n\n # Return the list of collections and metadata associated\n return [\n {\n \"name\": col.name,\n \"records\": self.collection_data(collection_name=col.name, database=database),\n \"provider\": (\n col.options.vector.service.provider if col.options.vector and col.options.vector.service else None\n ),\n \"icon\": self.get_provider_icon(collection=col),\n \"model\": (\n col.options.vector.service.model_name if col.options.vector and col.options.vector.service else None\n ),\n }\n for col in collection_list\n ]\n\n def reset_provider_options(self, build_config: dict):\n # Get the list of vectorize providers\n vectorize_providers = self.get_vectorize_providers(\n token=self.token,\n environment=self.environment,\n api_endpoint=build_config[\"api_endpoint\"][\"value\"],\n )\n\n # If the collection is set, allow user to see embedding options\n build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_provider\"\n ][\"options\"] = [\"Bring your own\", \"Nvidia\", *[key for key in vectorize_providers if key != \"Nvidia\"]]\n\n # For all not Bring your own or Nvidia providers, add metadata saying configure in Astra DB Portal\n provider_options = build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_provider\"\n ][\"options\"]\n\n # Go over each possible provider and add metadata to configure in Astra DB Portal\n for provider in provider_options:\n # Skip Bring your own and Nvidia, automatically configured\n if provider in [\"Bring your own\", \"Nvidia\"]:\n build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_provider\"\n ][\"options_metadata\"].append({\"icon\": self.get_provider_icon(provider_name=provider.lower())})\n continue\n\n # Add metadata to configure in Astra DB Portal\n build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_provider\"\n ][\"options_metadata\"].append({\" \": \"Configure in Astra DB Portal\"})\n\n # And allow the user to see the models based on a selected provider\n embedding_provider = build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_provider\"\n ][\"value\"]\n\n # Set the options for the embedding model based on the provider\n build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_model\"\n ][\"options\"] = vectorize_providers.get(embedding_provider, [[], []])[1]\n\n return build_config\n\n def reset_collection_list(self, build_config: dict):\n # Get the list of options we have based on the token provided\n collection_options = self._initialize_collection_options(api_endpoint=build_config[\"api_endpoint\"][\"value\"])\n\n # If we retrieved options based on the token, show the dropdown\n build_config[\"collection_name\"][\"options\"] = [col[\"name\"] for col in collection_options]\n build_config[\"collection_name\"][\"options_metadata\"] = [\n {k: v for k, v in col.items() if k not in [\"name\"]} for col in collection_options\n ]\n\n # Reset the selected collection\n if build_config[\"collection_name\"][\"value\"] not in build_config[\"collection_name\"][\"options\"]:\n build_config[\"collection_name\"][\"value\"] = \"\"\n\n # If we have a database, collection name should not be advanced\n build_config[\"collection_name\"][\"advanced\"] = not build_config[\"database_name\"][\"value\"]\n\n return build_config\n\n def reset_database_list(self, build_config: dict):\n # Get the list of options we have based on the token provided\n database_options = self._initialize_database_options()\n\n # If we retrieved options based on the token, show the dropdown\n build_config[\"database_name\"][\"options\"] = [db[\"name\"] for db in database_options]\n build_config[\"database_name\"][\"options_metadata\"] = [\n {k: v for k, v in db.items() if k not in [\"name\"]} for db in database_options\n ]\n\n # Reset the selected database\n if build_config[\"database_name\"][\"value\"] not in build_config[\"database_name\"][\"options\"]:\n build_config[\"database_name\"][\"value\"] = \"\"\n build_config[\"api_endpoint\"][\"value\"] = \"\"\n build_config[\"collection_name\"][\"advanced\"] = True\n\n # If we have a token, database name should not be advanced\n build_config[\"database_name\"][\"advanced\"] = not build_config[\"token\"][\"value\"]\n\n return build_config\n\n def reset_build_config(self, build_config: dict):\n # Reset the list of databases we have based on the token provided\n build_config[\"database_name\"][\"options\"] = []\n build_config[\"database_name\"][\"options_metadata\"] = []\n build_config[\"database_name\"][\"value\"] = \"\"\n build_config[\"database_name\"][\"advanced\"] = True\n build_config[\"api_endpoint\"][\"value\"] = \"\"\n\n # Reset the list of collections and metadata associated\n build_config[\"collection_name\"][\"options\"] = []\n build_config[\"collection_name\"][\"options_metadata\"] = []\n build_config[\"collection_name\"][\"value\"] = \"\"\n build_config[\"collection_name\"][\"advanced\"] = True\n\n return build_config\n\n async def update_build_config(self, build_config: dict, field_value: str, field_name: str | None = None):\n # Callback for database creation\n if field_name == \"database_name\" and isinstance(field_value, dict) and \"new_database_name\" in field_value:\n try:\n await self.create_database_api(\n new_database_name=field_value[\"new_database_name\"],\n token=self.token,\n keyspace=self.get_keyspace(),\n environment=self.environment,\n cloud_provider=field_value[\"cloud_provider\"],\n region=field_value[\"region\"],\n )\n except Exception as e:\n msg = f\"Error creating database: {e}\"\n raise ValueError(msg) from e\n\n # Add the new database to the list of options\n build_config[\"database_name\"][\"options\"] = build_config[\"database_name\"][\"options\"] + [\n field_value[\"new_database_name\"]\n ]\n build_config[\"database_name\"][\"options_metadata\"] = build_config[\"database_name\"][\"options_metadata\"] + [\n {\"status\": \"PENDING\"}\n ]\n\n return self.reset_collection_list(build_config)\n\n # This is the callback required to update the list of regions for a cloud provider\n if field_name == \"database_name\" and isinstance(field_value, dict) and \"new_database_name\" not in field_value:\n cloud_provider = field_value[\"cloud_provider\"]\n build_config[\"database_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\"region\"][\n \"options\"\n ] = self.map_cloud_providers()[cloud_provider][\"regions\"]\n\n return build_config\n\n # Callback for the creation of collections\n if field_name == \"collection_name\" and isinstance(field_value, dict) and \"new_collection_name\" in field_value:\n try:\n # Get the dimension if its a BYO provider\n dimension = (\n field_value[\"dimension\"]\n if field_value[\"embedding_generation_provider\"] == \"Bring your own\"\n else None\n )\n\n # Create the collection\n await self.create_collection_api(\n new_collection_name=field_value[\"new_collection_name\"],\n token=self.token,\n api_endpoint=build_config[\"api_endpoint\"][\"value\"],\n environment=self.environment,\n keyspace=self.get_keyspace(),\n dimension=dimension,\n embedding_generation_provider=field_value[\"embedding_generation_provider\"],\n embedding_generation_model=field_value[\"embedding_generation_model\"],\n )\n except Exception as e:\n msg = f\"Error creating collection: {e}\"\n raise ValueError(msg) from e\n\n # Add the new collection to the list of options\n build_config[\"collection_name\"][\"value\"] = field_value[\"new_collection_name\"]\n build_config[\"collection_name\"][\"options\"].append(field_value[\"new_collection_name\"])\n\n # Get the provider and model for the new collection\n generation_provider = field_value[\"embedding_generation_provider\"]\n provider = generation_provider if generation_provider != \"Bring your own\" else None\n generation_model = field_value[\"embedding_generation_model\"]\n model = generation_model if generation_model else None\n\n # Add the new collection to the list of options\n icon = \"NVIDIA\" if provider == \"Nvidia\" else \"vectorstores\"\n build_config[\"collection_name\"][\"options_metadata\"] = build_config[\"collection_name\"][\n \"options_metadata\"\n ] + [{\"records\": 0, \"provider\": provider, \"icon\": icon, \"model\": model}]\n\n return build_config\n\n # Callback to update the model list based on the embedding provider\n if (\n field_name == \"collection_name\"\n and isinstance(field_value, dict)\n and \"new_collection_name\" not in field_value\n ):\n return self.reset_provider_options(build_config)\n\n # When the component first executes, this is the update refresh call\n first_run = field_name == \"collection_name\" and not field_value and not build_config[\"database_name\"][\"options\"]\n\n # If the token has not been provided, simply return the empty build config\n if not self.token:\n return self.reset_build_config(build_config)\n\n # If this is the first execution of the component, reset and build database list\n if first_run or field_name in [\"token\", \"environment\"]:\n return self.reset_database_list(build_config)\n\n # Refresh the collection name options\n if field_name == \"database_name\" and not isinstance(field_value, dict):\n # If missing, refresh the database options\n if field_value not in build_config[\"database_name\"][\"options\"]:\n build_config = await self.update_build_config(build_config, field_value=self.token, field_name=\"token\")\n build_config[\"database_name\"][\"value\"] = \"\"\n else:\n # Find the position of the selected database to align with metadata\n index_of_name = build_config[\"database_name\"][\"options\"].index(field_value)\n\n # Initializing database condition\n pending = build_config[\"database_name\"][\"options_metadata\"][index_of_name][\"status\"] == \"PENDING\"\n if pending:\n return self.update_build_config(build_config, field_value=self.token, field_name=\"token\")\n\n # Set the API endpoint based on the selected database\n build_config[\"api_endpoint\"][\"value\"] = build_config[\"database_name\"][\"options_metadata\"][\n index_of_name\n ][\"api_endpoint\"]\n\n # Reset the provider options\n build_config = self.reset_provider_options(build_config)\n\n # Reset the list of collections we have based on the token provided\n return self.reset_collection_list(build_config)\n\n # Hide embedding model option if opriona_metadata provider is not null\n if field_name == \"collection_name\" and not isinstance(field_value, dict):\n # Assume we will be autodetecting the collection:\n build_config[\"autodetect_collection\"][\"value\"] = True\n\n # Reload the collection list\n build_config = self.reset_collection_list(build_config)\n\n # Set the options for collection name to be the field value if its a new collection\n if field_value and field_value not in build_config[\"collection_name\"][\"options\"]:\n # Add the new collection to the list of options\n build_config[\"collection_name\"][\"options\"].append(field_value)\n build_config[\"collection_name\"][\"options_metadata\"].append(\n {\"records\": 0, \"provider\": None, \"icon\": \"\", \"model\": None}\n )\n\n # Ensure that autodetect collection is set to False, since its a new collection\n build_config[\"autodetect_collection\"][\"value\"] = False\n\n # Find the position of the selected collection to align with metadata\n index_of_name = build_config[\"collection_name\"][\"options\"].index(field_value)\n value_of_provider = build_config[\"collection_name\"][\"options_metadata\"][index_of_name][\"provider\"]\n\n # If we were able to determine the Vectorize provider, set it accordingly\n if value_of_provider:\n build_config[\"embedding_model\"][\"advanced\"] = True\n build_config[\"embedding_choice\"][\"value\"] = \"Astra Vectorize\"\n else:\n build_config[\"embedding_model\"][\"advanced\"] = False\n build_config[\"embedding_choice\"][\"value\"] = \"Embedding Model\"\n\n return build_config\n\n return build_config\n\n @check_cached_vector_store\n def build_vector_store(self):\n try:\n from langchain_astradb import AstraDBVectorStore\n except ImportError as e:\n msg = (\n \"Could not import langchain Astra DB integration package. \"\n \"Please install it with `pip install langchain-astradb`.\"\n )\n raise ImportError(msg) from e\n\n # Get the embedding model and additional params\n embedding_params = (\n {\"embedding\": self.embedding_model}\n if self.embedding_model and self.embedding_choice == \"Embedding Model\"\n else {}\n )\n\n # Get the additional parameters\n additional_params = self.astradb_vectorstore_kwargs or {}\n\n # Get Langflow version and platform information\n __version__ = get_version_info()[\"version\"]\n langflow_prefix = \"\"\n # if os.getenv(\"AWS_EXECUTION_ENV\") == \"AWS_ECS_FARGATE\": # TODO: More precise way of detecting\n # langflow_prefix = \"ds-\"\n\n # Get the database object\n database = self.get_database_object()\n autodetect = self.collection_name in database.list_collection_names() and self.autodetect_collection\n\n # Bundle up the auto-detect parameters\n autodetect_params = {\n \"autodetect_collection\": autodetect,\n \"content_field\": (\n self.content_field\n if self.content_field and embedding_params\n else (\n \"page_content\"\n if embedding_params\n and self.collection_data(collection_name=self.collection_name, database=database) == 0\n else None\n )\n ),\n \"ignore_invalid_documents\": self.ignore_invalid_documents,\n }\n\n # Attempt to build the Vector Store object\n try:\n vector_store = AstraDBVectorStore(\n # Astra DB Authentication Parameters\n token=self.token,\n api_endpoint=database.api_endpoint,\n namespace=database.keyspace,\n collection_name=self.collection_name,\n environment=self.environment,\n # Astra DB Usage Tracking Parameters\n ext_callers=[(f\"{langflow_prefix}langflow\", __version__)],\n # Astra DB Vector Store Parameters\n **autodetect_params,\n **embedding_params,\n **additional_params,\n )\n except Exception as e:\n msg = f\"Error initializing AstraDBVectorStore: {e}\"\n raise ValueError(msg) from e\n\n # Add documents to the vector store\n self._add_documents_to_vector_store(vector_store)\n\n return vector_store\n\n def _add_documents_to_vector_store(self, vector_store) -> None:\n documents = []\n for _input in self.ingest_data or []:\n if isinstance(_input, Data):\n documents.append(_input.to_lc_document())\n else:\n msg = \"Vector Store Inputs must be Data objects.\"\n raise TypeError(msg)\n\n if documents and self.deletion_field:\n self.log(f\"Deleting documents where {self.deletion_field}\")\n try:\n database = self.get_database_object()\n collection = database.get_collection(self.collection_name, keyspace=database.keyspace)\n delete_values = list({doc.metadata[self.deletion_field] for doc in documents})\n self.log(f\"Deleting documents where {self.deletion_field} matches {delete_values}.\")\n collection.delete_many({f\"metadata.{self.deletion_field}\": {\"$in\": delete_values}})\n except Exception as e:\n msg = f\"Error deleting documents from AstraDBVectorStore based on '{self.deletion_field}': {e}\"\n raise ValueError(msg) from e\n\n if documents:\n self.log(f\"Adding {len(documents)} documents to the Vector Store.\")\n try:\n vector_store.add_documents(documents)\n except Exception as e:\n msg = f\"Error adding documents to AstraDBVectorStore: {e}\"\n raise ValueError(msg) from e\n else:\n self.log(\"No documents to add to the Vector Store.\")\n\n def _map_search_type(self) -> str:\n search_type_mapping = {\n \"Similarity with score threshold\": \"similarity_score_threshold\",\n \"MMR (Max Marginal Relevance)\": \"mmr\",\n }\n\n return search_type_mapping.get(self.search_type, \"similarity\")\n\n def _build_search_args(self):\n query = self.search_query if isinstance(self.search_query, str) and self.search_query.strip() else None\n\n if query:\n args = {\n \"query\": query,\n \"search_type\": self._map_search_type(),\n \"k\": self.number_of_results,\n \"score_threshold\": self.search_score_threshold,\n }\n elif self.advanced_search_filter:\n args = {\n \"n\": self.number_of_results,\n }\n else:\n return {}\n\n filter_arg = self.advanced_search_filter or {}\n if filter_arg:\n args[\"filter\"] = filter_arg\n\n return args\n\n def search_documents(self, vector_store=None) -> list[Data]:\n vector_store = vector_store or self.build_vector_store()\n\n self.log(f\"Search input: {self.search_query}\")\n self.log(f\"Search type: {self.search_type}\")\n self.log(f\"Number of results: {self.number_of_results}\")\n\n try:\n search_args = self._build_search_args()\n except Exception as e:\n msg = f\"Error in AstraDBVectorStore._build_search_args: {e}\"\n raise ValueError(msg) from e\n\n if not search_args:\n self.log(\"No search input or filters provided. Skipping search.\")\n return []\n\n docs = []\n search_method = \"search\" if \"query\" in search_args else \"metadata_search\"\n\n try:\n self.log(f\"Calling vector_store.{search_method} with args: {search_args}\")\n docs = getattr(vector_store, search_method)(**search_args)\n except Exception as e:\n msg = f\"Error performing {search_method} in AstraDBVectorStore: {e}\"\n raise ValueError(msg) from e\n\n self.log(f\"Retrieved documents: {len(docs)}\")\n\n data = docs_to_data(docs)\n self.log(f\"Converted documents to data: {len(data)}\")\n self.status = data\n\n return data\n\n def get_retriever_kwargs(self):\n search_args = self._build_search_args()\n\n return {\n \"search_type\": self._map_search_type(),\n \"search_kwargs\": search_args,\n }\n"
},
"collection_name": {
"_input_type": "DropdownInput",
- "advanced": false,
+ "advanced": true,
"combobox": true,
- "dialog_inputs": {},
+ "dialog_inputs": {
+ "fields": {
+ "data": {
+ "node": {
+ "description": "",
+ "display_name": "Create new collection",
+ "field_order": [
+ "new_collection_name",
+ "embedding_generation_provider",
+ "embedding_generation_model"
+ ],
+ "name": "create_collection",
+ "template": {
+ "dimension": {
+ "_input_type": "IntInput",
+ "advanced": false,
+ "display_name": "Dimensions",
+ "dynamic": false,
+ "info": "Dimension of the embeddings to generate.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "dimension",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 1024
+ },
+ "embedding_generation_model": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Embedding model",
+ "dynamic": false,
+ "info": "Model to use for generating embeddings.",
+ "name": "embedding_generation_model",
+ "options": [
+ "Bring your own",
+ "NV-Embed-QA"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "embedding_generation_provider": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Embedding generation method",
+ "dynamic": false,
+ "info": "Provider to use for generating embeddings.",
+ "name": "embedding_generation_provider",
+ "options": [
+ "Bring your own",
+ "Nvidia"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "real_time_refresh": true,
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "new_collection_name": {
+ "_input_type": "StrInput",
+ "advanced": false,
+ "display_name": "Name",
+ "dynamic": false,
+ "info": "Name of the new collection to create in Astra DB.",
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "new_collection_name",
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ }
+ }
+ }
+ },
+ "functionality": "create"
+ },
"display_name": "Collection",
"dynamic": false,
"info": "The name of the collection within Astra DB where the vectors will be stored.",
@@ -3385,18 +3307,107 @@
"type": "str",
"value": ""
},
- "d_api_endpoint": {
- "_input_type": "StrInput",
- "advanced": true,
- "display_name": "Database API Endpoint",
+ "database_name": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": true,
+ "dialog_inputs": {
+ "fields": {
+ "data": {
+ "node": {
+ "description": "",
+ "display_name": "Create new database",
+ "field_order": [
+ "new_database_name",
+ "cloud_provider",
+ "region"
+ ],
+ "name": "create_database",
+ "template": {
+ "cloud_provider": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Cloud provider",
+ "dynamic": false,
+ "info": "Cloud provider for the new database.",
+ "name": "cloud_provider",
+ "options": [
+ "Amazon Web Services",
+ "Google Cloud Platform",
+ "Microsoft Azure"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "real_time_refresh": true,
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "new_database_name": {
+ "_input_type": "StrInput",
+ "advanced": false,
+ "display_name": "Name",
+ "dynamic": false,
+ "info": "Name of the new database to create in Astra DB.",
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "new_database_name",
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "region": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Region",
+ "dynamic": false,
+ "info": "Region for the new database.",
+ "name": "region",
+ "options": [
+ "us-east-2",
+ "ap-south-1",
+ "eu-west-1"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ }
+ }
+ }
+ },
+ "functionality": "create"
+ },
+ "display_name": "Database",
"dynamic": false,
- "info": "The API Endpoint for the Astra DB instance. Supercedes database selection.",
- "list": false,
- "list_add_label": "Add More",
- "load_from_db": false,
- "name": "d_api_endpoint",
+ "info": "The Database name for the Astra DB instance.",
+ "name": "database_name",
+ "options": [],
+ "options_metadata": [],
"placeholder": "",
- "required": false,
+ "real_time_refresh": true,
+ "refresh_button": true,
+ "required": true,
"show": true,
"title_case": false,
"tool_mode": false,
@@ -3432,10 +3443,7 @@
"dynamic": false,
"info": "Choose an embedding model or use Astra Vectorize.",
"name": "embedding_choice",
- "options": [
- "Embedding Model",
- "Astra Vectorize"
- ],
+ "options": ["Embedding Model", "Astra Vectorize"],
"options_metadata": [],
"placeholder": "",
"real_time_refresh": true,
@@ -3453,9 +3461,7 @@
"display_name": "Embedding Model",
"dynamic": false,
"info": "Specify the Embedding Model. Not required for Astra Vectorize collections.",
- "input_types": [
- "Embeddings"
- ],
+ "input_types": ["Embeddings"],
"list": false,
"list_add_label": "Add More",
"name": "embedding_model",
@@ -3478,6 +3484,7 @@
"load_from_db": false,
"name": "environment",
"placeholder": "",
+ "real_time_refresh": true,
"required": false,
"show": true,
"title_case": false,
@@ -3510,9 +3517,7 @@
"display_name": "Ingest Data",
"dynamic": false,
"info": "",
- "input_types": [
- "Data"
- ],
+ "input_types": ["Data"],
"list": false,
"list_add_label": "Add More",
"name": "ingest_data",
@@ -3569,9 +3574,7 @@
"display_name": "Search Query",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -3645,7 +3648,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "ASTRA_DB_APPLICATION_TOKEN"
}
},
"tool_mode": false
@@ -3654,26 +3657,23 @@
"type": "AstraDB"
},
"dragging": false,
- "id": "AstraDB-Qdaes",
+ "id": "AstraDB-HXAXh",
"measured": {
- "height": 611,
+ "height": 532,
"width": 320
},
"position": {
- "x": 1221.7808624943825,
- "y": 598.7224891255499
+ "x": 1213.4353517134307,
+ "y": 631.4125346711122
},
"selected": false,
"type": "genericNode"
},
{
"data": {
- "id": "AstraDB-sPWXd",
+ "id": "AstraDB-nMlxo",
"node": {
- "base_classes": [
- "Data",
- "DataFrame"
- ],
+ "base_classes": ["Data", "DataFrame"],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
@@ -3684,6 +3684,7 @@
"field_order": [
"token",
"environment",
+ "database_name",
"api_endpoint",
"collection_name",
"keyspace",
@@ -3695,6 +3696,7 @@
"search_type",
"search_score_threshold",
"advanced_search_filter",
+ "autodetect_collection",
"content_field",
"deletion_field",
"ignore_invalid_documents",
@@ -3714,15 +3716,13 @@
"method": "search_documents",
"name": "search_results",
"required_inputs": [
- "api_endpoint",
"collection_name",
+ "database_name",
"token"
],
"selected": "Data",
"tool_mode": true,
- "types": [
- "Data"
- ],
+ "types": ["Data"],
"value": "__UNDEFINED__"
},
{
@@ -3734,9 +3734,7 @@
"required_inputs": [],
"selected": "DataFrame",
"tool_mode": true,
- "types": [
- "DataFrame"
- ],
+ "types": ["DataFrame"],
"value": "__UNDEFINED__"
}
],
@@ -3763,20 +3761,17 @@
"value": {}
},
"api_endpoint": {
- "_input_type": "DropdownInput",
- "advanced": false,
- "combobox": true,
- "dialog_inputs": {},
- "display_name": "Database",
+ "_input_type": "StrInput",
+ "advanced": true,
+ "display_name": "Astra DB API Endpoint",
"dynamic": false,
- "info": "The Database / API Endpoint for the Astra DB instance.",
- "name": "Database",
- "options": [],
- "options_metadata": [],
+ "info": "The API Endpoint for the Astra DB instance. Supercedes database selection.",
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "api_endpoint",
"placeholder": "",
- "real_time_refresh": true,
- "refresh_button": true,
- "required": true,
+ "required": false,
"show": true,
"title_case": false,
"tool_mode": false,
@@ -3837,13 +3832,115 @@
"show": true,
"title_case": false,
"type": "code",
- "value": "import os\nfrom collections import defaultdict\nfrom dataclasses import dataclass, field\n\nfrom astrapy import AstraDBAdmin, DataAPIClient, Database\nfrom langchain_astradb import AstraDBVectorStore, CollectionVectorServiceOptions\n\nfrom langflow.base.vectorstores.model import LCVectorStoreComponent, check_cached_vector_store\nfrom langflow.helpers import docs_to_data\nfrom langflow.inputs import FloatInput, NestedDictInput\nfrom langflow.io import (\n BoolInput,\n DropdownInput,\n HandleInput,\n IntInput,\n SecretStrInput,\n StrInput,\n)\nfrom langflow.schema import Data\nfrom langflow.utils.version import get_version_info\n\n\nclass AstraDBVectorStoreComponent(LCVectorStoreComponent):\n display_name: str = \"Astra DB\"\n description: str = \"Ingest and search documents in Astra DB\"\n documentation: str = \"https://docs.datastax.com/en/langflow/astra-components.html\"\n name = \"AstraDB\"\n icon: str = \"AstraDB\"\n\n _cached_vector_store: AstraDBVectorStore | None = None\n\n @dataclass\n class NewDatabaseInput:\n functionality: str = \"create\"\n fields: dict[str, dict] = field(\n default_factory=lambda: {\n \"data\": {\n \"node\": {\n \"description\": \"Create a new database in Astra DB.\",\n \"display_name\": \"Create New Database\",\n \"field_order\": [\"new_database_name\", \"cloud_provider\", \"region\"],\n \"template\": {\n \"new_database_name\": StrInput(\n name=\"new_database_name\",\n display_name=\"New Database Name\",\n info=\"Name of the new database to create in Astra DB.\",\n required=True,\n ),\n \"cloud_provider\": DropdownInput(\n name=\"cloud_provider\",\n display_name=\"Cloud Provider\",\n info=\"Cloud provider for the new database.\",\n options=[\"Amazon Web Services\", \"Google Cloud Platform\", \"Microsoft Azure\"],\n required=True,\n ),\n \"region\": DropdownInput(\n name=\"region\",\n display_name=\"Region\",\n info=\"Region for the new database.\",\n options=[],\n required=True,\n ),\n },\n },\n }\n }\n )\n\n @dataclass\n class NewCollectionInput:\n functionality: str = \"create\"\n fields: dict[str, dict] = field(\n default_factory=lambda: {\n \"data\": {\n \"node\": {\n \"description\": \"Create a new collection in Astra DB.\",\n \"display_name\": \"Create New Collection\",\n \"field_order\": [\n \"new_collection_name\",\n \"embedding_generation_provider\",\n \"embedding_generation_model\",\n ],\n \"template\": {\n \"new_collection_name\": StrInput(\n name=\"new_collection_name\",\n display_name=\"New Collection Name\",\n info=\"Name of the new collection to create in Astra DB.\",\n required=True,\n ),\n \"embedding_generation_provider\": DropdownInput(\n name=\"embedding_generation_provider\",\n display_name=\"Embedding Generation Provider\",\n info=\"Provider to use for generating embeddings.\",\n options=[],\n required=True,\n ),\n \"embedding_generation_model\": DropdownInput(\n name=\"embedding_generation_model\",\n display_name=\"Embedding Generation Model\",\n info=\"Model to use for generating embeddings.\",\n options=[],\n required=True,\n ),\n },\n },\n }\n }\n )\n\n inputs = [\n SecretStrInput(\n name=\"token\",\n display_name=\"Astra DB Application Token\",\n info=\"Authentication token for accessing Astra DB.\",\n value=\"ASTRA_DB_APPLICATION_TOKEN\",\n required=True,\n real_time_refresh=True,\n input_types=[],\n ),\n StrInput(\n name=\"environment\",\n display_name=\"Environment\",\n info=\"The environment for the Astra DB API Endpoint.\",\n advanced=True,\n real_time_refresh=True,\n ),\n DropdownInput(\n name=\"api_endpoint\",\n display_name=\"Database\",\n info=\"The Database / API Endpoint for the Astra DB instance.\",\n required=True,\n refresh_button=True,\n real_time_refresh=True,\n combobox=True,\n ),\n StrInput(\n name=\"d_api_endpoint\",\n display_name=\"Database API Endpoint\",\n info=\"The API Endpoint for the Astra DB instance. Supercedes database selection.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"collection_name\",\n display_name=\"Collection\",\n info=\"The name of the collection within Astra DB where the vectors will be stored.\",\n required=True,\n refresh_button=True,\n real_time_refresh=True,\n # dialog_inputs=asdict(NewCollectionInput()),\n combobox=True,\n ),\n StrInput(\n name=\"keyspace\",\n display_name=\"Keyspace\",\n info=\"Optional keyspace within Astra DB to use for the collection.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"embedding_choice\",\n display_name=\"Embedding Model or Astra Vectorize\",\n info=\"Choose an embedding model or use Astra Vectorize.\",\n options=[\"Embedding Model\", \"Astra Vectorize\"],\n value=\"Embedding Model\",\n advanced=True,\n real_time_refresh=True,\n ),\n HandleInput(\n name=\"embedding_model\",\n display_name=\"Embedding Model\",\n input_types=[\"Embeddings\"],\n info=\"Specify the Embedding Model. Not required for Astra Vectorize collections.\",\n required=False,\n ),\n *LCVectorStoreComponent.inputs,\n IntInput(\n name=\"number_of_results\",\n display_name=\"Number of Search Results\",\n info=\"Number of search results to return.\",\n advanced=True,\n value=4,\n ),\n DropdownInput(\n name=\"search_type\",\n display_name=\"Search Type\",\n info=\"Search type to use\",\n options=[\"Similarity\", \"Similarity with score threshold\", \"MMR (Max Marginal Relevance)\"],\n value=\"Similarity\",\n advanced=True,\n ),\n FloatInput(\n name=\"search_score_threshold\",\n display_name=\"Search Score Threshold\",\n info=\"Minimum similarity score threshold for search results. \"\n \"(when using 'Similarity with score threshold')\",\n value=0,\n advanced=True,\n ),\n NestedDictInput(\n name=\"advanced_search_filter\",\n display_name=\"Search Metadata Filter\",\n info=\"Optional dictionary of filters to apply to the search query.\",\n advanced=True,\n ),\n BoolInput(\n name=\"autodetect_collection\",\n display_name=\"Autodetect Collection\",\n info=\"Boolean flag to determine whether to autodetect the collection.\",\n advanced=True,\n value=True,\n ),\n StrInput(\n name=\"content_field\",\n display_name=\"Content Field\",\n info=\"Field to use as the text content field for the vector store.\",\n advanced=True,\n ),\n StrInput(\n name=\"deletion_field\",\n display_name=\"Deletion Based On Field\",\n info=\"When this parameter is provided, documents in the target collection with \"\n \"metadata field values matching the input metadata field value will be deleted \"\n \"before new data is loaded.\",\n advanced=True,\n ),\n BoolInput(\n name=\"ignore_invalid_documents\",\n display_name=\"Ignore Invalid Documents\",\n info=\"Boolean flag to determine whether to ignore invalid documents at runtime.\",\n advanced=True,\n ),\n NestedDictInput(\n name=\"astradb_vectorstore_kwargs\",\n display_name=\"AstraDBVectorStore Parameters\",\n info=\"Optional dictionary of additional parameters for the AstraDBVectorStore.\",\n advanced=True,\n ),\n ]\n\n @classmethod\n def map_cloud_providers(cls):\n return {\n \"Amazon Web Services\": {\n \"id\": \"aws\",\n \"regions\": [\"us-east-2\", \"ap-south-1\", \"eu-west-1\"],\n },\n \"Google Cloud Platform\": {\n \"id\": \"gcp\",\n \"regions\": [\"us-east1\"],\n },\n \"Microsoft Azure\": {\n \"id\": \"azure\",\n \"regions\": [\"westus3\"],\n },\n }\n\n @classmethod\n def create_database_api(\n cls,\n token: str,\n new_database_name: str,\n cloud_provider: str,\n region: str,\n ):\n client = DataAPIClient(token=token)\n\n # Get the admin object\n admin_client = client.get_admin(token=token)\n\n # Call the create database function\n return admin_client.create_database(\n name=new_database_name,\n cloud_provider=cloud_provider,\n region=region,\n )\n\n @classmethod\n def create_collection_api(\n cls,\n token: str,\n database_name: str,\n new_collection_name: str,\n dimension: int | None = None,\n embedding_generation_provider: str | None = None,\n embedding_generation_model: str | None = None,\n ):\n client = DataAPIClient(token=token)\n api_endpoint = cls.get_api_endpoint_static(token=token, database_name=database_name)\n\n # Get the database object\n database = client.get_database(api_endpoint=api_endpoint, token=token)\n\n # Build vectorize options, if needed\n vectorize_options = None\n if not dimension:\n vectorize_options = CollectionVectorServiceOptions(\n provider=embedding_generation_provider,\n model_name=embedding_generation_model,\n authentication=None,\n parameters=None,\n )\n\n # Create the collection\n return database.create_collection(\n name=new_collection_name,\n dimension=dimension,\n service=vectorize_options,\n )\n\n @classmethod\n def get_database_list_static(cls, token: str, environment: str | None = None):\n client = DataAPIClient(token=token, environment=environment)\n\n # Get the admin object\n admin_client = client.get_admin(token=token)\n\n # Get the list of databases\n db_list = list(admin_client.list_databases())\n\n # Set the environment properly\n env_string = \"\"\n if environment and environment != \"prod\":\n env_string = f\"-{environment}\"\n\n # Generate the api endpoint for each database\n db_info_dict = {}\n for db in db_list:\n try:\n api_endpoint = f\"https://{db.info.id}-{db.info.region}.apps.astra{env_string}.datastax.com\"\n db_info_dict[db.info.name] = {\n \"api_endpoint\": api_endpoint,\n \"collections\": len(\n list(\n client.get_database(\n api_endpoint=api_endpoint, token=token, keyspace=db.info.keyspace\n ).list_collection_names(keyspace=db.info.keyspace)\n )\n ),\n }\n except Exception: # noqa: BLE001, S110\n pass\n\n return db_info_dict\n\n def get_database_list(self):\n return self.get_database_list_static(token=self.token, environment=self.environment)\n\n @classmethod\n def get_api_endpoint_static(\n cls,\n token: str,\n environment: str | None = None,\n api_endpoint: str | None = None,\n database_name: str | None = None,\n ):\n # If the api_endpoint is set, return it\n if api_endpoint:\n return api_endpoint\n\n # Check if the database_name is like a url\n if database_name and database_name.startswith(\"https://\"):\n return database_name\n\n # If the database is not set, nothing we can do.\n if not database_name:\n return None\n\n # Otherwise, get the URL from the database list\n return cls.get_database_list_static(token=token, environment=environment).get(database_name).get(\"api_endpoint\")\n\n def get_api_endpoint(self, *, api_endpoint: str | None = None):\n return self.get_api_endpoint_static(\n token=self.token,\n environment=self.environment,\n api_endpoint=api_endpoint or self.d_api_endpoint,\n database_name=self.api_endpoint,\n )\n\n def get_keyspace(self):\n keyspace = self.keyspace\n\n if keyspace:\n return keyspace.strip()\n\n return None\n\n def get_database_object(self, api_endpoint: str | None = None):\n try:\n client = DataAPIClient(token=self.token, environment=self.environment)\n\n return client.get_database(\n api_endpoint=self.get_api_endpoint(api_endpoint=api_endpoint),\n token=self.token,\n keyspace=self.get_keyspace(),\n )\n except Exception as e:\n msg = f\"Error fetching database object: {e}\"\n raise ValueError(msg) from e\n\n def collection_data(self, collection_name: str, database: Database | None = None):\n try:\n if not database:\n client = DataAPIClient(token=self.token, environment=self.environment)\n\n database = client.get_database(\n api_endpoint=self.get_api_endpoint(),\n token=self.token,\n keyspace=self.get_keyspace(),\n )\n\n collection = database.get_collection(collection_name, keyspace=self.get_keyspace())\n\n return collection.estimated_document_count()\n except Exception as e: # noqa: BLE001\n self.log(f\"Error checking collection data: {e}\")\n\n return None\n\n def get_vectorize_providers(self):\n try:\n self.log(\"Dynamically updating list of Vectorize providers.\")\n\n # Get the admin object\n admin = AstraDBAdmin(token=self.token)\n db_admin = admin.get_database_admin(api_endpoint=self.get_api_endpoint())\n\n # Get the list of embedding providers\n embedding_providers = db_admin.find_embedding_providers().as_dict()\n\n vectorize_providers_mapping = {}\n # Map the provider display name to the provider key and models\n for provider_key, provider_data in embedding_providers[\"embeddingProviders\"].items():\n display_name = provider_data[\"displayName\"]\n models = [model[\"name\"] for model in provider_data[\"models\"]]\n\n # TODO: https://astra.datastax.com/api/v2/graphql\n vectorize_providers_mapping[display_name] = [provider_key, models]\n\n # Sort the resulting dictionary\n return defaultdict(list, dict(sorted(vectorize_providers_mapping.items())))\n except Exception as e: # noqa: BLE001\n self.log(f\"Error fetching Vectorize providers: {e}\")\n\n return {}\n\n def _initialize_database_options(self):\n try:\n return [\n {\n \"name\": name,\n \"collections\": info[\"collections\"],\n \"api_endpoint\": info[\"api_endpoint\"],\n }\n for name, info in self.get_database_list().items()\n ]\n except Exception as e:\n msg = f\"Error fetching database options: {e}\"\n raise ValueError(msg) from e\n\n def _initialize_collection_options(self, api_endpoint: str | None = None):\n # Retrieve the database object\n database = self.get_database_object(api_endpoint=api_endpoint)\n\n # Get the list of collections\n collection_list = list(database.list_collections(keyspace=self.get_keyspace()))\n\n # Return the list of collections and metadata associated\n return [\n {\n \"name\": col.name,\n \"records\": self.collection_data(collection_name=col.name, database=database),\n \"provider\": (\n col.options.vector.service.provider if col.options.vector and col.options.vector.service else None\n ),\n \"icon\": \"\",\n \"model\": (\n col.options.vector.service.model_name if col.options.vector and col.options.vector.service else None\n ),\n }\n for col in collection_list\n ]\n\n def reset_collection_list(self, build_config: dict):\n # Get the list of options we have based on the token provided\n collection_options = self._initialize_collection_options()\n\n # If we retrieved options based on the token, show the dropdown\n build_config[\"collection_name\"][\"options\"] = [col[\"name\"] for col in collection_options]\n build_config[\"collection_name\"][\"options_metadata\"] = [\n {k: v for k, v in col.items() if k not in [\"name\"]} for col in collection_options\n ]\n\n # Reset the selected collection\n build_config[\"collection_name\"][\"value\"] = \"\"\n\n return build_config\n\n def reset_database_list(self, build_config: dict):\n # Get the list of options we have based on the token provided\n database_options = self._initialize_database_options()\n\n # If we retrieved options based on the token, show the dropdown\n build_config[\"api_endpoint\"][\"options\"] = [db[\"name\"] for db in database_options]\n build_config[\"api_endpoint\"][\"options_metadata\"] = [\n {k: v for k, v in db.items() if k not in [\"name\"]} for db in database_options\n ]\n\n # Reset the selected database\n build_config[\"api_endpoint\"][\"value\"] = \"\"\n\n return build_config\n\n def reset_build_config(self, build_config: dict):\n # Reset the list of databases we have based on the token provided\n build_config[\"api_endpoint\"][\"options\"] = []\n build_config[\"api_endpoint\"][\"options_metadata\"] = []\n build_config[\"api_endpoint\"][\"value\"] = \"\"\n build_config[\"api_endpoint\"][\"name\"] = \"Database\"\n\n # Reset the list of collections and metadata associated\n build_config[\"collection_name\"][\"options\"] = []\n build_config[\"collection_name\"][\"options_metadata\"] = []\n build_config[\"collection_name\"][\"value\"] = \"\"\n\n return build_config\n\n def update_build_config(self, build_config: dict, field_value: str, field_name: str | None = None):\n # When the component first executes, this is the update refresh call\n first_run = field_name == \"collection_name\" and not field_value and not build_config[\"api_endpoint\"][\"options\"]\n\n # If the token has not been provided, simply return\n if not self.token:\n return self.reset_build_config(build_config)\n\n # If this is the first execution of the component, reset and build database list\n if first_run or field_name in [\"token\", \"environment\"]:\n # Reset the build config to ensure we are starting fresh\n build_config = self.reset_build_config(build_config)\n build_config = self.reset_database_list(build_config)\n\n # Get list of regions for a given cloud provider\n \"\"\"\n cloud_provider = (\n build_config[\"api_endpoint\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\"cloud_provider\"][\n \"value\"\n ]\n or \"Amazon Web Services\"\n )\n build_config[\"api_endpoint\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\"region\"][\n \"options\"\n ] = self.map_cloud_providers()[cloud_provider][\"regions\"]\n \"\"\"\n\n return build_config\n\n # Refresh the collection name options\n if field_name == \"api_endpoint\":\n # If missing, refresh the database options\n if not build_config[\"api_endpoint\"][\"options\"] or not field_value:\n return self.update_build_config(build_config, field_value=self.token, field_name=\"token\")\n\n # Set the underlying api endpoint value of the database\n if field_value in build_config[\"api_endpoint\"][\"options\"]:\n index_of_name = build_config[\"api_endpoint\"][\"options\"].index(field_value)\n build_config[\"d_api_endpoint\"][\"value\"] = build_config[\"api_endpoint\"][\"options_metadata\"][\n index_of_name\n ][\"api_endpoint\"]\n else:\n build_config[\"d_api_endpoint\"][\"value\"] = \"\"\n\n # Reset the list of collections we have based on the token provided\n return self.reset_collection_list(build_config)\n\n # Hide embedding model option if opriona_metadata provider is not null\n if field_name == \"collection_name\" and field_value:\n # Assume we will be autodetecting the collection:\n build_config[\"autodetect_collection\"][\"value\"] = True\n\n # Set the options for collection name to be the field value if its a new collection\n if field_value not in build_config[\"collection_name\"][\"options\"]:\n # Add the new collection to the list of options\n build_config[\"collection_name\"][\"options\"].append(field_value)\n build_config[\"collection_name\"][\"options_metadata\"].append(\n {\"records\": 0, \"provider\": None, \"icon\": \"\", \"model\": None}\n )\n\n # Ensure that autodetect collection is set to False, since its a new collection\n build_config[\"autodetect_collection\"][\"value\"] = False\n\n # Find the position of the selected collection to align with metadata\n index_of_name = build_config[\"collection_name\"][\"options\"].index(field_value)\n value_of_provider = build_config[\"collection_name\"][\"options_metadata\"][index_of_name][\"provider\"]\n\n # If we were able to determine the Vectorize provider, set it accordingly\n if value_of_provider:\n build_config[\"embedding_model\"][\"advanced\"] = True\n build_config[\"embedding_choice\"][\"value\"] = \"Astra Vectorize\"\n else:\n build_config[\"embedding_model\"][\"advanced\"] = False\n build_config[\"embedding_choice\"][\"value\"] = \"Embedding Model\"\n\n # For the final step, get the list of vectorize providers\n \"\"\"\n vectorize_providers = self.get_vectorize_providers()\n if not vectorize_providers:\n return build_config\n\n # Allow the user to see the embedding provider options\n provider_options = build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_provider\"\n ][\"options\"]\n if not provider_options:\n # If the collection is set, allow user to see embedding options\n build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_provider\"\n ][\"options\"] = [\"Bring your own\", \"Nvidia\", *[key for key in vectorize_providers if key != \"Nvidia\"]]\n\n # And allow the user to see the models based on a selected provider\n model_options = build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_model\"\n ][\"options\"]\n if not model_options:\n embedding_provider = build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_provider\"\n ][\"value\"]\n\n build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_model\"\n ][\"options\"] = vectorize_providers.get(embedding_provider, [[], []])[1]\n \"\"\"\n\n return build_config\n\n @check_cached_vector_store\n def build_vector_store(self):\n try:\n from langchain_astradb import AstraDBVectorStore\n except ImportError as e:\n msg = (\n \"Could not import langchain Astra DB integration package. \"\n \"Please install it with `pip install langchain-astradb`.\"\n )\n raise ImportError(msg) from e\n\n # Get the embedding model and additional params\n embedding_params = (\n {\"embedding\": self.embedding_model}\n if self.embedding_model and self.embedding_choice == \"Embedding Model\"\n else {}\n )\n\n # Get the additional parameters\n additional_params = self.astradb_vectorstore_kwargs or {}\n\n # Get Langflow version and platform information\n __version__ = get_version_info()[\"version\"]\n langflow_prefix = \"\"\n if os.getenv(\"AWS_EXECUTION_ENV\") == \"AWS_ECS_FARGATE\": # TODO: More precise way of detecting\n langflow_prefix = \"ds-\"\n\n # Get the database object\n database = self.get_database_object(api_endpoint=self.d_api_endpoint)\n autodetect = self.collection_name in database.list_collection_names() and self.autodetect_collection\n\n # Bundle up the auto-detect parameters\n autodetect_params = {\n \"autodetect_collection\": autodetect,\n \"content_field\": (\n self.content_field\n if self.content_field and embedding_params\n else (\n \"page_content\"\n if embedding_params\n and self.collection_data(collection_name=self.collection_name, database=database) == 0\n else None\n )\n ),\n \"ignore_invalid_documents\": self.ignore_invalid_documents,\n }\n\n # Attempt to build the Vector Store object\n try:\n vector_store = AstraDBVectorStore(\n # Astra DB Authentication Parameters\n token=self.token,\n api_endpoint=database.api_endpoint,\n namespace=database.keyspace,\n collection_name=self.collection_name,\n environment=self.environment,\n # Astra DB Usage Tracking Parameters\n ext_callers=[(f\"{langflow_prefix}langflow\", __version__)],\n # Astra DB Vector Store Parameters\n **autodetect_params,\n **embedding_params,\n **additional_params,\n )\n except Exception as e:\n msg = f\"Error initializing AstraDBVectorStore: {e}\"\n raise ValueError(msg) from e\n\n # Add documents to the vector store\n self._add_documents_to_vector_store(vector_store)\n\n return vector_store\n\n def _add_documents_to_vector_store(self, vector_store) -> None:\n documents = []\n for _input in self.ingest_data or []:\n if isinstance(_input, Data):\n documents.append(_input.to_lc_document())\n else:\n msg = \"Vector Store Inputs must be Data objects.\"\n raise TypeError(msg)\n\n if documents and self.deletion_field:\n self.log(f\"Deleting documents where {self.deletion_field}\")\n try:\n database = self.get_database_object(api_endpoint=self.d_api_endpoint)\n collection = database.get_collection(self.collection_name, keyspace=database.keyspace)\n delete_values = list({doc.metadata[self.deletion_field] for doc in documents})\n self.log(f\"Deleting documents where {self.deletion_field} matches {delete_values}.\")\n collection.delete_many({f\"metadata.{self.deletion_field}\": {\"$in\": delete_values}})\n except Exception as e:\n msg = f\"Error deleting documents from AstraDBVectorStore based on '{self.deletion_field}': {e}\"\n raise ValueError(msg) from e\n\n if documents:\n self.log(f\"Adding {len(documents)} documents to the Vector Store.\")\n try:\n vector_store.add_documents(documents)\n except Exception as e:\n msg = f\"Error adding documents to AstraDBVectorStore: {e}\"\n raise ValueError(msg) from e\n else:\n self.log(\"No documents to add to the Vector Store.\")\n\n def _map_search_type(self) -> str:\n search_type_mapping = {\n \"Similarity with score threshold\": \"similarity_score_threshold\",\n \"MMR (Max Marginal Relevance)\": \"mmr\",\n }\n\n return search_type_mapping.get(self.search_type, \"similarity\")\n\n def _build_search_args(self):\n query = self.search_query if isinstance(self.search_query, str) and self.search_query.strip() else None\n\n if query:\n args = {\n \"query\": query,\n \"search_type\": self._map_search_type(),\n \"k\": self.number_of_results,\n \"score_threshold\": self.search_score_threshold,\n }\n elif self.advanced_search_filter:\n args = {\n \"n\": self.number_of_results,\n }\n else:\n return {}\n\n filter_arg = self.advanced_search_filter or {}\n if filter_arg:\n args[\"filter\"] = filter_arg\n\n return args\n\n def search_documents(self, vector_store=None) -> list[Data]:\n vector_store = vector_store or self.build_vector_store()\n\n self.log(f\"Search input: {self.search_query}\")\n self.log(f\"Search type: {self.search_type}\")\n self.log(f\"Number of results: {self.number_of_results}\")\n\n try:\n search_args = self._build_search_args()\n except Exception as e:\n msg = f\"Error in AstraDBVectorStore._build_search_args: {e}\"\n raise ValueError(msg) from e\n\n if not search_args:\n self.log(\"No search input or filters provided. Skipping search.\")\n return []\n\n docs = []\n search_method = \"search\" if \"query\" in search_args else \"metadata_search\"\n\n try:\n self.log(f\"Calling vector_store.{search_method} with args: {search_args}\")\n docs = getattr(vector_store, search_method)(**search_args)\n except Exception as e:\n msg = f\"Error performing {search_method} in AstraDBVectorStore: {e}\"\n raise ValueError(msg) from e\n\n self.log(f\"Retrieved documents: {len(docs)}\")\n\n data = docs_to_data(docs)\n self.log(f\"Converted documents to data: {len(data)}\")\n self.status = data\n\n return data\n\n def get_retriever_kwargs(self):\n search_args = self._build_search_args()\n\n return {\n \"search_type\": self._map_search_type(),\n \"search_kwargs\": search_args,\n }\n"
+ "value": "from collections import defaultdict\nfrom dataclasses import asdict, dataclass, field\n\nfrom astrapy import AstraDBAdmin, DataAPIClient, Database\nfrom astrapy.info import CollectionDescriptor\nfrom langchain_astradb import AstraDBVectorStore, CollectionVectorServiceOptions\n\nfrom langflow.base.vectorstores.model import LCVectorStoreComponent, check_cached_vector_store\nfrom langflow.helpers import docs_to_data\nfrom langflow.inputs import FloatInput, NestedDictInput\nfrom langflow.io import (\n BoolInput,\n DropdownInput,\n HandleInput,\n IntInput,\n SecretStrInput,\n StrInput,\n)\nfrom langflow.schema import Data\nfrom langflow.utils.version import get_version_info\n\n\nclass AstraDBVectorStoreComponent(LCVectorStoreComponent):\n display_name: str = \"Astra DB\"\n description: str = \"Ingest and search documents in Astra DB\"\n documentation: str = \"https://docs.datastax.com/en/langflow/astra-components.html\"\n name = \"AstraDB\"\n icon: str = \"AstraDB\"\n\n _cached_vector_store: AstraDBVectorStore | None = None\n\n @dataclass\n class NewDatabaseInput:\n functionality: str = \"create\"\n fields: dict[str, dict] = field(\n default_factory=lambda: {\n \"data\": {\n \"node\": {\n \"name\": \"create_database\",\n \"description\": \"\",\n \"display_name\": \"Create new database\",\n \"field_order\": [\"new_database_name\", \"cloud_provider\", \"region\"],\n \"template\": {\n \"new_database_name\": StrInput(\n name=\"new_database_name\",\n display_name=\"Name\",\n info=\"Name of the new database to create in Astra DB.\",\n required=True,\n ),\n \"cloud_provider\": DropdownInput(\n name=\"cloud_provider\",\n display_name=\"Cloud provider\",\n info=\"Cloud provider for the new database.\",\n options=[\"Amazon Web Services\", \"Google Cloud Platform\", \"Microsoft Azure\"],\n required=True,\n real_time_refresh=True,\n ),\n \"region\": DropdownInput(\n name=\"region\",\n display_name=\"Region\",\n info=\"Region for the new database.\",\n options=[],\n required=True,\n ),\n },\n },\n }\n }\n )\n\n @dataclass\n class NewCollectionInput:\n functionality: str = \"create\"\n fields: dict[str, dict] = field(\n default_factory=lambda: {\n \"data\": {\n \"node\": {\n \"name\": \"create_collection\",\n \"description\": \"\",\n \"display_name\": \"Create new collection\",\n \"field_order\": [\n \"new_collection_name\",\n \"embedding_generation_provider\",\n \"embedding_generation_model\",\n ],\n \"template\": {\n \"new_collection_name\": StrInput(\n name=\"new_collection_name\",\n display_name=\"Name\",\n info=\"Name of the new collection to create in Astra DB.\",\n required=True,\n ),\n \"embedding_generation_provider\": DropdownInput(\n name=\"embedding_generation_provider\",\n display_name=\"Embedding generation method\",\n info=\"Provider to use for generating embeddings.\",\n real_time_refresh=True,\n required=True,\n options=[\"Bring your own\", \"Nvidia\"],\n ),\n \"embedding_generation_model\": DropdownInput(\n name=\"embedding_generation_model\",\n display_name=\"Embedding model\",\n info=\"Model to use for generating embeddings.\",\n required=True,\n options=[],\n ),\n \"dimension\": IntInput(\n name=\"dimension\",\n display_name=\"Dimensions (Required only for `Bring your own`)\",\n info=\"Dimensions of the embeddings to generate.\",\n required=False,\n value=1024,\n ),\n },\n },\n }\n }\n )\n\n inputs = [\n SecretStrInput(\n name=\"token\",\n display_name=\"Astra DB Application Token\",\n info=\"Authentication token for accessing Astra DB.\",\n value=\"ASTRA_DB_APPLICATION_TOKEN\",\n required=True,\n real_time_refresh=True,\n input_types=[],\n ),\n StrInput(\n name=\"environment\",\n display_name=\"Environment\",\n info=\"The environment for the Astra DB API Endpoint.\",\n advanced=True,\n real_time_refresh=True,\n ),\n DropdownInput(\n name=\"database_name\",\n display_name=\"Database\",\n info=\"The Database name for the Astra DB instance.\",\n required=True,\n refresh_button=True,\n real_time_refresh=True,\n dialog_inputs=asdict(NewDatabaseInput()),\n combobox=True,\n ),\n StrInput(\n name=\"api_endpoint\",\n display_name=\"Astra DB API Endpoint\",\n info=\"The API Endpoint for the Astra DB instance. Supercedes database selection.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"collection_name\",\n display_name=\"Collection\",\n info=\"The name of the collection within Astra DB where the vectors will be stored.\",\n required=True,\n refresh_button=True,\n real_time_refresh=True,\n dialog_inputs=asdict(NewCollectionInput()),\n combobox=True,\n advanced=True,\n ),\n StrInput(\n name=\"keyspace\",\n display_name=\"Keyspace\",\n info=\"Optional keyspace within Astra DB to use for the collection.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"embedding_choice\",\n display_name=\"Embedding Model or Astra Vectorize\",\n info=\"Choose an embedding model or use Astra Vectorize.\",\n options=[\"Embedding Model\", \"Astra Vectorize\"],\n value=\"Embedding Model\",\n advanced=True,\n real_time_refresh=True,\n ),\n HandleInput(\n name=\"embedding_model\",\n display_name=\"Embedding Model\",\n input_types=[\"Embeddings\"],\n info=\"Specify the Embedding Model. Not required for Astra Vectorize collections.\",\n required=False,\n ),\n *LCVectorStoreComponent.inputs,\n IntInput(\n name=\"number_of_results\",\n display_name=\"Number of Search Results\",\n info=\"Number of search results to return.\",\n advanced=True,\n value=4,\n ),\n DropdownInput(\n name=\"search_type\",\n display_name=\"Search Type\",\n info=\"Search type to use\",\n options=[\"Similarity\", \"Similarity with score threshold\", \"MMR (Max Marginal Relevance)\"],\n value=\"Similarity\",\n advanced=True,\n ),\n FloatInput(\n name=\"search_score_threshold\",\n display_name=\"Search Score Threshold\",\n info=\"Minimum similarity score threshold for search results. \"\n \"(when using 'Similarity with score threshold')\",\n value=0,\n advanced=True,\n ),\n NestedDictInput(\n name=\"advanced_search_filter\",\n display_name=\"Search Metadata Filter\",\n info=\"Optional dictionary of filters to apply to the search query.\",\n advanced=True,\n ),\n BoolInput(\n name=\"autodetect_collection\",\n display_name=\"Autodetect Collection\",\n info=\"Boolean flag to determine whether to autodetect the collection.\",\n advanced=True,\n value=True,\n ),\n StrInput(\n name=\"content_field\",\n display_name=\"Content Field\",\n info=\"Field to use as the text content field for the vector store.\",\n advanced=True,\n ),\n StrInput(\n name=\"deletion_field\",\n display_name=\"Deletion Based On Field\",\n info=\"When this parameter is provided, documents in the target collection with \"\n \"metadata field values matching the input metadata field value will be deleted \"\n \"before new data is loaded.\",\n advanced=True,\n ),\n BoolInput(\n name=\"ignore_invalid_documents\",\n display_name=\"Ignore Invalid Documents\",\n info=\"Boolean flag to determine whether to ignore invalid documents at runtime.\",\n advanced=True,\n ),\n NestedDictInput(\n name=\"astradb_vectorstore_kwargs\",\n display_name=\"AstraDBVectorStore Parameters\",\n info=\"Optional dictionary of additional parameters for the AstraDBVectorStore.\",\n advanced=True,\n ),\n ]\n\n @classmethod\n def map_cloud_providers(cls):\n # TODO: Programmatically fetch the regions for each cloud provider\n return {\n \"Amazon Web Services\": {\n \"id\": \"aws\",\n \"regions\": [\"us-east-2\", \"ap-south-1\", \"eu-west-1\"],\n },\n \"Google Cloud Platform\": {\n \"id\": \"gcp\",\n \"regions\": [\"us-east1\"],\n },\n \"Microsoft Azure\": {\n \"id\": \"azure\",\n \"regions\": [\"westus3\"],\n },\n }\n\n @classmethod\n def get_vectorize_providers(cls, token: str, environment: str | None = None, api_endpoint: str | None = None):\n try:\n # Get the admin object\n admin = AstraDBAdmin(token=token, environment=environment)\n db_admin = admin.get_database_admin(api_endpoint=api_endpoint)\n\n # Get the list of embedding providers\n embedding_providers = db_admin.find_embedding_providers().as_dict()\n\n vectorize_providers_mapping = {}\n # Map the provider display name to the provider key and models\n for provider_key, provider_data in embedding_providers[\"embeddingProviders\"].items():\n # Get the provider display name and models\n display_name = provider_data[\"displayName\"]\n models = [model[\"name\"] for model in provider_data[\"models\"]]\n\n # Build our mapping\n vectorize_providers_mapping[display_name] = [provider_key, models]\n\n # Sort the resulting dictionary\n return defaultdict(list, dict(sorted(vectorize_providers_mapping.items())))\n except Exception as e:\n msg = f\"Error fetching vectorize providers: {e}\"\n raise ValueError(msg) from e\n\n @classmethod\n async def create_database_api(\n cls,\n new_database_name: str,\n cloud_provider: str,\n region: str,\n token: str,\n environment: str | None = None,\n keyspace: str | None = None,\n ):\n client = DataAPIClient(token=token, environment=environment)\n\n # Get the admin object\n admin_client = client.get_admin(token=token)\n\n # Call the create database function\n return await admin_client.async_create_database(\n name=new_database_name,\n cloud_provider=cls.map_cloud_providers()[cloud_provider][\"id\"],\n region=region,\n keyspace=keyspace,\n wait_until_active=False,\n )\n\n @classmethod\n async def create_collection_api(\n cls,\n new_collection_name: str,\n token: str,\n api_endpoint: str,\n environment: str | None = None,\n keyspace: str | None = None,\n dimension: int | None = None,\n embedding_generation_provider: str | None = None,\n embedding_generation_model: str | None = None,\n ):\n # Create the data API client\n client = DataAPIClient(token=token)\n\n # Get the database object\n database = client.get_async_database(api_endpoint=api_endpoint, token=token)\n\n # Build vectorize options, if needed\n vectorize_options = None\n if not dimension:\n vectorize_options = CollectionVectorServiceOptions(\n provider=cls.get_vectorize_providers(\n token=token, environment=environment, api_endpoint=api_endpoint\n ).get(embedding_generation_provider, [None, []])[0],\n model_name=embedding_generation_model,\n )\n\n # Create the collection\n return await database.create_collection(\n name=new_collection_name,\n keyspace=keyspace,\n dimension=dimension,\n service=vectorize_options,\n )\n\n @classmethod\n def get_database_list_static(cls, token: str, environment: str | None = None):\n client = DataAPIClient(token=token, environment=environment)\n\n # Get the admin object\n admin_client = client.get_admin(token=token)\n\n # Get the list of databases\n db_list = list(admin_client.list_databases())\n\n # Set the environment properly\n env_string = \"\"\n if environment and environment != \"prod\":\n env_string = f\"-{environment}\"\n\n # Generate the api endpoint for each database\n db_info_dict = {}\n for db in db_list:\n try:\n # Get the API endpoint for the database\n api_endpoint = f\"https://{db.info.id}-{db.info.region}.apps.astra{env_string}.datastax.com\"\n\n # Get the number of collections\n try:\n num_collections = len(\n list(\n client.get_database(\n api_endpoint=api_endpoint, token=token, keyspace=db.info.keyspace\n ).list_collection_names(keyspace=db.info.keyspace)\n )\n )\n except Exception: # noqa: BLE001\n num_collections = 0\n if db.status != \"PENDING\":\n continue\n\n # Add the database to the dictionary\n db_info_dict[db.info.name] = {\n \"api_endpoint\": api_endpoint,\n \"collections\": num_collections,\n \"status\": db.status if db.status != \"ACTIVE\" else None,\n }\n except Exception: # noqa: BLE001, S110\n pass\n\n return db_info_dict\n\n def get_database_list(self):\n return self.get_database_list_static(token=self.token, environment=self.environment)\n\n @classmethod\n def get_api_endpoint_static(\n cls,\n token: str,\n environment: str | None = None,\n api_endpoint: str | None = None,\n database_name: str | None = None,\n ):\n # If the api_endpoint is set, return it\n if api_endpoint:\n return api_endpoint\n\n # Check if the database_name is like a url\n if database_name and database_name.startswith(\"https://\"):\n return database_name\n\n # If the database is not set, nothing we can do.\n if not database_name:\n return None\n\n # Grab the database object\n db = cls.get_database_list_static(token=token, environment=environment).get(database_name)\n if not db:\n return None\n\n # Otherwise, get the URL from the database list\n return db.get(\"api_endpoint\")\n\n def get_api_endpoint(self):\n return self.get_api_endpoint_static(\n token=self.token,\n environment=self.environment,\n api_endpoint=self.api_endpoint,\n database_name=self.database_name,\n )\n\n def get_keyspace(self):\n keyspace = self.keyspace\n\n if keyspace:\n return keyspace.strip()\n\n return None\n\n def get_database_object(self, api_endpoint: str | None = None):\n try:\n client = DataAPIClient(token=self.token, environment=self.environment)\n\n return client.get_database(\n api_endpoint=api_endpoint or self.get_api_endpoint(),\n token=self.token,\n keyspace=self.get_keyspace(),\n )\n except Exception as e:\n msg = f\"Error fetching database object: {e}\"\n raise ValueError(msg) from e\n\n def collection_data(self, collection_name: str, database: Database | None = None):\n try:\n if not database:\n client = DataAPIClient(token=self.token, environment=self.environment)\n\n database = client.get_database(\n api_endpoint=self.get_api_endpoint(),\n token=self.token,\n keyspace=self.get_keyspace(),\n )\n\n collection = database.get_collection(collection_name, keyspace=self.get_keyspace())\n\n return collection.estimated_document_count()\n except Exception as e: # noqa: BLE001\n self.log(f\"Error checking collection data: {e}\")\n\n return None\n\n def _initialize_database_options(self):\n try:\n return [\n {\n \"name\": name,\n \"status\": info[\"status\"],\n \"collections\": info[\"collections\"],\n \"api_endpoint\": info[\"api_endpoint\"],\n \"icon\": \"data\",\n }\n for name, info in self.get_database_list().items()\n ]\n except Exception as e:\n msg = f\"Error fetching database options: {e}\"\n raise ValueError(msg) from e\n\n @classmethod\n def get_provider_icon(cls, collection: CollectionDescriptor | None = None, provider_name: str | None = None) -> str:\n # Get the provider name from the collection\n provider_name = provider_name or (\n collection.options.vector.service.provider\n if collection and collection.options and collection.options.vector and collection.options.vector.service\n else None\n )\n\n # If there is no provider, use the vector store icon\n if not provider_name or provider_name == \"bring your own\":\n return \"vectorstores\"\n\n # Special case for certain models\n # TODO: Add more icons\n if provider_name == \"nvidia\":\n return \"NVIDIA\"\n if provider_name == \"openai\":\n return \"OpenAI\"\n\n # Title case on the provider for the icon if no special case\n return provider_name.title()\n\n def _initialize_collection_options(self, api_endpoint: str | None = None):\n # Nothing to generate if we don't have an API endpoint yet\n api_endpoint = api_endpoint or self.get_api_endpoint()\n if not api_endpoint:\n return []\n\n # Retrieve the database object\n database = self.get_database_object(api_endpoint=api_endpoint)\n\n # Get the list of collections\n collection_list = list(database.list_collections(keyspace=self.get_keyspace()))\n\n # Return the list of collections and metadata associated\n return [\n {\n \"name\": col.name,\n \"records\": self.collection_data(collection_name=col.name, database=database),\n \"provider\": (\n col.options.vector.service.provider if col.options.vector and col.options.vector.service else None\n ),\n \"icon\": self.get_provider_icon(collection=col),\n \"model\": (\n col.options.vector.service.model_name if col.options.vector and col.options.vector.service else None\n ),\n }\n for col in collection_list\n ]\n\n def reset_provider_options(self, build_config: dict):\n # Get the list of vectorize providers\n vectorize_providers = self.get_vectorize_providers(\n token=self.token,\n environment=self.environment,\n api_endpoint=build_config[\"api_endpoint\"][\"value\"],\n )\n\n # If the collection is set, allow user to see embedding options\n build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_provider\"\n ][\"options\"] = [\"Bring your own\", \"Nvidia\", *[key for key in vectorize_providers if key != \"Nvidia\"]]\n\n # For all not Bring your own or Nvidia providers, add metadata saying configure in Astra DB Portal\n provider_options = build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_provider\"\n ][\"options\"]\n\n # Go over each possible provider and add metadata to configure in Astra DB Portal\n for provider in provider_options:\n # Skip Bring your own and Nvidia, automatically configured\n if provider in [\"Bring your own\", \"Nvidia\"]:\n build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_provider\"\n ][\"options_metadata\"].append({\"icon\": self.get_provider_icon(provider_name=provider.lower())})\n continue\n\n # Add metadata to configure in Astra DB Portal\n build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_provider\"\n ][\"options_metadata\"].append({\" \": \"Configure in Astra DB Portal\"})\n\n # And allow the user to see the models based on a selected provider\n embedding_provider = build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_provider\"\n ][\"value\"]\n\n # Set the options for the embedding model based on the provider\n build_config[\"collection_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\n \"embedding_generation_model\"\n ][\"options\"] = vectorize_providers.get(embedding_provider, [[], []])[1]\n\n return build_config\n\n def reset_collection_list(self, build_config: dict):\n # Get the list of options we have based on the token provided\n collection_options = self._initialize_collection_options(api_endpoint=build_config[\"api_endpoint\"][\"value\"])\n\n # If we retrieved options based on the token, show the dropdown\n build_config[\"collection_name\"][\"options\"] = [col[\"name\"] for col in collection_options]\n build_config[\"collection_name\"][\"options_metadata\"] = [\n {k: v for k, v in col.items() if k not in [\"name\"]} for col in collection_options\n ]\n\n # Reset the selected collection\n if build_config[\"collection_name\"][\"value\"] not in build_config[\"collection_name\"][\"options\"]:\n build_config[\"collection_name\"][\"value\"] = \"\"\n\n # If we have a database, collection name should not be advanced\n build_config[\"collection_name\"][\"advanced\"] = not build_config[\"database_name\"][\"value\"]\n\n return build_config\n\n def reset_database_list(self, build_config: dict):\n # Get the list of options we have based on the token provided\n database_options = self._initialize_database_options()\n\n # If we retrieved options based on the token, show the dropdown\n build_config[\"database_name\"][\"options\"] = [db[\"name\"] for db in database_options]\n build_config[\"database_name\"][\"options_metadata\"] = [\n {k: v for k, v in db.items() if k not in [\"name\"]} for db in database_options\n ]\n\n # Reset the selected database\n if build_config[\"database_name\"][\"value\"] not in build_config[\"database_name\"][\"options\"]:\n build_config[\"database_name\"][\"value\"] = \"\"\n build_config[\"api_endpoint\"][\"value\"] = \"\"\n build_config[\"collection_name\"][\"advanced\"] = True\n\n # If we have a token, database name should not be advanced\n build_config[\"database_name\"][\"advanced\"] = not build_config[\"token\"][\"value\"]\n\n return build_config\n\n def reset_build_config(self, build_config: dict):\n # Reset the list of databases we have based on the token provided\n build_config[\"database_name\"][\"options\"] = []\n build_config[\"database_name\"][\"options_metadata\"] = []\n build_config[\"database_name\"][\"value\"] = \"\"\n build_config[\"database_name\"][\"advanced\"] = True\n build_config[\"api_endpoint\"][\"value\"] = \"\"\n\n # Reset the list of collections and metadata associated\n build_config[\"collection_name\"][\"options\"] = []\n build_config[\"collection_name\"][\"options_metadata\"] = []\n build_config[\"collection_name\"][\"value\"] = \"\"\n build_config[\"collection_name\"][\"advanced\"] = True\n\n return build_config\n\n async def update_build_config(self, build_config: dict, field_value: str, field_name: str | None = None):\n # Callback for database creation\n if field_name == \"database_name\" and isinstance(field_value, dict) and \"new_database_name\" in field_value:\n try:\n await self.create_database_api(\n new_database_name=field_value[\"new_database_name\"],\n token=self.token,\n keyspace=self.get_keyspace(),\n environment=self.environment,\n cloud_provider=field_value[\"cloud_provider\"],\n region=field_value[\"region\"],\n )\n except Exception as e:\n msg = f\"Error creating database: {e}\"\n raise ValueError(msg) from e\n\n # Add the new database to the list of options\n build_config[\"database_name\"][\"options\"] = build_config[\"database_name\"][\"options\"] + [\n field_value[\"new_database_name\"]\n ]\n build_config[\"database_name\"][\"options_metadata\"] = build_config[\"database_name\"][\"options_metadata\"] + [\n {\"status\": \"PENDING\"}\n ]\n\n return self.reset_collection_list(build_config)\n\n # This is the callback required to update the list of regions for a cloud provider\n if field_name == \"database_name\" and isinstance(field_value, dict) and \"new_database_name\" not in field_value:\n cloud_provider = field_value[\"cloud_provider\"]\n build_config[\"database_name\"][\"dialog_inputs\"][\"fields\"][\"data\"][\"node\"][\"template\"][\"region\"][\n \"options\"\n ] = self.map_cloud_providers()[cloud_provider][\"regions\"]\n\n return build_config\n\n # Callback for the creation of collections\n if field_name == \"collection_name\" and isinstance(field_value, dict) and \"new_collection_name\" in field_value:\n try:\n # Get the dimension if its a BYO provider\n dimension = (\n field_value[\"dimension\"]\n if field_value[\"embedding_generation_provider\"] == \"Bring your own\"\n else None\n )\n\n # Create the collection\n await self.create_collection_api(\n new_collection_name=field_value[\"new_collection_name\"],\n token=self.token,\n api_endpoint=build_config[\"api_endpoint\"][\"value\"],\n environment=self.environment,\n keyspace=self.get_keyspace(),\n dimension=dimension,\n embedding_generation_provider=field_value[\"embedding_generation_provider\"],\n embedding_generation_model=field_value[\"embedding_generation_model\"],\n )\n except Exception as e:\n msg = f\"Error creating collection: {e}\"\n raise ValueError(msg) from e\n\n # Add the new collection to the list of options\n build_config[\"collection_name\"][\"value\"] = field_value[\"new_collection_name\"]\n build_config[\"collection_name\"][\"options\"].append(field_value[\"new_collection_name\"])\n\n # Get the provider and model for the new collection\n generation_provider = field_value[\"embedding_generation_provider\"]\n provider = generation_provider if generation_provider != \"Bring your own\" else None\n generation_model = field_value[\"embedding_generation_model\"]\n model = generation_model if generation_model else None\n\n # Add the new collection to the list of options\n icon = \"NVIDIA\" if provider == \"Nvidia\" else \"vectorstores\"\n build_config[\"collection_name\"][\"options_metadata\"] = build_config[\"collection_name\"][\n \"options_metadata\"\n ] + [{\"records\": 0, \"provider\": provider, \"icon\": icon, \"model\": model}]\n\n return build_config\n\n # Callback to update the model list based on the embedding provider\n if (\n field_name == \"collection_name\"\n and isinstance(field_value, dict)\n and \"new_collection_name\" not in field_value\n ):\n return self.reset_provider_options(build_config)\n\n # When the component first executes, this is the update refresh call\n first_run = field_name == \"collection_name\" and not field_value and not build_config[\"database_name\"][\"options\"]\n\n # If the token has not been provided, simply return the empty build config\n if not self.token:\n return self.reset_build_config(build_config)\n\n # If this is the first execution of the component, reset and build database list\n if first_run or field_name in [\"token\", \"environment\"]:\n return self.reset_database_list(build_config)\n\n # Refresh the collection name options\n if field_name == \"database_name\" and not isinstance(field_value, dict):\n # If missing, refresh the database options\n if field_value not in build_config[\"database_name\"][\"options\"]:\n build_config = await self.update_build_config(build_config, field_value=self.token, field_name=\"token\")\n build_config[\"database_name\"][\"value\"] = \"\"\n else:\n # Find the position of the selected database to align with metadata\n index_of_name = build_config[\"database_name\"][\"options\"].index(field_value)\n\n # Initializing database condition\n pending = build_config[\"database_name\"][\"options_metadata\"][index_of_name][\"status\"] == \"PENDING\"\n if pending:\n return self.update_build_config(build_config, field_value=self.token, field_name=\"token\")\n\n # Set the API endpoint based on the selected database\n build_config[\"api_endpoint\"][\"value\"] = build_config[\"database_name\"][\"options_metadata\"][\n index_of_name\n ][\"api_endpoint\"]\n\n # Reset the provider options\n build_config = self.reset_provider_options(build_config)\n\n # Reset the list of collections we have based on the token provided\n return self.reset_collection_list(build_config)\n\n # Hide embedding model option if opriona_metadata provider is not null\n if field_name == \"collection_name\" and not isinstance(field_value, dict):\n # Assume we will be autodetecting the collection:\n build_config[\"autodetect_collection\"][\"value\"] = True\n\n # Reload the collection list\n build_config = self.reset_collection_list(build_config)\n\n # Set the options for collection name to be the field value if its a new collection\n if field_value and field_value not in build_config[\"collection_name\"][\"options\"]:\n # Add the new collection to the list of options\n build_config[\"collection_name\"][\"options\"].append(field_value)\n build_config[\"collection_name\"][\"options_metadata\"].append(\n {\"records\": 0, \"provider\": None, \"icon\": \"\", \"model\": None}\n )\n\n # Ensure that autodetect collection is set to False, since its a new collection\n build_config[\"autodetect_collection\"][\"value\"] = False\n\n # Find the position of the selected collection to align with metadata\n index_of_name = build_config[\"collection_name\"][\"options\"].index(field_value)\n value_of_provider = build_config[\"collection_name\"][\"options_metadata\"][index_of_name][\"provider\"]\n\n # If we were able to determine the Vectorize provider, set it accordingly\n if value_of_provider:\n build_config[\"embedding_model\"][\"advanced\"] = True\n build_config[\"embedding_choice\"][\"value\"] = \"Astra Vectorize\"\n else:\n build_config[\"embedding_model\"][\"advanced\"] = False\n build_config[\"embedding_choice\"][\"value\"] = \"Embedding Model\"\n\n return build_config\n\n return build_config\n\n @check_cached_vector_store\n def build_vector_store(self):\n try:\n from langchain_astradb import AstraDBVectorStore\n except ImportError as e:\n msg = (\n \"Could not import langchain Astra DB integration package. \"\n \"Please install it with `pip install langchain-astradb`.\"\n )\n raise ImportError(msg) from e\n\n # Get the embedding model and additional params\n embedding_params = (\n {\"embedding\": self.embedding_model}\n if self.embedding_model and self.embedding_choice == \"Embedding Model\"\n else {}\n )\n\n # Get the additional parameters\n additional_params = self.astradb_vectorstore_kwargs or {}\n\n # Get Langflow version and platform information\n __version__ = get_version_info()[\"version\"]\n langflow_prefix = \"\"\n # if os.getenv(\"AWS_EXECUTION_ENV\") == \"AWS_ECS_FARGATE\": # TODO: More precise way of detecting\n # langflow_prefix = \"ds-\"\n\n # Get the database object\n database = self.get_database_object()\n autodetect = self.collection_name in database.list_collection_names() and self.autodetect_collection\n\n # Bundle up the auto-detect parameters\n autodetect_params = {\n \"autodetect_collection\": autodetect,\n \"content_field\": (\n self.content_field\n if self.content_field and embedding_params\n else (\n \"page_content\"\n if embedding_params\n and self.collection_data(collection_name=self.collection_name, database=database) == 0\n else None\n )\n ),\n \"ignore_invalid_documents\": self.ignore_invalid_documents,\n }\n\n # Attempt to build the Vector Store object\n try:\n vector_store = AstraDBVectorStore(\n # Astra DB Authentication Parameters\n token=self.token,\n api_endpoint=database.api_endpoint,\n namespace=database.keyspace,\n collection_name=self.collection_name,\n environment=self.environment,\n # Astra DB Usage Tracking Parameters\n ext_callers=[(f\"{langflow_prefix}langflow\", __version__)],\n # Astra DB Vector Store Parameters\n **autodetect_params,\n **embedding_params,\n **additional_params,\n )\n except Exception as e:\n msg = f\"Error initializing AstraDBVectorStore: {e}\"\n raise ValueError(msg) from e\n\n # Add documents to the vector store\n self._add_documents_to_vector_store(vector_store)\n\n return vector_store\n\n def _add_documents_to_vector_store(self, vector_store) -> None:\n documents = []\n for _input in self.ingest_data or []:\n if isinstance(_input, Data):\n documents.append(_input.to_lc_document())\n else:\n msg = \"Vector Store Inputs must be Data objects.\"\n raise TypeError(msg)\n\n if documents and self.deletion_field:\n self.log(f\"Deleting documents where {self.deletion_field}\")\n try:\n database = self.get_database_object()\n collection = database.get_collection(self.collection_name, keyspace=database.keyspace)\n delete_values = list({doc.metadata[self.deletion_field] for doc in documents})\n self.log(f\"Deleting documents where {self.deletion_field} matches {delete_values}.\")\n collection.delete_many({f\"metadata.{self.deletion_field}\": {\"$in\": delete_values}})\n except Exception as e:\n msg = f\"Error deleting documents from AstraDBVectorStore based on '{self.deletion_field}': {e}\"\n raise ValueError(msg) from e\n\n if documents:\n self.log(f\"Adding {len(documents)} documents to the Vector Store.\")\n try:\n vector_store.add_documents(documents)\n except Exception as e:\n msg = f\"Error adding documents to AstraDBVectorStore: {e}\"\n raise ValueError(msg) from e\n else:\n self.log(\"No documents to add to the Vector Store.\")\n\n def _map_search_type(self) -> str:\n search_type_mapping = {\n \"Similarity with score threshold\": \"similarity_score_threshold\",\n \"MMR (Max Marginal Relevance)\": \"mmr\",\n }\n\n return search_type_mapping.get(self.search_type, \"similarity\")\n\n def _build_search_args(self):\n query = self.search_query if isinstance(self.search_query, str) and self.search_query.strip() else None\n\n if query:\n args = {\n \"query\": query,\n \"search_type\": self._map_search_type(),\n \"k\": self.number_of_results,\n \"score_threshold\": self.search_score_threshold,\n }\n elif self.advanced_search_filter:\n args = {\n \"n\": self.number_of_results,\n }\n else:\n return {}\n\n filter_arg = self.advanced_search_filter or {}\n if filter_arg:\n args[\"filter\"] = filter_arg\n\n return args\n\n def search_documents(self, vector_store=None) -> list[Data]:\n vector_store = vector_store or self.build_vector_store()\n\n self.log(f\"Search input: {self.search_query}\")\n self.log(f\"Search type: {self.search_type}\")\n self.log(f\"Number of results: {self.number_of_results}\")\n\n try:\n search_args = self._build_search_args()\n except Exception as e:\n msg = f\"Error in AstraDBVectorStore._build_search_args: {e}\"\n raise ValueError(msg) from e\n\n if not search_args:\n self.log(\"No search input or filters provided. Skipping search.\")\n return []\n\n docs = []\n search_method = \"search\" if \"query\" in search_args else \"metadata_search\"\n\n try:\n self.log(f\"Calling vector_store.{search_method} with args: {search_args}\")\n docs = getattr(vector_store, search_method)(**search_args)\n except Exception as e:\n msg = f\"Error performing {search_method} in AstraDBVectorStore: {e}\"\n raise ValueError(msg) from e\n\n self.log(f\"Retrieved documents: {len(docs)}\")\n\n data = docs_to_data(docs)\n self.log(f\"Converted documents to data: {len(data)}\")\n self.status = data\n\n return data\n\n def get_retriever_kwargs(self):\n search_args = self._build_search_args()\n\n return {\n \"search_type\": self._map_search_type(),\n \"search_kwargs\": search_args,\n }\n"
},
"collection_name": {
"_input_type": "DropdownInput",
- "advanced": false,
+ "advanced": true,
"combobox": true,
- "dialog_inputs": {},
+ "dialog_inputs": {
+ "fields": {
+ "data": {
+ "node": {
+ "description": "",
+ "display_name": "Create new collection",
+ "field_order": [
+ "new_collection_name",
+ "embedding_generation_provider",
+ "embedding_generation_model"
+ ],
+ "name": "create_collection",
+ "template": {
+ "dimension": {
+ "_input_type": "IntInput",
+ "advanced": false,
+ "display_name": "Dimensions",
+ "dynamic": false,
+ "info": "Dimension of the embeddings to generate.",
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "dimension",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "int",
+ "value": 1024
+ },
+ "embedding_generation_model": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Embedding model",
+ "dynamic": false,
+ "info": "Model to use for generating embeddings.",
+ "name": "embedding_generation_model",
+ "options": [
+ "Bring your own",
+ "NV-Embed-QA"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "embedding_generation_provider": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Embedding generation method",
+ "dynamic": false,
+ "info": "Provider to use for generating embeddings.",
+ "name": "embedding_generation_provider",
+ "options": [
+ "Bring your own",
+ "Nvidia"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "real_time_refresh": true,
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "new_collection_name": {
+ "_input_type": "StrInput",
+ "advanced": false,
+ "display_name": "Name",
+ "dynamic": false,
+ "info": "Name of the new collection to create in Astra DB.",
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "new_collection_name",
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ }
+ }
+ }
+ },
+ "functionality": "create"
+ },
"display_name": "Collection",
"dynamic": false,
"info": "The name of the collection within Astra DB where the vectors will be stored.",
@@ -3880,18 +3977,107 @@
"type": "str",
"value": ""
},
- "d_api_endpoint": {
- "_input_type": "StrInput",
- "advanced": true,
- "display_name": "Database API Endpoint",
+ "database_name": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": true,
+ "dialog_inputs": {
+ "fields": {
+ "data": {
+ "node": {
+ "description": "",
+ "display_name": "Create new database",
+ "field_order": [
+ "new_database_name",
+ "cloud_provider",
+ "region"
+ ],
+ "name": "create_database",
+ "template": {
+ "cloud_provider": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Cloud provider",
+ "dynamic": false,
+ "info": "Cloud provider for the new database.",
+ "name": "cloud_provider",
+ "options": [
+ "Amazon Web Services",
+ "Google Cloud Platform",
+ "Microsoft Azure"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "real_time_refresh": true,
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "new_database_name": {
+ "_input_type": "StrInput",
+ "advanced": false,
+ "display_name": "Name",
+ "dynamic": false,
+ "info": "Name of the new database to create in Astra DB.",
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "new_database_name",
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ },
+ "region": {
+ "_input_type": "DropdownInput",
+ "advanced": false,
+ "combobox": false,
+ "dialog_inputs": {},
+ "display_name": "Region",
+ "dynamic": false,
+ "info": "Region for the new database.",
+ "name": "region",
+ "options": [
+ "us-east-2",
+ "ap-south-1",
+ "eu-west-1"
+ ],
+ "options_metadata": [],
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": ""
+ }
+ }
+ }
+ }
+ },
+ "functionality": "create"
+ },
+ "display_name": "Database",
"dynamic": false,
- "info": "The API Endpoint for the Astra DB instance. Supercedes database selection.",
- "list": false,
- "list_add_label": "Add More",
- "load_from_db": false,
- "name": "d_api_endpoint",
+ "info": "The Database name for the Astra DB instance.",
+ "name": "database_name",
+ "options": [],
+ "options_metadata": [],
"placeholder": "",
- "required": false,
+ "real_time_refresh": true,
+ "refresh_button": true,
+ "required": true,
"show": true,
"title_case": false,
"tool_mode": false,
@@ -3927,10 +4113,7 @@
"dynamic": false,
"info": "Choose an embedding model or use Astra Vectorize.",
"name": "embedding_choice",
- "options": [
- "Embedding Model",
- "Astra Vectorize"
- ],
+ "options": ["Embedding Model", "Astra Vectorize"],
"options_metadata": [],
"placeholder": "",
"real_time_refresh": true,
@@ -3948,9 +4131,7 @@
"display_name": "Embedding Model",
"dynamic": false,
"info": "Specify the Embedding Model. Not required for Astra Vectorize collections.",
- "input_types": [
- "Embeddings"
- ],
+ "input_types": ["Embeddings"],
"list": false,
"list_add_label": "Add More",
"name": "embedding_model",
@@ -3973,6 +4154,7 @@
"load_from_db": false,
"name": "environment",
"placeholder": "",
+ "real_time_refresh": true,
"required": false,
"show": true,
"title_case": false,
@@ -4005,9 +4187,7 @@
"display_name": "Ingest Data",
"dynamic": false,
"info": "",
- "input_types": [
- "Data"
- ],
+ "input_types": ["Data"],
"list": false,
"list_add_label": "Add More",
"name": "ingest_data",
@@ -4064,9 +4244,7 @@
"display_name": "Search Query",
"dynamic": false,
"info": "",
- "input_types": [
- "Message"
- ],
+ "input_types": ["Message"],
"list": false,
"list_add_label": "Add More",
"load_from_db": false,
@@ -4140,7 +4318,7 @@
"show": true,
"title_case": false,
"type": "str",
- "value": ""
+ "value": "ASTRA_DB_APPLICATION_TOKEN"
}
},
"tool_mode": false
@@ -4149,35 +4327,30 @@
"type": "AstraDB"
},
"dragging": false,
- "id": "AstraDB-sPWXd",
+ "id": "AstraDB-nMlxo",
"measured": {
- "height": 611,
+ "height": 532,
"width": 320
},
"position": {
- "x": 2053.8028711939423,
- "y": 1455.7952184640951
+ "x": 2065.4581687557493,
+ "y": 1496.259507100966
},
"selected": false,
"type": "genericNode"
}
],
"viewport": {
- "x": 14.338407079834894,
- "y": 248.6723683033677,
- "zoom": 0.2658894837527901
+ "x": 24.946958998386435,
+ "y": -163.43184624766263,
+ "zoom": 0.44406917240373706
}
},
"description": "Load your data for chat context with Retrieval Augmented Generation.",
"endpoint_name": null,
- "id": "b57f5ec7-f4f1-42d9-b877-4b2a4fb0650a",
+ "id": "89b399d4-ddab-44cb-bda6-f8cad1120416",
"is_component": false,
- "last_tested_version": "1.1.2",
+ "last_tested_version": "1.1.5",
"name": "Vector Store RAG",
- "tags": [
- "openai",
- "astradb",
- "rag",
- "q-a"
- ]
-}
\ No newline at end of file
+ "tags": ["openai", "astradb", "rag", "q-a"]
+}
diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json b/src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json
new file mode 100644
index 0000000000..7441fd1505
--- /dev/null
+++ b/src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json
@@ -0,0 +1,3282 @@
+{
+ "data": {
+ "edges": [
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "YouTubeCommentsComponent",
+ "id": "YouTubeCommentsComponent-10bJT",
+ "name": "comments",
+ "output_types": [
+ "DataFrame"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "df",
+ "id": "BatchRunComponent-Y6Aec",
+ "inputTypes": [
+ "DataFrame"
+ ],
+ "type": "other"
+ }
+ },
+ "id": "reactflow__edge-YouTubeCommentsComponent-10bJT{œdataTypeœ:œYouTubeCommentsComponentœ,œidœ:œYouTubeCommentsComponent-10bJTœ,œnameœ:œcommentsœ,œoutput_typesœ:[œDataFrameœ]}-BatchRunComponent-Y6Aec{œfieldNameœ:œdfœ,œidœ:œBatchRunComponent-Y6Aecœ,œinputTypesœ:[œDataFrameœ],œtypeœ:œotherœ}",
+ "selected": false,
+ "source": "YouTubeCommentsComponent-10bJT",
+ "sourceHandle": "{œdataTypeœ: œYouTubeCommentsComponentœ, œidœ: œYouTubeCommentsComponent-10bJTœ, œnameœ: œcommentsœ, œoutput_typesœ: [œDataFrameœ]}",
+ "target": "BatchRunComponent-Y6Aec",
+ "targetHandle": "{œfieldNameœ: œdfœ, œidœ: œBatchRunComponent-Y6Aecœ, œinputTypesœ: [œDataFrameœ], œtypeœ: œotherœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "OpenAIModel",
+ "id": "OpenAIModel-QgyC5",
+ "name": "model_output",
+ "output_types": [
+ "LanguageModel"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "model",
+ "id": "BatchRunComponent-Y6Aec",
+ "inputTypes": [
+ "LanguageModel"
+ ],
+ "type": "other"
+ }
+ },
+ "id": "reactflow__edge-OpenAIModel-QgyC5{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-QgyC5œ,œnameœ:œmodel_outputœ,œoutput_typesœ:[œLanguageModelœ]}-BatchRunComponent-Y6Aec{œfieldNameœ:œmodelœ,œidœ:œBatchRunComponent-Y6Aecœ,œinputTypesœ:[œLanguageModelœ],œtypeœ:œotherœ}",
+ "selected": false,
+ "source": "OpenAIModel-QgyC5",
+ "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-QgyC5œ, œnameœ: œmodel_outputœ, œoutput_typesœ: [œLanguageModelœ]}",
+ "target": "BatchRunComponent-Y6Aec",
+ "targetHandle": "{œfieldNameœ: œmodelœ, œidœ: œBatchRunComponent-Y6Aecœ, œinputTypesœ: [œLanguageModelœ], œtypeœ: œotherœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "BatchRunComponent",
+ "id": "BatchRunComponent-Y6Aec",
+ "name": "batch_results",
+ "output_types": [
+ "DataFrame"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "df",
+ "id": "ParseDataFrame-Ni6HW",
+ "inputTypes": [
+ "DataFrame"
+ ],
+ "type": "other"
+ }
+ },
+ "id": "reactflow__edge-BatchRunComponent-Y6Aec{œdataTypeœ:œBatchRunComponentœ,œidœ:œBatchRunComponent-Y6Aecœ,œnameœ:œbatch_resultsœ,œoutput_typesœ:[œDataFrameœ]}-ParseDataFrame-Ni6HW{œfieldNameœ:œdfœ,œidœ:œParseDataFrame-Ni6HWœ,œinputTypesœ:[œDataFrameœ],œtypeœ:œotherœ}",
+ "selected": false,
+ "source": "BatchRunComponent-Y6Aec",
+ "sourceHandle": "{œdataTypeœ: œBatchRunComponentœ, œidœ: œBatchRunComponent-Y6Aecœ, œnameœ: œbatch_resultsœ, œoutput_typesœ: [œDataFrameœ]}",
+ "target": "ParseDataFrame-Ni6HW",
+ "targetHandle": "{œfieldNameœ: œdfœ, œidœ: œParseDataFrame-Ni6HWœ, œinputTypesœ: [œDataFrameœ], œtypeœ: œotherœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "ParseDataFrame",
+ "id": "ParseDataFrame-Ni6HW",
+ "name": "text",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "analysis",
+ "id": "Prompt-ozK70",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "reactflow__edge-ParseDataFrame-Ni6HW{œdataTypeœ:œParseDataFrameœ,œidœ:œParseDataFrame-Ni6HWœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-ozK70{œfieldNameœ:œanalysisœ,œidœ:œPrompt-ozK70œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "ParseDataFrame-Ni6HW",
+ "sourceHandle": "{œdataTypeœ: œParseDataFrameœ, œidœ: œParseDataFrame-Ni6HWœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Prompt-ozK70",
+ "targetHandle": "{œfieldNameœ: œanalysisœ, œidœ: œPrompt-ozK70œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "Prompt",
+ "id": "Prompt-ozK70",
+ "name": "prompt",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "input_value",
+ "id": "Agent-U1bxR",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "reactflow__edge-Prompt-ozK70{œdataTypeœ:œPromptœ,œidœ:œPrompt-ozK70œ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-U1bxR{œfieldNameœ:œinput_valueœ,œidœ:œAgent-U1bxRœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "Prompt-ozK70",
+ "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-ozK70œ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Agent-U1bxR",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-U1bxRœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "Agent",
+ "id": "Agent-U1bxR",
+ "name": "response",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "input_value",
+ "id": "ChatOutput-BILzx",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "reactflow__edge-Agent-U1bxR{œdataTypeœ:œAgentœ,œidœ:œAgent-U1bxRœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-BILzx{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-BILzxœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "Agent-U1bxR",
+ "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-U1bxRœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "ChatOutput-BILzx",
+ "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-BILzxœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "YouTubeTranscripts",
+ "id": "YouTubeTranscripts-wPf1w",
+ "name": "component_as_tool",
+ "output_types": [
+ "Tool"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "tools",
+ "id": "Agent-U1bxR",
+ "inputTypes": [
+ "Tool"
+ ],
+ "type": "other"
+ }
+ },
+ "id": "reactflow__edge-YouTubeTranscripts-wPf1w{œdataTypeœ:œYouTubeTranscriptsœ,œidœ:œYouTubeTranscripts-wPf1wœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-U1bxR{œfieldNameœ:œtoolsœ,œidœ:œAgent-U1bxRœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}",
+ "selected": false,
+ "source": "YouTubeTranscripts-wPf1w",
+ "sourceHandle": "{œdataTypeœ: œYouTubeTranscriptsœ, œidœ: œYouTubeTranscripts-wPf1wœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}",
+ "target": "Agent-U1bxR",
+ "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-U1bxRœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "ChatInput",
+ "id": "ChatInput-VrWjf",
+ "name": "message",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "input_text",
+ "id": "ConditionalRouter-CfANV",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "xy-edge__ChatInput-VrWjf{œdataTypeœ:œChatInputœ,œidœ:œChatInput-VrWjfœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-ConditionalRouter-CfANV{œfieldNameœ:œinput_textœ,œidœ:œConditionalRouter-CfANVœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "ChatInput-VrWjf",
+ "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-VrWjfœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "ConditionalRouter-CfANV",
+ "targetHandle": "{œfieldNameœ: œinput_textœ, œidœ: œConditionalRouter-CfANVœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "ChatInput",
+ "id": "ChatInput-VrWjf",
+ "name": "message",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "message",
+ "id": "ConditionalRouter-CfANV",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "xy-edge__ChatInput-VrWjf{œdataTypeœ:œChatInputœ,œidœ:œChatInput-VrWjfœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-ConditionalRouter-CfANV{œfieldNameœ:œmessageœ,œidœ:œConditionalRouter-CfANVœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "ChatInput-VrWjf",
+ "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-VrWjfœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "ConditionalRouter-CfANV",
+ "targetHandle": "{œfieldNameœ: œmessageœ, œidœ: œConditionalRouter-CfANVœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "ConditionalRouter",
+ "id": "ConditionalRouter-CfANV",
+ "name": "true_result",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "video_url",
+ "id": "YouTubeCommentsComponent-10bJT",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "xy-edge__ConditionalRouter-CfANV{œdataTypeœ:œConditionalRouterœ,œidœ:œConditionalRouter-CfANVœ,œnameœ:œtrue_resultœ,œoutput_typesœ:[œMessageœ]}-YouTubeCommentsComponent-10bJT{œfieldNameœ:œvideo_urlœ,œidœ:œYouTubeCommentsComponent-10bJTœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "ConditionalRouter-CfANV",
+ "sourceHandle": "{œdataTypeœ: œConditionalRouterœ, œidœ: œConditionalRouter-CfANVœ, œnameœ: œtrue_resultœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "YouTubeCommentsComponent-10bJT",
+ "targetHandle": "{œfieldNameœ: œvideo_urlœ, œidœ: œYouTubeCommentsComponent-10bJTœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ },
+ {
+ "animated": false,
+ "className": "",
+ "data": {
+ "sourceHandle": {
+ "dataType": "ConditionalRouter",
+ "id": "ConditionalRouter-CfANV",
+ "name": "true_result",
+ "output_types": [
+ "Message"
+ ]
+ },
+ "targetHandle": {
+ "fieldName": "url",
+ "id": "Prompt-ozK70",
+ "inputTypes": [
+ "Message"
+ ],
+ "type": "str"
+ }
+ },
+ "id": "xy-edge__ConditionalRouter-CfANV{œdataTypeœ:œConditionalRouterœ,œidœ:œConditionalRouter-CfANVœ,œnameœ:œtrue_resultœ,œoutput_typesœ:[œMessageœ]}-Prompt-ozK70{œfieldNameœ:œurlœ,œidœ:œPrompt-ozK70œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
+ "selected": false,
+ "source": "ConditionalRouter-CfANV",
+ "sourceHandle": "{œdataTypeœ: œConditionalRouterœ, œidœ: œConditionalRouter-CfANVœ, œnameœ: œtrue_resultœ, œoutput_typesœ: [œMessageœ]}",
+ "target": "Prompt-ozK70",
+ "targetHandle": "{œfieldNameœ: œurlœ, œidœ: œPrompt-ozK70œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
+ }
+ ],
+ "nodes": [
+ {
+ "data": {
+ "id": "BatchRunComponent-Y6Aec",
+ "node": {
+ "base_classes": [
+ "DataFrame"
+ ],
+ "beta": true,
+ "category": "helpers",
+ "conditional_paths": [],
+ "custom_fields": {},
+ "description": "Runs a language model over each row of a DataFrame's text column and returns a new DataFrame with two columns: 'text_input' (the original text) and 'model_response' containing the model's response.",
+ "display_name": "Batch Run",
+ "documentation": "",
+ "edited": false,
+ "field_order": [
+ "model",
+ "system_message",
+ "df",
+ "column_name"
+ ],
+ "frozen": false,
+ "icon": "List",
+ "key": "BatchRunComponent",
+ "legacy": false,
+ "lf_version": "1.1.3",
+ "metadata": {},
+ "minimized": false,
+ "output_types": [],
+ "outputs": [
+ {
+ "allows_loop": false,
+ "cache": true,
+ "display_name": "Batch Results",
+ "method": "run_batch",
+ "name": "batch_results",
+ "selected": "DataFrame",
+ "tool_mode": true,
+ "types": [
+ "DataFrame"
+ ],
+ "value": "__UNDEFINED__"
+ }
+ ],
+ "pinned": false,
+ "score": 0.007568328950209746,
+ "template": {
+ "_type": "Component",
+ "code": {
+ "advanced": true,
+ "dynamic": true,
+ "fileTypes": [],
+ "file_path": "",
+ "info": "",
+ "list": false,
+ "load_from_db": false,
+ "multiline": true,
+ "name": "code",
+ "password": false,
+ "placeholder": "",
+ "required": true,
+ "show": true,
+ "title_case": false,
+ "type": "code",
+ "value": "from __future__ import annotations\n\nfrom typing import TYPE_CHECKING\n\nfrom langflow.custom import Component\nfrom langflow.io import DataFrameInput, HandleInput, MultilineInput, Output, StrInput\nfrom langflow.schema import DataFrame\n\nif TYPE_CHECKING:\n from langchain_core.runnables import Runnable\n\n\nclass BatchRunComponent(Component):\n display_name = \"Batch Run\"\n description = (\n \"Runs a language model over each row of a DataFrame's text column and returns a new \"\n \"DataFrame with two columns: 'text_input' (the original text) and 'model_response' \"\n \"containing the model's response.\"\n )\n icon = \"List\"\n beta = True\n\n inputs = [\n HandleInput(\n name=\"model\",\n display_name=\"Language Model\",\n info=\"Connect the 'Language Model' output from your LLM component here.\",\n input_types=[\"LanguageModel\"],\n ),\n MultilineInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"Multi-line system instruction for all rows in the DataFrame.\",\n required=False,\n ),\n DataFrameInput(\n name=\"df\",\n display_name=\"DataFrame\",\n info=\"The DataFrame whose column (specified by 'column_name') we'll treat as text messages.\",\n ),\n StrInput(\n name=\"column_name\",\n display_name=\"Column Name\",\n info=\"The name of the DataFrame column to treat as text messages. Default='text'.\",\n value=\"text\",\n ),\n ]\n\n outputs = [\n Output(\n display_name=\"Batch Results\",\n name=\"batch_results\",\n method=\"run_batch\",\n info=\"A DataFrame with two columns: 'text_input' and 'model_response'.\",\n ),\n ]\n\n async def run_batch(self) -> DataFrame:\n \"\"\"For each row in df[column_name], combine that text with system_message, then invoke the model asynchronously.\n\n Returns a new DataFrame of the same length, with columns 'text_input' and 'model_response'.\n \"\"\"\n model: Runnable = self.model\n system_msg = self.system_message or \"\"\n df: DataFrame = self.df\n col_name = self.column_name or \"text\"\n\n if col_name not in df.columns:\n msg = f\"Column '{col_name}' not found in the DataFrame.\"\n raise ValueError(msg)\n\n # Convert the specified column to a list of strings\n user_texts = df[col_name].astype(str).tolist()\n\n # Prepare the batch of conversations\n conversations = [\n [{\"role\": \"system\", \"content\": system_msg}, {\"role\": \"user\", \"content\": text}]\n if system_msg\n else [{\"role\": \"user\", \"content\": text}]\n for text in user_texts\n ]\n model = model.with_config(\n {\n \"run_name\": self.display_name,\n \"project_name\": self.get_project_name(),\n \"callbacks\": self.get_langchain_callbacks(),\n }\n )\n\n responses = await model.abatch(conversations)\n\n # Build the final data, each row has 'text_input' + 'model_response'\n rows = []\n for original_text, response in zip(user_texts, responses, strict=False):\n resp_text = response.content if hasattr(response, \"content\") else str(response)\n\n row = {\"text_input\": original_text, \"model_response\": resp_text}\n rows.append(row)\n\n # Convert to a new DataFrame\n return DataFrame(rows) # Langflow DataFrame from a list of dicts\n"
+ },
+ "column_name": {
+ "_input_type": "StrInput",
+ "advanced": false,
+ "display_name": "Column Name",
+ "dynamic": false,
+ "info": "The name of the DataFrame column to treat as text messages. Default='text'.",
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "name": "column_name",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "text"
+ },
+ "df": {
+ "_input_type": "DataFrameInput",
+ "advanced": false,
+ "display_name": "DataFrame",
+ "dynamic": false,
+ "info": "The DataFrame whose column (specified by 'column_name') we'll treat as text messages.",
+ "input_types": [
+ "DataFrame"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "df",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "other",
+ "value": ""
+ },
+ "model": {
+ "_input_type": "HandleInput",
+ "advanced": false,
+ "display_name": "Language Model",
+ "dynamic": false,
+ "info": "Connect the 'Language Model' output from your LLM component here.",
+ "input_types": [
+ "LanguageModel"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "name": "model",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "trace_as_metadata": true,
+ "type": "other",
+ "value": ""
+ },
+ "system_message": {
+ "_input_type": "MultilineInput",
+ "advanced": false,
+ "display_name": "System Message",
+ "dynamic": false,
+ "info": "Multi-line system instruction for all rows in the DataFrame.",
+ "input_types": [
+ "Message"
+ ],
+ "list": false,
+ "list_add_label": "Add More",
+ "load_from_db": false,
+ "multiline": true,
+ "name": "system_message",
+ "placeholder": "",
+ "required": false,
+ "show": true,
+ "title_case": false,
+ "tool_mode": false,
+ "trace_as_input": true,
+ "trace_as_metadata": true,
+ "type": "str",
+ "value": "You are a sentiment analysis AI specialized in analyzing YouTube comments. Your task is to determine the emotional tone of each comment.\n\nAnalyze:\n- Word choice and tone\n- Emotional language \n- Context clues (emojis, punctuation, caps)\n\nClassify sentiment as:\n- Positive\n- Negative \n- Neutral\n- Mixed\n- Sarcastic\n\nFormat:\n