diff --git a/examples/.gitignore b/examples/.gitignore
new file mode 100644
index 00000000..0a197900
--- /dev/null
+++ b/examples/.gitignore
@@ -0,0 +1,174 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# UV
+# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+#uv.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
+.pdm.toml
+.pdm-python
+.pdm-build/
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# PyCharm
+# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+# and can be added to the global gitignore or merged into this file. For a more nuclear
+# option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
+
+# Ruff stuff:
+.ruff_cache/
+
+# PyPI configuration file
+.pypirc
diff --git a/examples/agent/crewAI/README.md b/examples/agent/crewAI/README.md
new file mode 100644
index 00000000..f77c3301
--- /dev/null
+++ b/examples/agent/crewAI/README.md
@@ -0,0 +1,13 @@
+# CrewAI + Splunk AO Examples
+
+This repo contains examples of how to use Splunk AO to instrument [CrewAI](https://www.crewai.com/) agents for observability and evaluation engineering.
+
+## research_crew
+
+The [resarch-crew](./research_crew/) is a quickstart tutorial. It is a completed version of the [CrewAI quickstart](https://docs.crewai.com/en/quickstart) and adds the
+Splunk AO's [CrewAIEventListener](https://docs.galileo.ai/sdk-api/python/reference/handlers/crewai/handler),
+an event handler implemented on top of OpenTelemetry (OTel). For more information, see
+Splunk AO’s [Add Splunk AO to a CrewAI Application](https://docs.galileo.ai/how-to-guides/third-party-integrations/add-galileo-to-crewai/add-galileo-to-crewai)
+how-to guide.
+
+See the [README.md](./research_crew/README.md) for detailed setup instructions.
diff --git a/examples/agent/crewAI/research_crew/.gitignore b/examples/agent/crewAI/research_crew/.gitignore
new file mode 100644
index 00000000..7279347a
--- /dev/null
+++ b/examples/agent/crewAI/research_crew/.gitignore
@@ -0,0 +1,3 @@
+.env
+__pycache__/
+.DS_Store
diff --git a/examples/agent/crewAI/research_crew/README.md b/examples/agent/crewAI/research_crew/README.md
new file mode 100644
index 00000000..a1804635
--- /dev/null
+++ b/examples/agent/crewAI/research_crew/README.md
@@ -0,0 +1,111 @@
+# CrewAI and Splunk AO Cookbook
+
+This tutorial is a completed version of the [CrewAI quickstart](https://docs.crewai.com/en/quickstart) and adds the
+Splunk AO [CrewAIEventListener](https://docs.galileo.ai/sdk-api/python/reference/handlers/crewai/handler),
+an event handler implemented on top of OpenTelemetry (OTel). For more information, see
+Splunk AO’s [Add Splunk AO to a CrewAI Application](https://docs.galileo.ai/how-to-guides/third-party-integrations/add-galileo-to-crewai/add-galileo-to-crewai)
+how-to guide.
+
+Below you'll find concise setup steps, configuration notes, and a short primer on Splunk AO so you know why we add it and what it provides.
+
+## Resources
+
+The relevant guides:
+
+- [Add Splunk AO to CrewAI](https://docs.galileo.ai/how-to-guides/third-party-integrations/add-galileo-to-crewai/add-galileo-to-crewai)
+- [CrewAI quickstart](https://docs.crewai.com/en/guides/crews/first-crew)
+
+## What is Splunk AO?
+
+[Splunk AO](https://galileo.ai) is an observability and evaluation platform for generative AI agents. Integrating Splunk AO into a CrewAI project gives you:
+
+- Structured logging of prompts, agent decisions, and model responses.
+- Metrics, logs, and traces to evaluate agent performance and behavior over time.
+- A centralized dashboard for debugging, auditing, and running evaluations on AI agents.
+
+## Why add Splunk AO here?
+
+- Faster troubleshooting: quickly find which agent produced what output and why
+- Better evaluation: collect examples, compare model versions, and compute metrics
+- Reproducibility: attach metadata (env, model, prompt) to recorded runs for later analysis
+
+## Prerequisites
+
+- Python 3.10–3.13
+- `uv` installed and available.
+- [CrewAI CLI](https://docs.crewai.com/en/installation) installed and available.
+- A [Splunk AO API key](https://app.galileo.ai/)
+- A [Serper API Key](https://serper.dev/)
+- An [OpenAI Key](https://platform.openai.com/)
+
+## Quick setup
+
+Run these steps from the repository root.
+
+1. Clone and open the repo
+
+```zsh
+git clone https://github.com/rungalileo/sdk-examples.git
+cd sdk-examples/python/agent/crewAI/research_crew
+```
+
+2. Copy the .env.example and configure credentials
+
+```zsh
+cp .env.example .env
+```
+
+In addition to API keys, you’ll need to specify a Splunk AO project and log stream (e.g. SPLUNK_AO_PROJECT and SPLUNK_AO_LOG_STREAM). All CrewAI run data will be logged to this destination in Splunk AO. See
+[Understanding the Splunk AO Integration](#understanding-the-galileo-integration) for more detail.
+
+3. Install project dependencies into the active environment:
+
+```zsh
+crewai install
+```
+
+4. Run the Crew
+
+```zsh
+crewai run
+```
+
+## Understanding the Splunk AO Integration
+
+Splunk AO integrates with CrewAI by registering an event listener that captures Crew execution events (e.g., agent actions, tool calls, model responses) and forwards them to Splunk AO for observability and evaluation. Under the hood, this integration is built on OpenTelemetry (OTel) for standardized tracing and telemetry collection.
+
+### Register the event listener
+
+At the beginning of your run() function (or before starting the Crew), instantiate the Splunk AO event listener:
+
+```python
+
+def run():
+ # Create the event listener (registers itself with CrewAI)
+ CrewAIEventListener()
+
+ # The rest of your existing code goes here
+```
+
+This is instrumented in [main.py](research_crew/src/research_crew/main.py).
+
+### What this does
+
+Creating a CrewAIEventListener() instance is all that’s required to enable Splunk AO for a CrewAI run. When instantiated, the listener:
+
+- Automatically registers itself with CrewAI
+- Uses OpenTelemetry (OTel) to instrument Crew execution events
+- Reads Splunk AO configuration from environment variables
+- Logs all run data to the Splunk AO project and log stream specified by
+ `SPLUNK_AO_PROJECT` and `SPLUNK_AO_LOG_STREAM`
+
+No additional configuration or code changes are required. All data from this run is logged to the Splunk AO project and log stream specified by your environment configuration (for example, SPLUNK_AO_PROJECT and SPLUNK_AO_LOG_STREAM).
+
+## CrewAI Support
+
+For support, questions, or feedback regarding the ResearchCrew Crew or crewAI.
+
+- Visit the [CrewAI documentation](https://docs.crewai.com)
+- Reach out to CrewAI through their [GitHub repository](https://github.com/joaomdmoura/crewai)
+- [Join the CrewAI Discord](https://discord.com/invite/X4JWnZnxPb)
+- [Chat with the CrewAI docs](https://chatg.pt/DWjSBZn)
diff --git a/examples/agent/crewAI/research_crew/knowledge/user_preference.txt b/examples/agent/crewAI/research_crew/knowledge/user_preference.txt
new file mode 100644
index 00000000..dd63a17b
--- /dev/null
+++ b/examples/agent/crewAI/research_crew/knowledge/user_preference.txt
@@ -0,0 +1,4 @@
+User name is John Doe.
+User is an AI Engineer.
+User is interested in AI Agents.
+User is based in San Francisco, California.
diff --git a/examples/agent/crewAI/research_crew/output/report.md b/examples/agent/crewAI/research_crew/output/report.md
new file mode 100644
index 00000000..f909fcac
--- /dev/null
+++ b/examples/agent/crewAI/research_crew/output/report.md
@@ -0,0 +1,86 @@
+---
+
+# Comprehensive Report on Artificial Intelligence in Healthcare
+
+**Executive Summary:**
+Artificial Intelligence (AI) is transforming the healthcare industry by enhancing diagnostic accuracy, revolutionizing treatment personalization, and improving operational efficiency. This report analyzes key concepts, historical developments, challenges, and opportunities associated with AI in healthcare. It also highlights prominent case studies and explores potential future developments. By examining current trends and future potential, this report provides a comprehensive perspective on AI's transformative role in the healthcare sector.
+
+---
+
+## 1. Key Concepts and Definitions
+
+**Artificial Intelligence in Healthcare:**
+AI in healthcare entails the use of machine learning algorithms and software to emulate human cognition in analyzing, interpreting, and understanding complex medical and health data. It aims to provide solutions that enhance clinical practices and outcomes.
+
+**Machine Learning:**
+A critical subset of AI, machine learning involves algorithms that empower computers to learn from new data and make informed decisions without human intervention. Its applications include predictive analytics and pattern recognition in patient data.
+
+**Natural Language Processing:**
+Natural Language Processing (NLP) is the AI technology that enables machines to understand and generate human language. In healthcare, NLP is instrumental in augmenting clinical documentation and managing electronic health records.
+
+_References:_
+- [NIH Overview of AI in Medicine](https://pmc.ncbi.nlm.nih.gov/articles/PMC6691444/).
+- [Arm Glossary on AI in Healthcare](https://www.arm.com/glossary/ai-in-healthcare).
+
+---
+
+## 2. Historical Development and Recent Trends
+
+**Development Timeline:**
+The integration of AI in healthcare began in the 1960s. Its journey saw significant advancements with the adoption of electronic health records and evolving data analytics capabilities, proving crucial in contemporary medical practices.
+
+**Current Trends:**
+AI currently plays a pivotal role in enhancing diagnostic accuracy, personalizing treatment, and optimizing healthcare operations. Emerging technological integrations have elevated its effectiveness in clinical workflows and patient management systems.
+
+_References:_
+- [National Library of Medicine Historical Review](https://pmc.ncbi.nlm.nih.gov/articles/PMC11122160/).
+- [Inferscience Milestones in AI](https://www.inferscience.com/10-milestones-in-the-history-of-ai-in-healthcare).
+
+---
+
+## 3. Major Challenges and Opportunities
+
+**Challenges:**
+The primary challenges faced include ethical considerations around data privacy and potential biases, the high initial investment costs, algorithmic accountability, and the complexities of integrating AI into existing healthcare frameworks.
+
+**Opportunities:**
+AI opens numerous opportunities, such as enhancing diagnostic processes, advancing predictive analytics, tailoring patient care, and accelerating drug discovery. These innovations promise to bolster clinical efficiency and patient outcomes.
+
+_References:_
+- [Forbes on AI Opportunities and Challenges](https://www.forbes.com/councils/forbesbusinesscouncil/2023/02/07/top-five-opportunities-and-challenges-of-ai-in-healthcare/).
+- [ScienceDirect on Ethical Implications](https://www.sciencedirect.com/science/article/pii/S1078143923004179).
+
+---
+
+## 4. Notable Applications or Case Studies
+
+**AI-Assisted Diagnostics:**
+AI applications, like Aidoc, facilitate radiology workflows by accurately predicting anomalies in medical imaging, significantly improving diagnostic precision.
+
+**Personalized Treatment Planning:**
+IBM Watson for Oncology exemplifies how AI can assist oncologists in customizing cancer treatment plans, thus illustrating AI's potential in personalizing healthcare strategies.
+
+_References:_
+- [VKTR AI Case Studies](https://www.vktr.com/ai-disruption/5-ai-case-studies-in-health-care/).
+- [Philips Real-World AI Applications](https://www.philips.com/a-w/about/news/archive/features/2022/20221124-10-real-world-examples-of-ai-in-healthcare.html).
+
+---
+
+## 5. Future Outlook and Potential Developments
+
+**Predictions:**
+AI is poised to revolutionize healthcare delivery through hybrid models that complement human decision-making with AI-powered insights, enhancing diagnostic speed and accuracy.
+
+**Growth Areas:**
+Future expansions in AI applications are anticipated in areas like preventive care, mental health support, and chronic disease management, which promise to redefine standard healthcare delivery models.
+
+_References:_
+- [Deloitte AI Future Insights](https://www.deloitte.com/us/en/Industries/life-sciences-health-care/articles/future-of-artificial-intelligence-in-health-care.html).
+- [International SOS AI Outlook](https://www.internationalsos.com/magazine/how-ai-is-transforming-the-future-of-healthcare).
+
+---
+
+**Conclusion:**
+AI is a transformative force in healthcare, promising improvements in diagnostic accuracy, treatment personalization, and operational efficiency. Overcoming the existing challenges, AI offers robust opportunities that can fundamentally reshape healthcare delivery. The ongoing advancements and integration of AI technologies are crucial for achieving future innovations in various sectors of healthcare.
+
+---
\ No newline at end of file
diff --git a/examples/agent/crewAI/research_crew/pyproject.toml b/examples/agent/crewAI/research_crew/pyproject.toml
new file mode 100644
index 00000000..9c46cbeb
--- /dev/null
+++ b/examples/agent/crewAI/research_crew/pyproject.toml
@@ -0,0 +1,31 @@
+[project]
+name = "research_crew"
+version = "0.1.0"
+description = "research_crew using crewAI"
+authors = [{ name = "Your Name", email = "you@example.com" }]
+requires-python = ">=3.10,<3.14"
+dependencies = [
+ "crewai[tools]>=0.203.1,<1.0.0",
+ "galileo",
+ "python-dotenv",
+]
+
+# Project-level runtime dependencies used by the Crew (added so users can
+# install them via the project's pyproject workflow instead of a separate
+# manual pip step)
+[project.optional-dependencies]
+extras = []
+
+[project.scripts]
+research_crew = "research_crew.main:run"
+run_crew = "research_crew.main:run"
+train = "research_crew.main:train"
+replay = "research_crew.main:replay"
+test = "research_crew.main:test"
+
+[build-system]
+requires = ["hatchling"]
+build-backend = "hatchling.build"
+
+[tool.crewai]
+type = "crew"
diff --git a/examples/agent/crewAI/research_crew/src/research_crew/__init__.py b/examples/agent/crewAI/research_crew/src/research_crew/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/examples/agent/crewAI/research_crew/src/research_crew/config/agents.yaml b/examples/agent/crewAI/research_crew/src/research_crew/config/agents.yaml
new file mode 100644
index 00000000..78baff7c
--- /dev/null
+++ b/examples/agent/crewAI/research_crew/src/research_crew/config/agents.yaml
@@ -0,0 +1,26 @@
+# src/research_crew/config/agents.yaml
+researcher:
+ role: >
+ Senior Research Specialist for {topic}
+ goal: >
+ Find comprehensive and accurate information about {topic}
+ with a focus on recent developments and key insights
+ backstory: >
+ You are an experienced research specialist with a talent for
+ finding relevant information from various sources. You excel at
+ organizing information in a clear and structured manner, making
+ complex topics accessible to others.
+ llm: openai/gpt-4o # e.g. openai/gpt-4o, google/gemini-2.0-flash, anthropic/claude...
+
+analyst:
+ role: >
+ Data Analyst and Report Writer for {topic}
+ goal: >
+ Analyze research findings and create a comprehensive, well-structured
+ report that presents insights in a clear and engaging way
+ backstory: >
+ You are a skilled analyst with a background in data interpretation
+ and technical writing. You have a talent for identifying patterns
+ and extracting meaningful insights from research data, then
+ communicating those insights effectively through well-crafted reports.
+ llm: openai/gpt-4o # e.g. openai/gpt-4o, google/gemini-2.0-flash, anthropic/claude...
\ No newline at end of file
diff --git a/examples/agent/crewAI/research_crew/src/research_crew/config/tasks.yaml b/examples/agent/crewAI/research_crew/src/research_crew/config/tasks.yaml
new file mode 100644
index 00000000..1713d24a
--- /dev/null
+++ b/examples/agent/crewAI/research_crew/src/research_crew/config/tasks.yaml
@@ -0,0 +1,34 @@
+# src/research_crew/config/tasks.yaml
+research_task:
+ description: >
+ Conduct thorough research on {topic}. Focus on:
+ 1. Key concepts and definitions
+ 2. Historical development and recent trends
+ 3. Major challenges and opportunities
+ 4. Notable applications or case studies
+ 5. Future outlook and potential developments
+
+ Make sure to organize your findings in a structured format with clear sections.
+ expected_output: >
+ A comprehensive research document with well-organized sections covering
+ all the requested aspects of {topic}. Include specific facts, figures,
+ and examples where relevant.
+ agent: researcher
+
+analysis_task:
+ description: >
+ Analyze the research findings and create a comprehensive report on {topic}.
+ Your report should:
+ 1. Begin with an executive summary
+ 2. Include all key information from the research
+ 3. Provide insightful analysis of trends and patterns
+ 4. Offer recommendations or future considerations
+ 5. Be formatted in a professional, easy-to-read style with clear headings
+ expected_output: >
+ A polished, professional report on {topic} that presents the research
+ findings with added analysis and insights. The report should be well-structured
+ with an executive summary, main sections, and conclusion.
+ agent: analyst
+ context:
+ - research_task
+ output_file: output/report.md
\ No newline at end of file
diff --git a/examples/agent/crewAI/research_crew/src/research_crew/crew.py b/examples/agent/crewAI/research_crew/src/research_crew/crew.py
new file mode 100644
index 00000000..b878e27d
--- /dev/null
+++ b/examples/agent/crewAI/research_crew/src/research_crew/crew.py
@@ -0,0 +1,40 @@
+# src/research_crew/crew.py
+from crewai import Agent, Crew, Process, Task
+from crewai.project import CrewBase, agent, crew, task
+from crewai_tools import SerperDevTool
+from crewai.agents.agent_builder.base_agent import BaseAgent
+from typing import List
+
+
+@CrewBase
+class ResearchCrew:
+ """Research crew for comprehensive topic analysis and reporting"""
+
+ agents: List[BaseAgent]
+ tasks: List[Task]
+
+ @agent
+ def researcher(self) -> Agent:
+ return Agent(config=self.agents_config["researcher"], verbose=True, tools=[SerperDevTool()]) # type: ignore[index]
+
+ @agent
+ def analyst(self) -> Agent:
+ return Agent(config=self.agents_config["analyst"], verbose=True) # type: ignore[index]
+
+ @task
+ def research_task(self) -> Task:
+ return Task(config=self.tasks_config["research_task"]) # type: ignore[index]
+
+ @task
+ def analysis_task(self) -> Task:
+ return Task(config=self.tasks_config["analysis_task"], output_file="output/report.md") # type: ignore[index]
+
+ @crew
+ def crew(self) -> Crew:
+ """Creates the research crew"""
+ return Crew(
+ agents=self.agents,
+ tasks=self.tasks,
+ process=Process.sequential,
+ verbose=True,
+ )
diff --git a/examples/agent/crewAI/research_crew/src/research_crew/main.py b/examples/agent/crewAI/research_crew/src/research_crew/main.py
new file mode 100644
index 00000000..ece1c5d8
--- /dev/null
+++ b/examples/agent/crewAI/research_crew/src/research_crew/main.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+# src/research_crew/main.py
+import os
+from research_crew.crew import ResearchCrew
+from dotenv import load_dotenv
+from splunk_ao.handlers.crewai.handler import CrewAIEventListener
+
+load_dotenv()
+
+# Create output directory if it doesn't exist
+os.makedirs("output", exist_ok=True)
+
+
+def run():
+ # Create the event listener for Splunk AO CrewAI integration
+ CrewAIEventListener()
+
+ """
+ Run the research crew.
+ """
+ inputs = {"topic": "Artificial Intelligence in Healthcare"}
+
+ # Create and run the crew
+ result = ResearchCrew().crew().kickoff(inputs=inputs)
+
+ # Print the result
+ print("\n\n=== FINAL REPORT ===\n\n")
+ print(result.raw)
+
+ print("\n\nReport has been saved to output/report.md")
+
+
+if __name__ == "__main__":
+ run()
diff --git a/examples/agent/crewAI/research_crew/src/research_crew/tools/__init__.py b/examples/agent/crewAI/research_crew/src/research_crew/tools/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/examples/agent/crewAI/research_crew/src/research_crew/tools/custom_tool.py b/examples/agent/crewAI/research_crew/src/research_crew/tools/custom_tool.py
new file mode 100644
index 00000000..08739e65
--- /dev/null
+++ b/examples/agent/crewAI/research_crew/src/research_crew/tools/custom_tool.py
@@ -0,0 +1,19 @@
+from crewai.tools import BaseTool
+from typing import Type
+from pydantic import BaseModel, Field
+
+
+class MyCustomToolInput(BaseModel):
+ """Input schema for MyCustomTool."""
+
+ argument: str = Field(..., description="Description of the argument.")
+
+
+class MyCustomTool(BaseTool):
+ name: str = "Name of my tool"
+ description: str = "Clear description for what this tool is useful for, your agent will need this information to use it."
+ args_schema: Type[BaseModel] = MyCustomToolInput
+
+ def _run(self, argument: str) -> str:
+ # Implementation goes here
+ return "this is an example of a tool output, ignore it and move along."
diff --git a/examples/agent/google-adk/README.md b/examples/agent/google-adk/README.md
new file mode 100644
index 00000000..388cb6d8
--- /dev/null
+++ b/examples/agent/google-adk/README.md
@@ -0,0 +1,55 @@
+# Google ADK + OpenTelemetry Example Project
+
+This is an example project demonstrating how to use Splunk AO with the Google ADK. This uses the simple [quickstart from the Google ADK documentation](https://google.github.io/adk-docs/get-started/python/#create-an-agent-project), and adds Splunk AO logging.
+
+## Getting Started
+
+To get started with this project, you'll need to have Python 3.10 or later installed. You can then install the required dependencies in a virtual environment:
+
+```bash
+pip install -r requirements.txt
+```
+
+## Configure environment variables
+
+You will need to configure environment variables to use this project. Copy the `.env.example` file to `.env`, then update the environment variables in the `.env` file with your Google and Splunk AO values:
+
+```ini
+# Gemini environment variables
+GOOGLE_GENAI_USE_VERTEXAI=0
+GOOGLE_API_KEY=
+
+# Splunk AO environment variables
+SPLUNK_AO_API_ENDPOINT=
+SPLUNK_AO_API_KEY=
+SPLUNK_AO_PROJECT=
+SPLUNK_AO_LOG_STREAM=
+```
+
+For the `SPLUNK_AO_API_ENDPOINT`, this is different to the console URL that you would normally use. If you are using `app.galileo.ai` for example, the endpoint is `https://api.galileo.ai/otel/traces`.
+
+See the [Splunk AO OTel and OpenInference documentation](https://docs.galileo.ai/sdk-api/third-party-integrations/opentelemetry-and-openinference) for more details.
+
+## Usage
+
+Once the dependencies are installed, you can run the example application using the `adk` command:
+
+```bash
+adk run my_agent
+```
+
+Traces will be captured and logged to Splunk AO.
+
+## Project Structure
+
+The project structure is as follows:
+
+```folder
+google-adk/
+├── my_agent/ # The main agent application
+│ ├── __init__.py
+│ ├── agent.py
+│ └── env.example # List of environment variables
+├── requirements.txt # Python project requirements
+└── README.md # Project documentation
+```
diff --git a/examples/agent/google-adk/my_agent/.env.example b/examples/agent/google-adk/my_agent/.env.example
new file mode 100644
index 00000000..dcf2904d
--- /dev/null
+++ b/examples/agent/google-adk/my_agent/.env.example
@@ -0,0 +1,14 @@
+GOOGLE_API_KEY="YOUR_GOOGLE_API_KEY"
+# Your Galileo API key
+GALILEO_API_KEY="YOUR_GALILEO_API_KEY"
+
+# Your Galileo project name
+GALILEO_PROJECT="google-adk"
+
+# The name of the Log stream you want to use for logging
+GALILEO_LOG_STREAM="google-adk-log-stream"
+
+# Provide texhe console url below if you are using a
+# custom deployment, and not using the free tier, or app.galileo.ai.
+# This will look something like “console.galileo.yourcompany.com”.
+# GALILEO_CONSOLE_URL="your-galileo-console-url"
\ No newline at end of file
diff --git a/examples/agent/google-adk/my_agent/__init__.py b/examples/agent/google-adk/my_agent/__init__.py
new file mode 100644
index 00000000..725e9ec3
--- /dev/null
+++ b/examples/agent/google-adk/my_agent/__init__.py
@@ -0,0 +1 @@
+from . import agent as agent
diff --git a/examples/agent/google-adk/my_agent/agent.py b/examples/agent/google-adk/my_agent/agent.py
new file mode 100644
index 00000000..438418cd
--- /dev/null
+++ b/examples/agent/google-adk/my_agent/agent.py
@@ -0,0 +1,36 @@
+"""Agent logic for the Google ADK example."""
+
+from dotenv import load_dotenv
+from opentelemetry.sdk import trace as trace_sdk
+from splunk_ao import otel
+from openinference.instrumentation.google_adk import GoogleADKInstrumentor
+from google.adk.agents.llm_agent import Agent
+
+load_dotenv()
+
+# Create tracer provider and register Splunk AO span processor
+tracer_provider = trace_sdk.TracerProvider()
+galileo_span_processor = otel.SplunkAOSpanProcessor()
+tracer_provider.add_span_processor(galileo_span_processor)
+
+# Instrument Google ADK with OpenInference (this captures inputs/outputs)
+GoogleADKInstrumentor().instrument(tracer_provider=tracer_provider)
+
+# ---------------------------------------------------------------------------
+# ADK agent definition (import after instrumentation is configured)
+# ---------------------------------------------------------------------------
+
+
+# Tool implementation
+def get_current_time(city: str) -> dict:
+ """Returns the current time in a specified city."""
+ return {"status": "success", "city": city, "time": "10:30 AM"}
+
+
+root_agent = Agent(
+ model="gemini-3-flash-preview",
+ name="root_agent",
+ description="Tells the current time in a specified city.",
+ instruction=("You are a helpful assistant that tells the current time in cities." "Use the 'get_current_time' tool for this purpose."),
+ tools=[get_current_time],
+)
diff --git a/examples/agent/google-adk/requirements.txt b/examples/agent/google-adk/requirements.txt
new file mode 100644
index 00000000..1e1570b4
--- /dev/null
+++ b/examples/agent/google-adk/requirements.txt
@@ -0,0 +1,4 @@
+google-adk
+openinference-instrumentation-google-adk
+python-dotenv
+galileo
\ No newline at end of file
diff --git a/examples/agent/langchain-agent/.env.example b/examples/agent/langchain-agent/.env.example
new file mode 100644
index 00000000..b54dde9d
--- /dev/null
+++ b/examples/agent/langchain-agent/.env.example
@@ -0,0 +1,9 @@
+# Galileo Environment Variables
+GALILEO_API_KEY=your-galileo-api-key # Your Galileo API key.
+GALILEO_PROJECT=your-galileo-project-name # Your Galileo project name.
+GALILEO_LOG_STREAM=your-galileo-log-stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# GALILEO_CONSOLE_URL=your-galileo-console-url # Optional if you are using a hosted version of Galileo
+
+OPENAI_API_KEY=your-openai-key-here
\ No newline at end of file
diff --git a/examples/agent/langchain-agent/00-tutorial/00-Getting-Started.md b/examples/agent/langchain-agent/00-tutorial/00-Getting-Started.md
new file mode 100644
index 00000000..492d83ef
--- /dev/null
+++ b/examples/agent/langchain-agent/00-tutorial/00-Getting-Started.md
@@ -0,0 +1,172 @@
+# Getting Started: Monitoring LangChain Agents with Splunk AO
+
+This guide will walk you through setting up a Python project that uses [LangChain](https://python.langchain.com/) to build an AI agent, and [Splunk AO](https://www.rungalileo.io/) to monitor and log your agent's activity.
+---
+
+## 1. Prerequisites
+
+- **Python 3.8+** installed on your system.
+- A Splunk AO account and API key (see [Splunk AO docs](https://docs.rungalileo.io/) for how to get one).
+- An OpenAI API key (for using OpenAI models with LangChain).
+
+---
+
+## 2. Install Required Packages
+
+Open a terminal, create a virtual environment and install the required packages:
+
+```sh
+python -m venv venv
+source venv/bin/activate
+pip install -r requirements.txt
+```
+
+- `langchain` and `langchain-openai` are for building and running the agent.
+- `python-dotenv` is for loading environment variables (API keys).
+- `galileo` is for Splunk AO monitoring.
+
+---
+
+## 3. Set Up Environment Variables
+
+Copy the existing `.env.example` file, and rename it to `.env` in your project directory.
+
+```
+SPLUNK_AO_API_KEY=your-splunk-ao-api-key # Your Splunk AO API key.
+SPLUNK_AO_PROJECT=your-splunk-ao-project-name # Your Splunk AO project name.
+SPLUNK_AO_LOG_STREAM=your-splunk-ao-log-stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# SPLUNK_AO_CONSOLE_URL=your-splunk-ao-console-url
+
+OPENAI_API_KEY=your-openai-api-key
+```
+
+- Replace `your-openai-api-key`, `your-splunk-ao-project-name`, and `your-splunk-ao-log-stream` with your actual values.
+- If you are using a custom deployment of Splunk AO, set `SPLUNK_AO_CONSOLE_URL` to the URL of your Splunk AO deployment.
+- This keeps your credentials secure and out of your code.
+
+---
+
+## 4. Create Your Agent Script
+
+Create a file called `main.py` and add the following code:
+
+```python
+from dotenv import load_dotenv
+from langchain.agents import initialize_agent, Tool
+from langchain.agents.agent_types import AgentType
+from langchain_openai import ChatOpenAI
+from langchain.tools import tool
+from splunk_ao import splunk_ao_context
+from splunk_ao.handlers.langchain import SplunkAOCallback
+import os
+
+# 1. Load environment variables (API keys)
+load_dotenv()
+
+# 2. Define a simple tool for the agent to use
+@tool
+def greet(name: str) -> str:
+ """Say hello to someone."""
+ return f"Hello, {name}! 👋"
+
+# 3. Set up Splunk AO monitoring context
+with splunk_ao_context(project="langchain-docs", log_stream="my_log_stream"):
+ # 4. Initialize the agent with the Splunk AO callback for monitoring
+ agent = initialize_agent(
+ tools=[greet],
+ llm=ChatOpenAI(model="gpt-4", temperature=0.7, callbacks=[SplunkAOCallback()]),
+ agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
+ verbose=True
+ )
+
+ # 5. Run the agent and print the response
+ if __name__ == "__main__":
+ result = agent.invoke({"input": "Say hello to Erin"})
+ print(f"\nAgent Response:\n{result}")
+```
+
+---
+
+### Explanation of Each Step
+
+1. **Load environment variables:**
+ This loads your API keys from the `.env` file so you don't have to hard-code them.
+
+2. **Define a tool:**
+ Tools are functions your agent can use. Here, we define a simple `greet` tool.
+
+3. **Set up Splunk AO context:**
+ The `splunk_ao_context` context manager ensures all logs are tagged with your chosen project and log stream in Splunk AO.
+
+4. **Initialize the agent:**
+ - The agent is set up with your tool, an OpenAI LLM, and the `SplunkAOCallback` for monitoring.
+ - The callback automatically logs all agent activity to Splunk AO.
+
+5. **Run the agent:**
+ - The agent is asked to "Say hello to Erin".
+ - The response is printed to your terminal.
+
+---
+
+## 5. Run Your Script
+
+In your terminal, run:
+
+```sh
+python main.py
+```
+
+You should see output like:
+
+```
+Agent Response:
+Hello, Erin! 👋
+```
+
+---
+
+## 6. View Logs in Splunk AO
+
+- Log in to your Splunk AO dashboard.
+- Navigate to the project (`langchain-docs`) and log stream (`my_log_stream`) you specified.
+- You should see logs for your agent run, including:
+ - The input prompt
+ - The agent's reasoning steps
+ - Tool usage
+ - The final answer
+
+---
+
+## 7. Troubleshooting
+
+- **No logs in Splunk AO?**
+ - Double-check your API keys and project/log stream names.
+ - Ensure your `.env` file is in the same directory as your script.
+- **Errors about traces not being concluded?**
+ - Make sure you are not using both the `@log` decorator and the `SplunkAOCallback` at the same time.
+ - Only use the `SplunkAOCallback` for agent monitoring.
+
+---
+
+## 8. Customizing Your Agent
+
+- **Add more tools:**
+ Define more functions with the `@tool` decorator and add them to the `tools` list.
+- **Change the model:**
+ Use a different OpenAI model by changing the `model` parameter in `ChatOpenAI`.
+- **Change the project/log stream:**
+ Update the values in `splunk_ao_context` to organize your logs.
+
+---
+
+## 9. Best Practices & Tips
+
+- **Use the Splunk AO context manager** to ensure logs are tagged correctly within the Splunk AO UI.
+- **Use environment variables** for all secrets and API keys.
+
+---
+
+You now have a fully working, observable LangChain agent with Splunk AO monitoring!
+If you want to add more features, track custom metrics, or troubleshoot, refer to the Splunk AO and LangChain documentation or reach out for support.
diff --git a/examples/agent/langchain-agent/main.py b/examples/agent/langchain-agent/main.py
new file mode 100644
index 00000000..5da1302a
--- /dev/null
+++ b/examples/agent/langchain-agent/main.py
@@ -0,0 +1,31 @@
+from dotenv import load_dotenv
+from langchain.agents import initialize_agent
+from langchain.agents.agent_types import AgentType
+from langchain_openai import ChatOpenAI
+from langchain.tools import tool
+from splunk_ao import splunk_ao_context
+from splunk_ao.handlers.langchain import SplunkAOCallback
+
+# Load environment variables (e.g., API keys)
+load_dotenv()
+
+
+# Define a tool for the agent to use
+@tool
+def greet(name: str) -> str:
+ """Say hello to someone."""
+ return f"Hello, {name}! 👋"
+
+
+# Use the Splunk AO context manager to specify project and log stream
+with splunk_ao_context(project="langchain-docs", log_stream="my_log_stream"):
+ agent = initialize_agent(
+ tools=[greet],
+ llm=ChatOpenAI(model="gpt-4", temperature=0.7, callbacks=[SplunkAOCallback()]),
+ agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
+ verbose=True,
+ )
+
+ if __name__ == "__main__":
+ result = agent.invoke({"input": "Say hello to Erin"})
+ print(f"\nAgent Response:\n{result}")
diff --git a/examples/agent/langchain-agent/requirements.txt b/examples/agent/langchain-agent/requirements.txt
new file mode 100644
index 00000000..05b1e1d4
--- /dev/null
+++ b/examples/agent/langchain-agent/requirements.txt
@@ -0,0 +1,6 @@
+
+openai
+langchain
+langchain-openai
+galileo
+
diff --git a/examples/agent/langchain-middleware/.env.example b/examples/agent/langchain-middleware/.env.example
new file mode 100644
index 00000000..9460c823
--- /dev/null
+++ b/examples/agent/langchain-middleware/.env.example
@@ -0,0 +1,9 @@
+# Galileo Environment Variables
+GALILEO_API_KEY=your-galileo-api-key # Your Galileo API key.
+GALILEO_PROJECT=your-galileo-project-name # Your Galileo project name.
+GALILEO_LOG_STREAM=your-galileo-log-stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# GALILEO_CONSOLE_URL=your-galileo-console-url # Optional if you are using a hosted version of Galileo
+
+OPENAI_API_KEY=your-openai-key-here
diff --git a/examples/agent/langchain-middleware/README.md b/examples/agent/langchain-middleware/README.md
new file mode 100644
index 00000000..29595375
--- /dev/null
+++ b/examples/agent/langchain-middleware/README.md
@@ -0,0 +1,63 @@
+# LangChain Middleware Example
+
+This example demonstrates how to use `SplunkAOMiddleware` to automatically log LangChain agent executions without manual callback setup.
+
+## Overview
+
+`SplunkAOMiddleware` provides drop-in logging for LangGraph agents. It automatically captures:
+
+- Agent lifecycle events (start/completion)
+- Model calls with prompts, responses, and metadata
+- Tool calls with function names, arguments, and outputs
+
+## Setup
+
+1. Install dependencies:
+
+```bash
+pip install -r requirements.txt
+```
+
+1. Configure environment variables:
+
+```bash
+cp .env.example .env
+# Edit .env with your API keys
+```
+
+## Running the Example
+
+```bash
+python main.py
+```
+
+The agent will:
+
+1. Create a LangChain agent with two tools (weather and stock price)
+2. Invoke the agent with a question requiring both tools. Specifically, ""What's the weather like in San Francisco and what's the current stock price of Apple?"
+3. Automatically log all interactions to Splunk AO using middleware
+
+## What Gets Logged
+
+The middleware creates a hierarchical trace with:
+
+- **Agent node**: Tracks overall execution with input/output state
+- **LLM nodes**: Logs each model call with prompts, responses, and timing
+- **Tool nodes**: Records tool invocations with arguments and outputs
+
+## Key Features
+
+- **Zero configuration**: Add middleware to your agent and it works automatically
+- **Async support**: Works seamlessly with both sync and async execution
+- **Flexible**: Can use custom loggers and control trace management
+- **Comprehensive**: Captures all relevant execution details
+
+## Comparison with Callbacks
+
+| Feature | SplunkAOMiddleware | SplunkAOCallback |
+| ---------- | ---------------------- | ---------------------- |
+| Setup | Add to middleware list | Pass to each component |
+| Complexity | Simple | Manual setup required |
+| Best for | LangGraph agents | Complex LangChain apps |
+
+For more details, see the [middleware documentation](https://docs.galileo.ai/sdk-api/third-party-integrations/langchain/middleware).
diff --git a/examples/agent/langchain-middleware/main.py b/examples/agent/langchain-middleware/main.py
new file mode 100644
index 00000000..a50a29a9
--- /dev/null
+++ b/examples/agent/langchain-middleware/main.py
@@ -0,0 +1,69 @@
+import json
+import os
+
+from dotenv import load_dotenv
+from splunk_ao import splunk_ao_context
+from splunk_ao.handlers.langchain.middleware import SplunkAOMiddleware
+from langchain.agents.factory import create_agent
+from langchain.tools import tool
+from langchain_core.messages import HumanMessage
+from langchain_openai import ChatOpenAI
+
+# Load environment variables (e.g., API keys)
+load_dotenv()
+
+# Initialize the OpenAI chat model that the agent will use for reasoning
+model = ChatOpenAI(
+ name="gpt-5",
+ api_key=os.getenv("OPENAI_API_KEY"), # type: ignore
+)
+
+
+# Define a tool that allows the agent to get weather information
+# The @tool decorator converts this function into a LangChain tool that the agent can use
+@tool
+def get_weather(location: str, unit: str = "fahrenheit") -> str:
+ """Get the current weather for a given location."""
+ # In a real application, this would call a weather API
+ # For demonstration, we return mock data
+ return json.dumps({"location": location, "temperature": 72, "unit": unit})
+
+
+# Define a tool that allows the agent to get stock price information
+@tool
+def get_stock_price(symbol: str) -> str:
+ """Get the current stock price for a given ticker symbol."""
+ # Mock stock prices for demonstration
+ prices = {"AAPL": 178.50, "GOOGL": 141.25, "MSFT": 378.90, "AMZN": 153.40}
+ price = prices.get(symbol.upper(), 100.00)
+ return json.dumps({"symbol": symbol.upper(), "price": price, "currency": "USD"})
+
+
+def main() -> None:
+ # Use the Splunk AO context manager to specify project and log stream
+ # All traces created within this context will be associated with this project
+ with splunk_ao_context(project=os.getenv("SPLUNK_AO_PROJECT", "langchain-middleware"), log_stream=os.getenv("SPLUNK_AO_LOG_STREAM", "agent_execution")):
+ # Create an agent with SplunkAOMiddleware for automatic logging
+ # SplunkAOMiddleware automatically captures:
+ # - Agent lifecycle events (start/completion)
+ # - Model calls (prompts, responses, metadata)
+ # - Tool calls (function names, arguments, outputs)
+ agent = create_agent(
+ model, # The LLM the agent uses for reasoning
+ tools=[get_weather, get_stock_price], # Available tools
+ middleware=[SplunkAOMiddleware()], # Add SplunkAOMiddleware for automatic logging
+ )
+
+ # Invoke the agent with a question that requires using both tools
+ # The agent will:
+ # 1. Understand it needs weather info for San Francisco
+ # 2. Call the get_weather tool
+ # 3. Understand it needs Apple's stock price
+ # 4. Call the get_stock_price tool
+ # 5. Synthesize the results into a coherent response
+ result = agent.invoke({"messages": [HumanMessage(content="What's the weather like in San Francisco and what's the current stock price of Apple?")]})
+ print(f"\nAgent Response:\n{result}")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/agent/langchain-middleware/requirements.txt b/examples/agent/langchain-middleware/requirements.txt
new file mode 100644
index 00000000..6b09d31c
--- /dev/null
+++ b/examples/agent/langchain-middleware/requirements.txt
@@ -0,0 +1,5 @@
+openai
+langchain
+langchain-openai
+galileo
+python-dotenv
diff --git a/examples/agent/langgraph-fsi-agent/README.md b/examples/agent/langgraph-fsi-agent/README.md
new file mode 100644
index 00000000..1a9cbac4
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/README.md
@@ -0,0 +1,190 @@
+# Splunk AO LangGraph multi-agent demo
+
+This demo app shows how to configure Splunk AO to monitor and evaluate a multi-agent app built using LangGraph.
+
+
+
+In this folder you will find 2 versions of the app:
+
+- A [before version](./before/) that contains the app without any evaluations
+- An [after version](./after/) that contains the app with evaluations
+
+To learn how to add evaluations, check out the [Add evaluations to a multi-agent LangGraph application cookbook](https://docs.galileo.ai/cookbooks/use-cases/multi-agent-langgraph/multi-agent-langgraph) in the Splunk AO documentation.
+
+## Overview of this app
+
+This app is a chatbot for the fictional financial services company, Brahe Bank. You can use the bot to ask about:
+
+- Information on the current credit card offers, and their terms and conditions
+- Information on your credit score (this is hard coded to 550)
+- More coming soon!
+
+### Tech stack
+
+This app uses:
+
+- LangGraph to orchestrate agents
+- Chainlit to provide a UI
+- Pinecone as a vector database
+
+### Agents
+
+This app has a number of agents, orchestrated by a supervisor agent.
+
+#### Credit card information agent
+
+This agent provides information on the available credit cards.
+
+```mermaid
+---
+config:
+ flowchart:
+ curve: linear
+---
+graph TD;
+ __start__([
Start
]):::first
+ agent(credit card information agent)
+ tools(tools)
+ pinecone_tool(pinecone retrieval tool)
+ __end__([End
]):::last
+ __start__ --> agent;
+ agent -.-> __end__;
+ agent -.-> tools;
+ tools --> agent;
+ tools -.-> pinecone_tool;
+ pinecone_tool --> tools;
+ classDef default fill:#f2f0ff,line-height:1.2
+ classDef first fill-opacity:0
+ classDef last fill:#bfb6fc
+```
+
+#### Credit score agent
+
+This agent provides information on a hard coded credit score, with is high enough for the Orbit credit card, but not enough for the Celestial credit card.
+
+```mermaid
+---
+config:
+ flowchart:
+ curve: linear
+---
+graph TD;
+ __start__([__start__
]):::first
+ agent(agent)
+ tools(tools)
+ __end__([__end__
]):::last
+ __start__ --> agent;
+ agent -.-> __end__;
+ agent -.-> tools;
+ tools --> agent;
+ tools -.-> credit_score_tool;
+ credit_score_tool --> tools;
+ classDef default fill:#f2f0ff,line-height:1.2
+ classDef first fill-opacity:0
+ classDef last fill:#bfb6fc
+```
+
+#### Supervisor agent
+
+```mermaid
+---
+config:
+ flowchart:
+ curve: linear
+---
+graph TD;
+ __start__([__start__
]):::first
+ brahe-bank-supervisor-agent(brahe-bank-supervisor-agent)
+ credit-card-agent(credit-card-agent)
+ credit-score-agent(credit-score-agent)
+ __end__([__end__
]):::last
+ __start__ --> brahe-bank-supervisor-agent;
+ brahe-bank-supervisor-agent -.-> __end__;
+ brahe-bank-supervisor-agent -.-> credit-card-agent;
+ brahe-bank-supervisor-agent -.-> credit-score-agent;
+ credit-card-agent --> brahe-bank-supervisor-agent;
+ credit-score-agent --> brahe-bank-supervisor-agent;
+ classDef default fill:#f2f0ff,line-height:1.2
+ classDef first fill-opacity:0
+ classDef last fill:#bfb6fc
+```
+
+## Setup
+
+To see traces in Splunk AO, you need to run the [after](./after/) version of the app.
+
+To run the app, you need the following:
+
+- [A Splunk AO account](https://app.galileo.ai/sign-up), with a project created
+- [A Pinecone account](https://www.pinecone.io)
+- [An OpenAI API Key](https://platform.openai.com/api-keys)
+
+### Configure the app
+
+1. Copy the `.env.example` file to `.env`
+1. Fill in the values
+
+ For the Splunk AO values, you MUST create the project up front, but the log stream does not need to be created, it will be created automatically
+
+### Install the dependencies
+
+You can install the dependencies into a virtual environment using `uv`.
+
+```bash
+uv sync --dev
+```
+
+### Upload data to Pinecone
+
+Pinecone is used to store documents that different agents can use. There is a helper script to create indexes and upload the documents.
+
+```bash
+python ./scripts/setup_pinecone.py
+```
+
+This will take a few seconds and a successful run should look like:
+
+```text
+Loading documents for credit-card-information folder...
+...
+✅ Document processing and upload complete!
+```
+
+### Launch the app
+
+To launch the app, you can use the `chainlit` package that you just installed:
+
+```bash
+chainlit run app.py -w
+```
+
+This will start the app, and launch it on [localhost:8000](http://localhost:8000). The `-w` flag will watch for code changes, and reload if these are made, so you avoid restarting the app if you make code changes.
+
+This project also includes a `launch.json` configured to debug the app in VS Code.
+
+## Evaluate the agents
+
+Once you have interacted with the app, traces will appear in Splunk AO. Log into the [Splunk AO console](https://app.galileo.ai), and you will see your traces.
+
+From there you can configure the metrics you are interested in. Once metrics are enabled, you can have more conversations to see the evaluations.
+
+## Evaluate the agents with a unit test
+
+This project also includes a unit test to run the chatbot with a set of defined prompts, evaluating the prompts for action advancement, action completion, tool selection quality, and tool errors, only passing the test if both metrics score an average of 100% (or 0% for tool errors) over all the entries in the dataset.
+
+This is run using the [Splunk AO experiments framework](https://docs.galileo.ai/concepts/experiments/overview) - allowing you to run any code as an experiment against a fixed dataset of prompts. This mechanism allows you to run AI applications, from simple to complex, under test conditions with a defined set of inputs. You can then use the results of evaluations run against your app to help with model selection or prompt engineering, as well as validating your application as part of a CI/CD pipeline.
+
+You can run the unit test by running the following command inside your virtual environment:
+
+```bash
+python -m pytest test.py
+```
+
+This will run the single test which will:
+
+- Look in your project for a dataset, creating it if it doesn't exist
+- Call the agent inside a call to `run_experiment`, passing each row from the dataset in as inputs
+- Poll the experiment until it has finished and the metrics are calculated
+- Check that all the metrics return 100% (or 0% for tool errors), failing if they do not
+
+To see the benefits of this unit test, after running it, check the insights in Splunk AO to fix up the agent system prompts. For example, the system prompt for the supervisor agent doesn't suggest using the credit score tool to answer questions on credit score.
diff --git a/examples/agent/langgraph-fsi-agent/after/.chainlit/config.toml b/examples/agent/langgraph-fsi-agent/after/.chainlit/config.toml
new file mode 100644
index 00000000..f748dbb8
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/.chainlit/config.toml
@@ -0,0 +1,120 @@
+[project]
+# Whether to enable telemetry (default: true). No personal data is collected.
+enable_telemetry = true
+
+
+# List of environment variables to be provided by each user to use the app.
+user_env = []
+
+# Duration (in seconds) during which the session is saved when the connection is lost
+session_timeout = 3600
+
+# Duration (in seconds) of the user session expiry
+user_session_timeout = 1296000 # 15 days
+
+# Enable third parties caching (e.g., LangChain cache)
+cache = false
+
+# Authorized origins
+allow_origins = ["*"]
+
+[features]
+# Process and display HTML in messages. This can be a security risk (see https://stackoverflow.com/questions/19603097/why-is-it-dangerous-to-render-user-generated-html-or-javascript)
+unsafe_allow_html = false
+
+# Process and display mathematical expressions. This can clash with "$" characters in messages.
+latex = false
+
+# Autoscroll new user messages at the top of the window
+user_message_autoscroll = true
+
+# Automatically tag threads with the current chat profile (if a chat profile is used)
+auto_tag_thread = true
+
+# Allow users to edit their own messages
+edit_message = true
+
+# Authorize users to spontaneously upload files with messages
+[features.spontaneous_file_upload]
+ enabled = true
+ # Define accepted file types using MIME types
+ # Examples:
+ # 1. For specific file types:
+ # accept = ["image/jpeg", "image/png", "application/pdf"]
+ # 2. For all files of certain type:
+ # accept = ["image/*", "audio/*", "video/*"]
+ # 3. For specific file extensions:
+ # accept = { "application/octet-stream" = [".xyz", ".pdb"] }
+ # Note: Using "*/*" is not recommended as it may cause browser warnings
+ accept = ["*/*"]
+ max_files = 20
+ max_size_mb = 500
+
+[features.audio]
+ # Sample rate of the audio
+ sample_rate = 24000
+
+[features.mcp.sse]
+ enabled = true
+
+[features.mcp.stdio]
+ enabled = true
+ # Only the executables in the allow list can be used for MCP stdio server.
+ # Only need the base name of the executable, e.g. "npx", not "/usr/bin/npx".
+ # Please don't comment this line for now, we need it to parse the executable name.
+ allowed_executables = [ "npx", "uvx" ]
+
+[UI]
+# Name of the assistant.
+name = "Assistant"
+
+# default_theme = "dark"
+
+# layout = "wide"
+
+# default_sidebar_state = "open"
+
+# Description of the assistant. This is used for HTML tags.
+# description = ""
+
+# Chain of Thought (CoT) display mode. Can be "hidden", "tool_call" or "full".
+cot = "full"
+
+# Specify a CSS file that can be used to customize the user interface.
+# The CSS file can be served from the public directory or via an external link.
+# custom_css = "/public/test.css"
+
+# Specify additional attributes for a custom CSS file
+# custom_css_attributes = "media=\"print\""
+
+# Specify a JavaScript file that can be used to customize the user interface.
+# The JavaScript file can be served from the public directory.
+# custom_js = "/public/test.js"
+
+# Specify additional attributes for custom JS file
+# custom_js_attributes = "async type = \"module\""
+
+# Custom login page image, relative to public directory or external URL
+# login_page_image = "/public/custom-background.jpg"
+
+# Custom login page image filter (Tailwind internal filters, no dark/light variants)
+# login_page_image_filter = "brightness-50 grayscale"
+# login_page_image_dark_filter = "contrast-200 blur-sm"
+
+# Specify a custom meta image url.
+# custom_meta_image_url = "https://chainlit-cloud.s3.eu-west-3.amazonaws.com/logo/chainlit_banner.png"
+
+# Specify a custom build directory for the frontend.
+# This can be used to customize the frontend code.
+# Be careful: If this is a relative path, it should not start with a slash.
+# custom_build = "./public/build"
+
+# Specify optional one or more custom links in the header.
+# [[UI.header_links]]
+# name = "Issues"
+# display_name = "Report Issue"
+# icon_url = "https://avatars.githubusercontent.com/u/128686189?s=200&v=4"
+# url = "https://github.com/Chainlit/chainlit/issues"
+
+[meta]
+generated_by = "2.5.5"
diff --git a/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/bn.json b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/bn.json
new file mode 100644
index 00000000..36c86764
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/bn.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u09ac\u09be\u09a4\u09bf\u09b2 \u0995\u09b0\u09c1\u09a8",
+ "confirm": "\u09a8\u09bf\u09b6\u09cd\u099a\u09bf\u09a4 \u0995\u09b0\u09c1\u09a8",
+ "continue": "\u099a\u09be\u09b2\u09bf\u09af\u09bc\u09c7 \u09af\u09be\u09a8",
+ "goBack": "\u09aa\u09bf\u099b\u09a8\u09c7 \u09af\u09be\u09a8",
+ "reset": "\u09b0\u09bf\u09b8\u09c7\u099f \u0995\u09b0\u09c1\u09a8",
+ "submit": "\u099c\u09ae\u09be \u09a6\u09bf\u09a8"
+ },
+ "status": {
+ "loading": "\u09b2\u09cb\u09a1 \u09b9\u099a\u09cd\u099b\u09c7...",
+ "error": {
+ "default": "\u098f\u0995\u099f\u09bf \u09a4\u09cd\u09b0\u09c1\u099f\u09bf \u0998\u099f\u09c7\u099b\u09c7",
+ "serverConnection": "\u09b8\u09be\u09b0\u09cd\u09ad\u09be\u09b0\u09c7\u09b0 \u09b8\u09be\u09a5\u09c7 \u09b8\u0982\u09af\u09cb\u0997 \u0995\u09b0\u09be \u09af\u09be\u099a\u09cd\u099b\u09c7 \u09a8\u09be"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u0985\u09cd\u09af\u09be\u09aa\u09cd\u09b2\u09bf\u0995\u09c7\u09b6\u09a8 \u09ac\u09cd\u09af\u09ac\u09b9\u09be\u09b0 \u0995\u09b0\u09a4\u09c7 \u09b2\u0997\u0987\u09a8 \u0995\u09b0\u09c1\u09a8",
+ "form": {
+ "email": {
+ "label": "\u0987\u09ae\u09c7\u0987\u09b2 \u09a0\u09bf\u0995\u09be\u09a8\u09be",
+ "required": "\u0987\u09ae\u09c7\u0987\u09b2 \u098f\u0995\u099f\u09bf \u0986\u09ac\u09b6\u09cd\u09af\u0995 \u0995\u09cd\u09b7\u09c7\u09a4\u09cd\u09b0"
+ },
+ "password": {
+ "label": "\u09aa\u09be\u09b8\u0993\u09af\u09bc\u09be\u09b0\u09cd\u09a1",
+ "required": "\u09aa\u09be\u09b8\u0993\u09af\u09bc\u09be\u09b0\u09cd\u09a1 \u098f\u0995\u099f\u09bf \u0986\u09ac\u09b6\u09cd\u09af\u0995 \u0995\u09cd\u09b7\u09c7\u09a4\u09cd\u09b0"
+ },
+ "actions": {
+ "signin": "\u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09c1\u09a8"
+ },
+ "alternativeText": {
+ "or": "\u0985\u09a5\u09ac\u09be"
+ }
+ },
+ "errors": {
+ "default": "\u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09be \u09b8\u09ae\u09cd\u09ad\u09ac \u09b9\u099a\u09cd\u099b\u09c7 \u09a8\u09be",
+ "signin": "\u0985\u09a8\u09cd\u09af \u098f\u0995\u099f\u09bf \u0985\u09cd\u09af\u09be\u0995\u09be\u0989\u09a8\u09cd\u099f \u09a6\u09bf\u09af\u09bc\u09c7 \u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09be\u09b0 \u099a\u09c7\u09b7\u09cd\u099f\u09be \u0995\u09b0\u09c1\u09a8",
+ "oauthSignin": "\u0985\u09a8\u09cd\u09af \u098f\u0995\u099f\u09bf \u0985\u09cd\u09af\u09be\u0995\u09be\u0989\u09a8\u09cd\u099f \u09a6\u09bf\u09af\u09bc\u09c7 \u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09be\u09b0 \u099a\u09c7\u09b7\u09cd\u099f\u09be \u0995\u09b0\u09c1\u09a8",
+ "redirectUriMismatch": "\u09b0\u09bf\u09a1\u09be\u0987\u09b0\u09c7\u0995\u09cd\u099f URI \u0993\u0986\u09a5 \u0985\u09cd\u09af\u09be\u09aa \u0995\u09a8\u09ab\u09bf\u0997\u09be\u09b0\u09c7\u09b6\u09a8\u09c7\u09b0 \u09b8\u09be\u09a5\u09c7 \u09ae\u09bf\u09b2\u099b\u09c7 \u09a8\u09be",
+ "oauthCallback": "\u0985\u09a8\u09cd\u09af \u098f\u0995\u099f\u09bf \u0985\u09cd\u09af\u09be\u0995\u09be\u0989\u09a8\u09cd\u099f \u09a6\u09bf\u09af\u09bc\u09c7 \u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09be\u09b0 \u099a\u09c7\u09b7\u09cd\u099f\u09be \u0995\u09b0\u09c1\u09a8",
+ "oauthCreateAccount": "\u0985\u09a8\u09cd\u09af \u098f\u0995\u099f\u09bf \u0985\u09cd\u09af\u09be\u0995\u09be\u0989\u09a8\u09cd\u099f \u09a6\u09bf\u09af\u09bc\u09c7 \u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09be\u09b0 \u099a\u09c7\u09b7\u09cd\u099f\u09be \u0995\u09b0\u09c1\u09a8",
+ "emailCreateAccount": "\u0985\u09a8\u09cd\u09af \u098f\u0995\u099f\u09bf \u0985\u09cd\u09af\u09be\u0995\u09be\u0989\u09a8\u09cd\u099f \u09a6\u09bf\u09af\u09bc\u09c7 \u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09be\u09b0 \u099a\u09c7\u09b7\u09cd\u099f\u09be \u0995\u09b0\u09c1\u09a8",
+ "callback": "\u0985\u09a8\u09cd\u09af \u098f\u0995\u099f\u09bf \u0985\u09cd\u09af\u09be\u0995\u09be\u0989\u09a8\u09cd\u099f \u09a6\u09bf\u09af\u09bc\u09c7 \u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09be\u09b0 \u099a\u09c7\u09b7\u09cd\u099f\u09be \u0995\u09b0\u09c1\u09a8",
+ "oauthAccountNotLinked": "\u0986\u09aa\u09a8\u09be\u09b0 \u09aa\u09b0\u09bf\u099a\u09af\u09bc \u09a8\u09bf\u09b6\u09cd\u099a\u09bf\u09a4 \u0995\u09b0\u09a4\u09c7, \u0986\u09aa\u09a8\u09bf \u09af\u09c7 \u0985\u09cd\u09af\u09be\u0995\u09be\u0989\u09a8\u09cd\u099f\u099f\u09bf \u09ae\u09c2\u09b2\u09a4 \u09ac\u09cd\u09af\u09ac\u09b9\u09be\u09b0 \u0995\u09b0\u09c7\u099b\u09bf\u09b2\u09c7\u09a8 \u09b8\u09c7\u099f\u09bf \u09a6\u09bf\u09af\u09bc\u09c7 \u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09c1\u09a8",
+ "emailSignin": "\u0987\u09ae\u09c7\u0987\u09b2 \u09aa\u09be\u09a0\u09be\u09a8\u09cb \u09af\u09be\u09af\u09bc\u09a8\u09bf",
+ "emailVerify": "\u0985\u09a8\u09c1\u0997\u09cd\u09b0\u09b9 \u0995\u09b0\u09c7 \u0986\u09aa\u09a8\u09be\u09b0 \u0987\u09ae\u09c7\u0987\u09b2 \u09af\u09be\u099a\u09be\u0987 \u0995\u09b0\u09c1\u09a8, \u098f\u0995\u099f\u09bf \u09a8\u09a4\u09c1\u09a8 \u0987\u09ae\u09c7\u0987\u09b2 \u09aa\u09be\u09a0\u09be\u09a8\u09cb \u09b9\u09af\u09bc\u09c7\u099b\u09c7",
+ "credentialsSignin": "\u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u09ac\u09cd\u09af\u09b0\u09cd\u09a5 \u09b9\u09af\u09bc\u09c7\u099b\u09c7\u0964 \u0986\u09aa\u09a8\u09be\u09b0 \u09a6\u09c7\u0993\u09af\u09bc\u09be \u09a4\u09a5\u09cd\u09af \u09b8\u09a0\u09bf\u0995 \u0995\u09bf\u09a8\u09be \u09af\u09be\u099a\u09be\u0987 \u0995\u09b0\u09c1\u09a8",
+ "sessionRequired": "\u098f\u0987 \u09aa\u09c3\u09b7\u09cd\u09a0\u09be \u09a6\u09c7\u0996\u09a4\u09c7 \u0985\u09a8\u09c1\u0997\u09cd\u09b0\u09b9 \u0995\u09b0\u09c7 \u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09c1\u09a8"
+ }
+ },
+ "provider": {
+ "continue": "{{provider}} \u09a6\u09bf\u09af\u09bc\u09c7 \u099a\u09be\u09b2\u09bf\u09af\u09bc\u09c7 \u09af\u09be\u09a8"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u0986\u09aa\u09a8\u09be\u09b0 \u09ac\u09be\u09b0\u09cd\u09a4\u09be \u098f\u0996\u09be\u09a8\u09c7 \u099f\u09be\u0987\u09aa \u0995\u09b0\u09c1\u09a8...",
+ "actions": {
+ "send": "\u09ac\u09be\u09b0\u09cd\u09a4\u09be \u09aa\u09be\u09a0\u09be\u09a8",
+ "stop": "\u0995\u09be\u099c \u09ac\u09a8\u09cd\u09a7 \u0995\u09b0\u09c1\u09a8",
+ "attachFiles": "\u09ab\u09be\u0987\u09b2 \u09b8\u0982\u09af\u09c1\u0995\u09cd\u09a4 \u0995\u09b0\u09c1\u09a8"
+ }
+ },
+ "speech": {
+ "start": "\u09b0\u09c7\u0995\u09b0\u09cd\u09a1\u09bf\u0982 \u09b6\u09c1\u09b0\u09c1 \u0995\u09b0\u09c1\u09a8",
+ "stop": "\u09b0\u09c7\u0995\u09b0\u09cd\u09a1\u09bf\u0982 \u09ac\u09a8\u09cd\u09a7 \u0995\u09b0\u09c1\u09a8",
+ "connecting": "\u09b8\u0982\u09af\u09cb\u0997 \u0995\u09b0\u09be \u09b9\u099a\u09cd\u099b\u09c7"
+ },
+ "fileUpload": {
+ "dragDrop": "\u098f\u0996\u09be\u09a8\u09c7 \u09ab\u09be\u0987\u09b2 \u099f\u09c7\u09a8\u09c7 \u0986\u09a8\u09c1\u09a8",
+ "browse": "\u09ab\u09be\u0987\u09b2 \u09ac\u09cd\u09b0\u09be\u0989\u099c \u0995\u09b0\u09c1\u09a8",
+ "sizeLimit": "\u09b8\u09c0\u09ae\u09be:",
+ "errors": {
+ "failed": "\u0986\u09aa\u09b2\u09cb\u09a1 \u09ac\u09cd\u09af\u09b0\u09cd\u09a5 \u09b9\u09af\u09bc\u09c7\u099b\u09c7",
+ "cancelled": "\u0986\u09aa\u09b2\u09cb\u09a1 \u09ac\u09be\u09a4\u09bf\u09b2 \u0995\u09b0\u09be \u09b9\u09af\u09bc\u09c7\u099b\u09c7"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u09ac\u09cd\u09af\u09ac\u09b9\u09be\u09b0 \u0995\u09b0\u099b\u09c7",
+ "used": "\u09ac\u09cd\u09af\u09ac\u09b9\u09c3\u09a4"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u0995\u09cd\u09b2\u09bf\u09aa\u09ac\u09cb\u09b0\u09cd\u09a1\u09c7 \u0995\u09aa\u09bf \u0995\u09b0\u09c1\u09a8",
+ "success": "\u0995\u09aa\u09bf \u0995\u09b0\u09be \u09b9\u09af\u09bc\u09c7\u099b\u09c7!"
+ }
+ },
+ "feedback": {
+ "positive": "\u09b8\u09b9\u09be\u09af\u09bc\u0995",
+ "negative": "\u09b8\u09b9\u09be\u09af\u09bc\u0995 \u09a8\u09af\u09bc",
+ "edit": "\u09aa\u09cd\u09b0\u09a4\u09bf\u0995\u09cd\u09b0\u09bf\u09af\u09bc\u09be \u09b8\u09ae\u09cd\u09aa\u09be\u09a6\u09a8\u09be \u0995\u09b0\u09c1\u09a8",
+ "dialog": {
+ "title": "\u09ae\u09a8\u09cd\u09a4\u09ac\u09cd\u09af \u09af\u09cb\u0997 \u0995\u09b0\u09c1\u09a8",
+ "submit": "\u09aa\u09cd\u09b0\u09a4\u09bf\u0995\u09cd\u09b0\u09bf\u09af\u09bc\u09be \u099c\u09ae\u09be \u09a6\u09bf\u09a8"
+ },
+ "status": {
+ "updating": "\u09b9\u09be\u09b2\u09a8\u09be\u0997\u09be\u09a6 \u0995\u09b0\u09be \u09b9\u099a\u09cd\u099b\u09c7",
+ "updated": "\u09aa\u09cd\u09b0\u09a4\u09bf\u0995\u09cd\u09b0\u09bf\u09af\u09bc\u09be \u09b9\u09be\u09b2\u09a8\u09be\u0997\u09be\u09a6 \u0995\u09b0\u09be \u09b9\u09af\u09bc\u09c7\u099b\u09c7"
+ }
+ }
+ },
+ "history": {
+ "title": "\u09b8\u09b0\u09cd\u09ac\u09b6\u09c7\u09b7 \u0987\u09a8\u09aa\u09c1\u099f",
+ "empty": "\u0995\u09cb\u09a8\u09cb \u09a4\u09a5\u09cd\u09af \u09a8\u09c7\u0987...",
+ "show": "\u0987\u09a4\u09bf\u09b9\u09be\u09b8 \u09a6\u09c7\u0996\u09c1\u09a8"
+ },
+ "settings": {
+ "title": "\u09b8\u09c7\u099f\u09bf\u0982\u09b8 \u09aa\u09cd\u09af\u09be\u09a8\u09c7\u09b2"
+ },
+ "watermark": "\u09a6\u09cd\u09ac\u09be\u09b0\u09be \u09a8\u09bf\u09b0\u09cd\u09ae\u09bf\u09a4"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u09aa\u09c2\u09b0\u09cd\u09ac\u09ac\u09b0\u09cd\u09a4\u09c0 \u099a\u09cd\u09af\u09be\u099f",
+ "filters": {
+ "search": "\u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u0986\u099c",
+ "yesterday": "\u0997\u09a4\u0995\u09be\u09b2",
+ "previous7days": "\u0997\u09a4 \u09ed \u09a6\u09bf\u09a8",
+ "previous30days": "\u0997\u09a4 \u09e9\u09e6 \u09a6\u09bf\u09a8"
+ },
+ "empty": "\u0995\u09cb\u09a8\u09cb \u09a5\u09cd\u09b0\u09c7\u09a1 \u09aa\u09be\u0993\u09af\u09bc\u09be \u09af\u09be\u09af\u09bc\u09a8\u09bf",
+ "actions": {
+ "close": "\u09b8\u09be\u0987\u09a1\u09ac\u09be\u09b0 \u09ac\u09a8\u09cd\u09a7 \u0995\u09b0\u09c1\u09a8",
+ "open": "\u09b8\u09be\u0987\u09a1\u09ac\u09be\u09b0 \u0996\u09c1\u09b2\u09c1\u09a8"
+ }
+ },
+ "thread": {
+ "untitled": "\u09b6\u09bf\u09b0\u09cb\u09a8\u09be\u09ae\u09b9\u09c0\u09a8 \u0986\u09b2\u09cb\u099a\u09a8\u09be",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u09ae\u09c1\u099b\u09c7 \u09ab\u09c7\u09b2\u09be \u09a8\u09bf\u09b6\u09cd\u099a\u09bf\u09a4 \u0995\u09b0\u09c1\u09a8",
+ "description": "\u098f\u099f\u09bf \u09a5\u09cd\u09b0\u09c7\u09a1 \u098f\u09ac\u0982 \u098f\u09b0 \u09ac\u09be\u09b0\u09cd\u09a4\u09be \u0993 \u0989\u09aa\u09be\u09a6\u09be\u09a8\u0997\u09c1\u09b2\u09bf \u09ae\u09c1\u099b\u09c7 \u09ab\u09c7\u09b2\u09ac\u09c7\u0964 \u098f\u0987 \u0995\u09be\u099c\u099f\u09bf \u09aa\u09c2\u09b0\u09cd\u09ac\u09be\u09ac\u09b8\u09cd\u09a5\u09be\u09af\u09bc \u09ab\u09c7\u09b0\u09be\u09a8\u09cb \u09af\u09be\u09ac\u09c7 \u09a8\u09be",
+ "success": "\u099a\u09cd\u09af\u09be\u099f \u09ae\u09c1\u099b\u09c7 \u09ab\u09c7\u09b2\u09be \u09b9\u09af\u09bc\u09c7\u099b\u09c7",
+ "inProgress": "\u099a\u09cd\u09af\u09be\u099f \u09ae\u09c1\u099b\u09c7 \u09ab\u09c7\u09b2\u09be \u09b9\u099a\u09cd\u099b\u09c7"
+ },
+ "rename": {
+ "title": "\u09a5\u09cd\u09b0\u09c7\u09a1\u09c7\u09b0 \u09a8\u09be\u09ae \u09aa\u09b0\u09bf\u09ac\u09b0\u09cd\u09a4\u09a8 \u0995\u09b0\u09c1\u09a8",
+ "description": "\u098f\u0987 \u09a5\u09cd\u09b0\u09c7\u09a1\u09c7\u09b0 \u099c\u09a8\u09cd\u09af \u098f\u0995\u099f\u09bf \u09a8\u09a4\u09c1\u09a8 \u09a8\u09be\u09ae \u09a6\u09bf\u09a8",
+ "form": {
+ "name": {
+ "label": "\u09a8\u09be\u09ae",
+ "placeholder": "\u09a8\u09a4\u09c1\u09a8 \u09a8\u09be\u09ae \u09b2\u09bf\u0996\u09c1\u09a8"
+ }
+ },
+ "success": "\u09a5\u09cd\u09b0\u09c7\u09a1\u09c7\u09b0 \u09a8\u09be\u09ae \u09aa\u09b0\u09bf\u09ac\u09b0\u09cd\u09a4\u09a8 \u0995\u09b0\u09be \u09b9\u09af\u09bc\u09c7\u099b\u09c7!",
+ "inProgress": "\u09a5\u09cd\u09b0\u09c7\u09a1\u09c7\u09b0 \u09a8\u09be\u09ae \u09aa\u09b0\u09bf\u09ac\u09b0\u09cd\u09a4\u09a8 \u0995\u09b0\u09be \u09b9\u099a\u09cd\u099b\u09c7"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u099a\u09cd\u09af\u09be\u099f",
+ "readme": "\u09b0\u09bf\u09a1\u09ae\u09bf",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u09a8\u09a4\u09c1\u09a8 \u099a\u09cd\u09af\u09be\u099f",
+ "dialog": {
+ "title": "\u09a8\u09a4\u09c1\u09a8 \u099a\u09cd\u09af\u09be\u099f \u09a4\u09c8\u09b0\u09bf \u0995\u09b0\u09c1\u09a8",
+ "description": "\u098f\u099f\u09bf \u0986\u09aa\u09a8\u09be\u09b0 \u09ac\u09b0\u09cd\u09a4\u09ae\u09be\u09a8 \u099a\u09cd\u09af\u09be\u099f \u0987\u09a4\u09bf\u09b9\u09be\u09b8 \u09ae\u09c1\u099b\u09c7 \u09ab\u09c7\u09b2\u09ac\u09c7\u0964 \u0986\u09aa\u09a8\u09bf \u0995\u09bf \u099a\u09be\u09b2\u09bf\u09af\u09bc\u09c7 \u09af\u09c7\u09a4\u09c7 \u099a\u09be\u09a8?",
+ "tooltip": "\u09a8\u09a4\u09c1\u09a8 \u099a\u09cd\u09af\u09be\u099f"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u09b8\u09c7\u099f\u09bf\u0982\u09b8",
+ "settingsKey": "S",
+ "apiKeys": "\u098f\u09aa\u09bf\u0986\u0987 \u0995\u09c0",
+ "logout": "\u09b2\u0997\u0986\u0989\u099f"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u09aa\u09cd\u09b0\u09af\u09bc\u09cb\u099c\u09a8\u09c0\u09af\u09bc \u098f\u09aa\u09bf\u0986\u0987 \u0995\u09c0",
+ "description": "\u098f\u0987 \u0985\u09cd\u09af\u09be\u09aa\u09cd\u09b2\u09bf\u0995\u09c7\u09b6\u09a8 \u09ac\u09cd\u09af\u09ac\u09b9\u09be\u09b0 \u0995\u09b0\u09a4\u09c7 \u09a8\u09bf\u09ae\u09cd\u09a8\u09b2\u09bf\u0996\u09bf\u09a4 \u098f\u09aa\u09bf\u0986\u0987 \u0995\u09c0 \u09aa\u09cd\u09b0\u09af\u09bc\u09cb\u099c\u09a8\u0964 \u0995\u09c0\u0997\u09c1\u09b2\u09bf \u0986\u09aa\u09a8\u09be\u09b0 \u09a1\u09bf\u09ad\u09be\u0987\u09b8\u09c7\u09b0 \u09b2\u09cb\u0995\u09be\u09b2 \u09b8\u09cd\u099f\u09cb\u09b0\u09c7\u099c\u09c7 \u09b8\u0982\u09b0\u0995\u09cd\u09b7\u09bf\u09a4 \u09a5\u09be\u0995\u09c7\u0964",
+ "success": {
+ "saved": "\u09b8\u09ab\u09b2\u09ad\u09be\u09ac\u09c7 \u09b8\u0982\u09b0\u0995\u09cd\u09b7\u09bf\u09a4 \u09b9\u09af\u09bc\u09c7\u099b\u09c7"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/en-US.json b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/en-US.json
new file mode 100644
index 00000000..87b8d747
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/en-US.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "Cancel",
+ "confirm": "Confirm",
+ "continue": "Continue",
+ "goBack": "Go Back",
+ "reset": "Reset",
+ "submit": "Submit"
+ },
+ "status": {
+ "loading": "Loading...",
+ "error": {
+ "default": "An error occurred",
+ "serverConnection": "Could not reach the server"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "Login to access the app",
+ "form": {
+ "email": {
+ "label": "Email address",
+ "required": "email is a required field"
+ },
+ "password": {
+ "label": "Password",
+ "required": "password is a required field"
+ },
+ "actions": {
+ "signin": "Sign In"
+ },
+ "alternativeText": {
+ "or": "OR"
+ }
+ },
+ "errors": {
+ "default": "Unable to sign in",
+ "signin": "Try signing in with a different account",
+ "oauthSignin": "Try signing in with a different account",
+ "redirectUriMismatch": "The redirect URI is not matching the oauth app configuration",
+ "oauthCallback": "Try signing in with a different account",
+ "oauthCreateAccount": "Try signing in with a different account",
+ "emailCreateAccount": "Try signing in with a different account",
+ "callback": "Try signing in with a different account",
+ "oauthAccountNotLinked": "To confirm your identity, sign in with the same account you used originally",
+ "emailSignin": "The e-mail could not be sent",
+ "emailVerify": "Please verify your email, a new email has been sent",
+ "credentialsSignin": "Sign in failed. Check the details you provided are correct",
+ "sessionRequired": "Please sign in to access this page"
+ }
+ },
+ "provider": {
+ "continue": "Continue with {{provider}}"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "Type your message here...",
+ "actions": {
+ "send": "Send message",
+ "stop": "Stop Task",
+ "attachFiles": "Attach files"
+ }
+ },
+ "speech": {
+ "start": "Start recording",
+ "stop": "Stop recording",
+ "connecting": "Connecting"
+ },
+ "fileUpload": {
+ "dragDrop": "Drag and drop files here",
+ "browse": "Browse Files",
+ "sizeLimit": "Limit:",
+ "errors": {
+ "failed": "Failed to upload",
+ "cancelled": "Cancelled upload of"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "Using",
+ "used": "Used"
+ },
+ "actions": {
+ "copy": {
+ "button": "Copy to clipboard",
+ "success": "Copied!"
+ }
+ },
+ "feedback": {
+ "positive": "Helpful",
+ "negative": "Not helpful",
+ "edit": "Edit feedback",
+ "dialog": {
+ "title": "Add a comment",
+ "submit": "Submit feedback"
+ },
+ "status": {
+ "updating": "Updating",
+ "updated": "Feedback updated"
+ }
+ }
+ },
+ "history": {
+ "title": "Last Inputs",
+ "empty": "Such empty...",
+ "show": "Show history"
+ },
+ "settings": {
+ "title": "Settings panel"
+ },
+ "watermark": "Built with"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "Past Chats",
+ "filters": {
+ "search": "Search",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "Today",
+ "yesterday": "Yesterday",
+ "previous7days": "Previous 7 days",
+ "previous30days": "Previous 30 days"
+ },
+ "empty": "No threads found",
+ "actions": {
+ "close": "Close sidebar",
+ "open": "Open sidebar"
+ }
+ },
+ "thread": {
+ "untitled": "Untitled Conversation",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "Confirm deletion",
+ "description": "This will delete the thread as well as its messages and elements. This action cannot be undone",
+ "success": "Chat deleted",
+ "inProgress": "Deleting chat"
+ },
+ "rename": {
+ "title": "Rename Thread",
+ "description": "Enter a new name for this thread",
+ "form": {
+ "name": {
+ "label": "Name",
+ "placeholder": "Enter new name"
+ }
+ },
+ "success": "Thread renamed!",
+ "inProgress": "Renaming thread"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "Chat",
+ "readme": "Readme",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "New Chat",
+ "dialog": {
+ "title": "Create New Chat",
+ "description": "This will clear your current chat history. Are you sure you want to continue?",
+ "tooltip": "New Chat"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "Settings",
+ "settingsKey": "S",
+ "apiKeys": "API Keys",
+ "logout": "Logout"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "Required API Keys",
+ "description": "To use this app, the following API keys are required. The keys are stored on your device's local storage.",
+ "success": {
+ "saved": "Saved successfully"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/gu.json b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/gu.json
new file mode 100644
index 00000000..6292b953
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/gu.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u0ab0\u0aa6 \u0a95\u0ab0\u0acb",
+ "confirm": "\u0aaa\u0ac1\u0ab7\u0acd\u0a9f\u0abf \u0a95\u0ab0\u0acb",
+ "continue": "\u0a9a\u0abe\u0ab2\u0ac1 \u0ab0\u0abe\u0a96\u0acb",
+ "goBack": "\u0aaa\u0abe\u0a9b\u0abe \u0a9c\u0abe\u0a93",
+ "reset": "\u0ab0\u0ac0\u0ab8\u0ac7\u0a9f \u0a95\u0ab0\u0acb",
+ "submit": "\u0ab8\u0aac\u0aae\u0abf\u0a9f \u0a95\u0ab0\u0acb"
+ },
+ "status": {
+ "loading": "\u0ab2\u0acb\u0aa1 \u0aa5\u0a88 \u0ab0\u0ab9\u0acd\u0aaf\u0ac1\u0a82 \u0a9b\u0ac7...",
+ "error": {
+ "default": "\u0a8f\u0a95 \u0aad\u0ac2\u0ab2 \u0aa5\u0a88",
+ "serverConnection": "\u0ab8\u0ab0\u0acd\u0ab5\u0ab0 \u0ab8\u0ac1\u0aa7\u0ac0 \u0aaa\u0ab9\u0acb\u0a82\u0a9a\u0ac0 \u0ab6\u0a95\u0abe\u0aaf\u0ac1\u0a82 \u0aa8\u0aa5\u0ac0"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u0a8f\u0aaa\u0acd\u0ab2\u0abf\u0a95\u0ac7\u0ab6\u0aa8 \u0a8d\u0a95\u0acd\u0ab8\u0ac7\u0ab8 \u0a95\u0ab0\u0ab5\u0abe \u0aae\u0abe\u0a9f\u0ac7 \u0ab2\u0ac9\u0a97\u0abf\u0aa8 \u0a95\u0ab0\u0acb",
+ "form": {
+ "email": {
+ "label": "\u0a88\u0aae\u0ac7\u0ab2 \u0a8f\u0aa1\u0acd\u0ab0\u0ac7\u0ab8",
+ "required": "\u0a88\u0aae\u0ac7\u0ab2 \u0a86\u0ab5\u0ab6\u0acd\u0aaf\u0a95 \u0a9b\u0ac7"
+ },
+ "password": {
+ "label": "\u0aaa\u0abe\u0ab8\u0ab5\u0ab0\u0acd\u0aa1",
+ "required": "\u0aaa\u0abe\u0ab8\u0ab5\u0ab0\u0acd\u0aa1 \u0a86\u0ab5\u0ab6\u0acd\u0aaf\u0a95 \u0a9b\u0ac7"
+ },
+ "actions": {
+ "signin": "\u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0acb"
+ },
+ "alternativeText": {
+ "or": "\u0a85\u0aa5\u0ab5\u0abe"
+ }
+ },
+ "errors": {
+ "default": "\u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0ac0 \u0ab6\u0a95\u0abe\u0aaf\u0ac1\u0a82 \u0aa8\u0aa5\u0ac0",
+ "signin": "\u0a85\u0ab2\u0a97 \u0a8f\u0a95\u0abe\u0a89\u0aa8\u0acd\u0a9f\u0aa5\u0ac0 \u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0ab5\u0abe\u0aa8\u0acb \u0aaa\u0acd\u0ab0\u0aaf\u0abe\u0ab8 \u0a95\u0ab0\u0acb",
+ "oauthSignin": "\u0a85\u0ab2\u0a97 \u0a8f\u0a95\u0abe\u0a89\u0aa8\u0acd\u0a9f\u0aa5\u0ac0 \u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0ab5\u0abe\u0aa8\u0acb \u0aaa\u0acd\u0ab0\u0aaf\u0abe\u0ab8 \u0a95\u0ab0\u0acb",
+ "redirectUriMismatch": "\u0ab0\u0ac0\u0aa1\u0abe\u0aaf\u0ab0\u0ac7\u0a95\u0acd\u0a9f URI oauth \u0a8d\u0aaa \u0a95\u0aa8\u0acd\u0aab\u0abf\u0a97\u0ab0\u0ac7\u0ab6\u0aa8 \u0ab8\u0abe\u0aa5\u0ac7 \u0aae\u0ac7\u0ab3 \u0a96\u0abe\u0aa4\u0acb \u0aa8\u0aa5\u0ac0",
+ "oauthCallback": "\u0a85\u0ab2\u0a97 \u0a8f\u0a95\u0abe\u0a89\u0aa8\u0acd\u0a9f\u0aa5\u0ac0 \u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0ab5\u0abe\u0aa8\u0acb \u0aaa\u0acd\u0ab0\u0aaf\u0abe\u0ab8 \u0a95\u0ab0\u0acb",
+ "oauthCreateAccount": "\u0a85\u0ab2\u0a97 \u0a8f\u0a95\u0abe\u0a89\u0aa8\u0acd\u0a9f\u0aa5\u0ac0 \u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0ab5\u0abe\u0aa8\u0acb \u0aaa\u0acd\u0ab0\u0aaf\u0abe\u0ab8 \u0a95\u0ab0\u0acb",
+ "emailCreateAccount": "\u0a85\u0ab2\u0a97 \u0a8f\u0a95\u0abe\u0a89\u0aa8\u0acd\u0a9f\u0aa5\u0ac0 \u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0ab5\u0abe\u0aa8\u0acb \u0aaa\u0acd\u0ab0\u0aaf\u0abe\u0ab8 \u0a95\u0ab0\u0acb",
+ "callback": "\u0a85\u0ab2\u0a97 \u0a8f\u0a95\u0abe\u0a89\u0aa8\u0acd\u0a9f\u0aa5\u0ac0 \u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0ab5\u0abe\u0aa8\u0acb \u0aaa\u0acd\u0ab0\u0aaf\u0abe\u0ab8 \u0a95\u0ab0\u0acb",
+ "oauthAccountNotLinked": "\u0aa4\u0aae\u0abe\u0ab0\u0ac0 \u0a93\u0ab3\u0a96\u0aa8\u0ac0 \u0aaa\u0ac1\u0ab7\u0acd\u0a9f\u0abf \u0a95\u0ab0\u0ab5\u0abe \u0aae\u0abe\u0a9f\u0ac7, \u0aae\u0ac2\u0ab3 \u0ab0\u0ac2\u0aaa\u0ac7 \u0ab5\u0abe\u0aaa\u0ab0\u0ac7\u0ab2\u0abe \u0a8f\u0a95\u0abe\u0a89\u0aa8\u0acd\u0a9f\u0aa5\u0ac0 \u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0acb",
+ "emailSignin": "\u0a88\u0aae\u0ac7\u0ab2 \u0aae\u0acb\u0a95\u0ab2\u0ac0 \u0ab6\u0a95\u0abe\u0aaf\u0acb \u0aa8\u0aa5\u0ac0",
+ "emailVerify": "\u0a95\u0ac3\u0aaa\u0abe \u0a95\u0ab0\u0ac0 \u0aa4\u0aae\u0abe\u0ab0\u0acb \u0a88\u0aae\u0ac7\u0ab2 \u0a9a\u0a95\u0abe\u0ab8\u0acb, \u0aa8\u0ab5\u0acb \u0a88\u0aae\u0ac7\u0ab2 \u0aae\u0acb\u0a95\u0ab2\u0ab5\u0abe\u0aae\u0abe\u0a82 \u0a86\u0ab5\u0acd\u0aaf\u0acb \u0a9b\u0ac7",
+ "credentialsSignin": "\u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0aa8\u0abf\u0ab7\u0acd\u0aab\u0ab3. \u0a86\u0aaa\u0ac7\u0ab2\u0ac0 \u0ab5\u0abf\u0a97\u0aa4\u0acb \u0ab8\u0abe\u0a9a\u0ac0 \u0a9b\u0ac7 \u0a95\u0ac7 \u0aa8\u0ab9\u0ac0\u0a82 \u0aa4\u0ac7 \u0a9a\u0a95\u0abe\u0ab8\u0acb",
+ "sessionRequired": "\u0a86 \u0aaa\u0ac7\u0a9c\u0aa8\u0ac7 \u0a8d\u0a95\u0acd\u0ab8\u0ac7\u0ab8 \u0a95\u0ab0\u0ab5\u0abe \u0aae\u0abe\u0a9f\u0ac7 \u0a95\u0ac3\u0aaa\u0abe \u0a95\u0ab0\u0ac0 \u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0acb"
+ }
+ },
+ "provider": {
+ "continue": "{{provider}} \u0ab8\u0abe\u0aa5\u0ac7 \u0a9a\u0abe\u0ab2\u0ac1 \u0ab0\u0abe\u0a96\u0acb"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u0a85\u0ab9\u0ac0\u0a82 \u0aa4\u0aae\u0abe\u0ab0\u0acb \u0ab8\u0a82\u0aa6\u0ac7\u0ab6 \u0ab2\u0a96\u0acb...",
+ "actions": {
+ "send": "\u0ab8\u0a82\u0aa6\u0ac7\u0ab6 \u0aae\u0acb\u0a95\u0ab2\u0acb",
+ "stop": "\u0a95\u0abe\u0ab0\u0acd\u0aaf \u0ab0\u0acb\u0a95\u0acb",
+ "attachFiles": "\u0aab\u0abe\u0a87\u0ab2\u0acd\u0ab8 \u0a9c\u0acb\u0aa1\u0acb"
+ }
+ },
+ "speech": {
+ "start": "\u0ab0\u0ac7\u0a95\u0acb\u0ab0\u0acd\u0aa1\u0abf\u0a82\u0a97 \u0ab6\u0ab0\u0ac2 \u0a95\u0ab0\u0acb",
+ "stop": "\u0ab0\u0ac7\u0a95\u0acb\u0ab0\u0acd\u0aa1\u0abf\u0a82\u0a97 \u0aac\u0a82\u0aa7 \u0a95\u0ab0\u0acb",
+ "connecting": "\u0a95\u0aa8\u0ac7\u0a95\u0acd\u0a9f \u0aa5\u0a88 \u0ab0\u0ab9\u0acd\u0aaf\u0ac1\u0a82 \u0a9b\u0ac7"
+ },
+ "fileUpload": {
+ "dragDrop": "\u0a85\u0ab9\u0ac0\u0a82 \u0aab\u0abe\u0a87\u0ab2\u0acd\u0ab8 \u0a96\u0ac7\u0a82\u0a9a\u0acb \u0a85\u0aa8\u0ac7 \u0a9b\u0acb\u0aa1\u0acb",
+ "browse": "\u0aab\u0abe\u0a87\u0ab2\u0acd\u0ab8 \u0aac\u0acd\u0ab0\u0abe\u0a89\u0a9d \u0a95\u0ab0\u0acb",
+ "sizeLimit": "\u0aae\u0ab0\u0acd\u0aaf\u0abe\u0aa6\u0abe:",
+ "errors": {
+ "failed": "\u0a85\u0aaa\u0ab2\u0acb\u0aa1 \u0a95\u0ab0\u0ab5\u0abe\u0aae\u0abe\u0a82 \u0aa8\u0abf\u0ab7\u0acd\u0aab\u0ab3",
+ "cancelled": "\u0a85\u0aaa\u0ab2\u0acb\u0aa1 \u0ab0\u0aa6 \u0a95\u0ab0\u0acd\u0aaf\u0ac1\u0a82"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u0ab5\u0abe\u0aaa\u0ab0\u0ac0 \u0ab0\u0ab9\u0acd\u0aaf\u0abe \u0a9b\u0ac7",
+ "used": "\u0ab5\u0aaa\u0ab0\u0abe\u0aaf\u0ac7\u0ab2"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u0a95\u0acd\u0ab2\u0abf\u0aaa\u0aac\u0acb\u0ab0\u0acd\u0aa1 \u0aaa\u0ab0 \u0a95\u0ac9\u0aaa\u0abf \u0a95\u0ab0\u0acb",
+ "success": "\u0a95\u0ac9\u0aaa\u0abf \u0aa5\u0aaf\u0ac1\u0a82!"
+ }
+ },
+ "feedback": {
+ "positive": "\u0a89\u0aaa\u0aaf\u0acb\u0a97\u0ac0",
+ "negative": "\u0aac\u0abf\u0aa8\u0a89\u0aaa\u0aaf\u0acb\u0a97\u0ac0",
+ "edit": "\u0aaa\u0acd\u0ab0\u0aa4\u0abf\u0ab8\u0abe\u0aa6 \u0ab8\u0a82\u0aaa\u0abe\u0aa6\u0abf\u0aa4 \u0a95\u0ab0\u0acb",
+ "dialog": {
+ "title": "\u0a9f\u0abf\u0aaa\u0acd\u0aaa\u0aa3\u0ac0 \u0a89\u0aae\u0ac7\u0ab0\u0acb",
+ "submit": "\u0aaa\u0acd\u0ab0\u0aa4\u0abf\u0ab8\u0abe\u0aa6 \u0ab8\u0aac\u0aae\u0abf\u0a9f \u0a95\u0ab0\u0acb"
+ },
+ "status": {
+ "updating": "\u0a85\u0aaa\u0aa1\u0ac7\u0a9f \u0aa5\u0a88 \u0ab0\u0ab9\u0acd\u0aaf\u0ac1\u0a82 \u0a9b\u0ac7",
+ "updated": "\u0aaa\u0acd\u0ab0\u0aa4\u0abf\u0ab8\u0abe\u0aa6 \u0a85\u0aaa\u0aa1\u0ac7\u0a9f \u0aa5\u0aaf\u0acb"
+ }
+ }
+ },
+ "history": {
+ "title": "\u0a9b\u0ac7\u0ab2\u0acd\u0ab2\u0abe \u0a87\u0aa8\u0aaa\u0ac1\u0a9f\u0acd\u0ab8",
+ "empty": "\u0a96\u0abe\u0ab2\u0ac0 \u0a9b\u0ac7...",
+ "show": "\u0a87\u0aa4\u0abf\u0ab9\u0abe\u0ab8 \u0aac\u0aa4\u0abe\u0ab5\u0acb"
+ },
+ "settings": {
+ "title": "\u0ab8\u0ac7\u0a9f\u0abf\u0a82\u0a97\u0acd\u0ab8 \u0aaa\u0ac7\u0aa8\u0ab2"
+ },
+ "watermark": "\u0ab8\u0abe\u0aa5\u0ac7 \u0aac\u0aa8\u0abe\u0ab5\u0ac7\u0ab2"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u0aaa\u0abe\u0a9b\u0ab2\u0ac0 \u0a9a\u0ac7\u0a9f\u0acd\u0ab8",
+ "filters": {
+ "search": "\u0ab6\u0acb\u0aa7\u0acb",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u0a86\u0a9c\u0ac7",
+ "yesterday": "\u0a97\u0a88\u0a95\u0abe\u0ab2\u0ac7",
+ "previous7days": "\u0aaa\u0abe\u0a9b\u0ab2\u0abe 7 \u0aa6\u0abf\u0ab5\u0ab8",
+ "previous30days": "\u0aaa\u0abe\u0a9b\u0ab2\u0abe 30 \u0aa6\u0abf\u0ab5\u0ab8"
+ },
+ "empty": "\u0a95\u0acb\u0a88 \u0aa5\u0acd\u0ab0\u0ac7\u0aa1\u0acd\u0ab8 \u0aae\u0ab3\u0acd\u0aaf\u0abe \u0aa8\u0aa5\u0ac0",
+ "actions": {
+ "close": "\u0ab8\u0abe\u0a87\u0aa1\u0aac\u0abe\u0ab0 \u0aac\u0a82\u0aa7 \u0a95\u0ab0\u0acb",
+ "open": "\u0ab8\u0abe\u0a87\u0aa1\u0aac\u0abe\u0ab0 \u0a96\u0acb\u0ab2\u0acb"
+ }
+ },
+ "thread": {
+ "untitled": "\u0ab6\u0ac0\u0ab0\u0acd\u0ab7\u0a95 \u0ab5\u0a97\u0ab0\u0aa8\u0ac0 \u0ab5\u0abe\u0aa4\u0a9a\u0ac0\u0aa4",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u0a95\u0abe\u0aa2\u0ac0 \u0aa8\u0abe\u0a96\u0ab5\u0abe\u0aa8\u0ac0 \u0aaa\u0ac1\u0ab7\u0acd\u0a9f\u0abf \u0a95\u0ab0\u0acb",
+ "description": "\u0a86 \u0aa5\u0acd\u0ab0\u0ac7\u0aa1 \u0a85\u0aa8\u0ac7 \u0aa4\u0ac7\u0aa8\u0abe \u0ab8\u0a82\u0aa6\u0ac7\u0ab6\u0abe\u0a93 \u0a85\u0aa8\u0ac7 \u0aa4\u0aa4\u0acd\u0ab5\u0acb\u0aa8\u0ac7 \u0a95\u0abe\u0aa2\u0ac0 \u0aa8\u0abe\u0a96\u0ab6\u0ac7. \u0a86 \u0a95\u0acd\u0ab0\u0abf\u0aaf\u0abe \u0aaa\u0abe\u0a9b\u0ac0 \u0aab\u0ac7\u0ab0\u0ab5\u0ac0 \u0ab6\u0a95\u0abe\u0ab6\u0ac7 \u0aa8\u0ab9\u0ac0\u0a82",
+ "success": "\u0a9a\u0ac7\u0a9f \u0a95\u0abe\u0aa2\u0ac0 \u0aa8\u0abe\u0a96\u0ac0",
+ "inProgress": "\u0a9a\u0ac7\u0a9f \u0a95\u0abe\u0aa2\u0ac0 \u0aa8\u0abe\u0a96\u0ac0 \u0ab0\u0ab9\u0acd\u0aaf\u0abe \u0a9b\u0ac0\u0a8f"
+ },
+ "rename": {
+ "title": "\u0aa5\u0acd\u0ab0\u0ac7\u0aa1\u0aa8\u0ac1\u0a82 \u0aa8\u0abe\u0aae \u0aac\u0aa6\u0ab2\u0acb",
+ "description": "\u0a86 \u0aa5\u0acd\u0ab0\u0ac7\u0aa1 \u0aae\u0abe\u0a9f\u0ac7 \u0aa8\u0ab5\u0ac1\u0a82 \u0aa8\u0abe\u0aae \u0aa6\u0abe\u0a96\u0ab2 \u0a95\u0ab0\u0acb",
+ "form": {
+ "name": {
+ "label": "\u0aa8\u0abe\u0aae",
+ "placeholder": "\u0aa8\u0ab5\u0ac1\u0a82 \u0aa8\u0abe\u0aae \u0aa6\u0abe\u0a96\u0ab2 \u0a95\u0ab0\u0acb"
+ }
+ },
+ "success": "\u0aa5\u0acd\u0ab0\u0ac7\u0aa1\u0aa8\u0ac1\u0a82 \u0aa8\u0abe\u0aae \u0aac\u0aa6\u0ab2\u0abe\u0aaf\u0ac1\u0a82!",
+ "inProgress": "\u0aa5\u0acd\u0ab0\u0ac7\u0aa1\u0aa8\u0ac1\u0a82 \u0aa8\u0abe\u0aae \u0aac\u0aa6\u0ab2\u0ac0 \u0ab0\u0ab9\u0acd\u0aaf\u0abe \u0a9b\u0ac0\u0a8f"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u0a9a\u0ac7\u0a9f",
+ "readme": "\u0ab5\u0abe\u0a82\u0a9a\u0acb",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u0aa8\u0ab5\u0ac0 \u0a9a\u0ac7\u0a9f",
+ "dialog": {
+ "title": "\u0aa8\u0ab5\u0ac0 \u0a9a\u0ac7\u0a9f \u0aac\u0aa8\u0abe\u0ab5\u0acb",
+ "description": "\u0a86 \u0aa4\u0aae\u0abe\u0ab0\u0acb \u0ab5\u0ab0\u0acd\u0aa4\u0aae\u0abe\u0aa8 \u0a9a\u0ac7\u0a9f \u0a87\u0aa4\u0abf\u0ab9\u0abe\u0ab8 \u0ab8\u0abe\u0aab \u0a95\u0ab0\u0ab6\u0ac7. \u0ab6\u0ac1\u0a82 \u0aa4\u0aae\u0ac7 \u0a9a\u0abe\u0ab2\u0ac1 \u0ab0\u0abe\u0a96\u0ab5\u0abe \u0aae\u0abe\u0a82\u0a97\u0acb \u0a9b\u0acb?",
+ "tooltip": "\u0aa8\u0ab5\u0ac0 \u0a9a\u0ac7\u0a9f"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u0ab8\u0ac7\u0a9f\u0abf\u0a82\u0a97\u0acd\u0ab8",
+ "settingsKey": "S",
+ "apiKeys": "API \u0a95\u0ac0",
+ "logout": "\u0ab2\u0ac9\u0a97\u0a86\u0a89\u0a9f"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u0a9c\u0ab0\u0ac2\u0ab0\u0ac0 API \u0a95\u0ac0",
+ "description": "\u0a86 \u0a8f\u0aaa\u0acd\u0ab2\u0abf\u0a95\u0ac7\u0ab6\u0aa8 \u0ab5\u0abe\u0aaa\u0ab0\u0ab5\u0abe \u0aae\u0abe\u0a9f\u0ac7, \u0aa8\u0ac0\u0a9a\u0ac7\u0aa8\u0ac0 API \u0a95\u0ac0 \u0a9c\u0ab0\u0ac2\u0ab0\u0ac0 \u0a9b\u0ac7. \u0a95\u0ac0 \u0aa4\u0aae\u0abe\u0ab0\u0abe \u0aa1\u0abf\u0ab5\u0abe\u0a87\u0ab8\u0aa8\u0abe \u0ab2\u0acb\u0a95\u0ab2 \u0ab8\u0acd\u0a9f\u0acb\u0ab0\u0ac7\u0a9c\u0aae\u0abe\u0a82 \u0ab8\u0a82\u0a97\u0acd\u0ab0\u0ab9\u0abf\u0aa4 \u0aa5\u0ab6\u0ac7.",
+ "success": {
+ "saved": "\u0ab8\u0aab\u0ab3\u0aa4\u0abe\u0aaa\u0ac2\u0ab0\u0acd\u0ab5\u0a95 \u0ab8\u0abe\u0a9a\u0ab5\u0acd\u0aaf\u0ac1\u0a82"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/he-IL.json b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/he-IL.json
new file mode 100644
index 00000000..fc076784
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/he-IL.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u05d1\u05d9\u05d8\u05d5\u05dc",
+ "confirm": "\u05d0\u05d9\u05e9\u05d5\u05e8",
+ "continue": "\u05d4\u05de\u05e9\u05da",
+ "goBack": "\u05d7\u05d6\u05d5\u05e8",
+ "reset": "\u05d0\u05d9\u05e4\u05d5\u05e1",
+ "submit": "\u05e9\u05dc\u05d7"
+ },
+ "status": {
+ "loading": "\u05d8\u05d5\u05e2\u05df...",
+ "error": {
+ "default": "\u05d0\u05d9\u05e8\u05e2\u05d4 \u05e9\u05d2\u05d9\u05d0\u05d4",
+ "serverConnection": "\u05dc\u05d0 \u05e0\u05d9\u05ea\u05df \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8 \u05dc\u05e9\u05e8\u05ea"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u05d4\u05ea\u05d7\u05d1\u05e8 \u05db\u05d3\u05d9 \u05dc\u05d2\u05e9\u05ea \u05dc\u05d0\u05e4\u05dc\u05d9\u05e7\u05e6\u05d9\u05d4",
+ "form": {
+ "email": {
+ "label": "\u05db\u05ea\u05d5\u05d1\u05ea \u05d0\u05d9\u05de\u05d9\u05d9\u05dc",
+ "required": "\u05e9\u05d3\u05d4 \u05d4\u05d0\u05d9\u05de\u05d9\u05d9\u05dc \u05d4\u05d5\u05d0 \u05e9\u05d3\u05d4 \u05d7\u05d5\u05d1\u05d4"
+ },
+ "password": {
+ "label": "\u05e1\u05d9\u05e1\u05de\u05d4",
+ "required": "\u05e9\u05d3\u05d4 \u05d4\u05e1\u05d9\u05e1\u05de\u05d4 \u05d4\u05d5\u05d0 \u05e9\u05d3\u05d4 \u05d7\u05d5\u05d1\u05d4"
+ },
+ "actions": {
+ "signin": "\u05d4\u05ea\u05d7\u05d1\u05e8"
+ },
+ "alternativeText": {
+ "or": "\u05d0\u05d5"
+ }
+ },
+ "errors": {
+ "default": "\u05dc\u05d0 \u05e0\u05d9\u05ea\u05df \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8",
+ "signin": "\u05e0\u05e1\u05d4 \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8 \u05e2\u05dd \u05d7\u05e9\u05d1\u05d5\u05df \u05d0\u05d7\u05e8",
+ "oauthSignin": "\u05e0\u05e1\u05d4 \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8 \u05e2\u05dd \u05d7\u05e9\u05d1\u05d5\u05df \u05d0\u05d7\u05e8",
+ "redirectUriMismatch": "\u05db\u05ea\u05d5\u05d1\u05ea \u05d4\u05d4\u05e4\u05e0\u05d9\u05d4 \u05d0\u05d9\u05e0\u05d4 \u05ea\u05d5\u05d0\u05de\u05ea \u05d0\u05ea \u05ea\u05e6\u05d5\u05e8\u05ea \u05d0\u05e4\u05dc\u05d9\u05e7\u05e6\u05d9\u05d9\u05ea OAuth",
+ "oauthCallback": "\u05e0\u05e1\u05d4 \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8 \u05e2\u05dd \u05d7\u05e9\u05d1\u05d5\u05df \u05d0\u05d7\u05e8",
+ "oauthCreateAccount": "\u05e0\u05e1\u05d4 \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8 \u05e2\u05dd \u05d7\u05e9\u05d1\u05d5\u05df \u05d0\u05d7\u05e8",
+ "emailCreateAccount": "\u05e0\u05e1\u05d4 \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8 \u05e2\u05dd \u05d7\u05e9\u05d1\u05d5\u05df \u05d0\u05d7\u05e8",
+ "callback": "\u05e0\u05e1\u05d4 \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8 \u05e2\u05dd \u05d7\u05e9\u05d1\u05d5\u05df \u05d0\u05d7\u05e8",
+ "oauthAccountNotLinked": "\u05db\u05d3\u05d9 \u05dc\u05d0\u05de\u05ea \u05d0\u05ea \u05d6\u05d4\u05d5\u05ea\u05da, \u05d4\u05ea\u05d7\u05d1\u05e8 \u05e2\u05dd \u05d0\u05d5\u05ea\u05d5 \u05d7\u05e9\u05d1\u05d5\u05df \u05d1\u05d5 \u05d4\u05e9\u05ea\u05de\u05e9\u05ea \u05d1\u05de\u05e7\u05d5\u05e8",
+ "emailSignin": "\u05dc\u05d0 \u05e0\u05d9\u05ea\u05df \u05d4\u05d9\u05d4 \u05dc\u05e9\u05dc\u05d5\u05d7 \u05d0\u05ea \u05d4\u05d0\u05d9\u05de\u05d9\u05d9\u05dc",
+ "emailVerify": "\u05d0\u05e0\u05d0 \u05d0\u05de\u05ea \u05d0\u05ea \u05d4\u05d0\u05d9\u05de\u05d9\u05d9\u05dc \u05e9\u05dc\u05da, \u05e0\u05e9\u05dc\u05d7 \u05d0\u05d9\u05de\u05d9\u05d9\u05dc \u05d7\u05d3\u05e9",
+ "credentialsSignin": "\u05d4\u05d4\u05ea\u05d7\u05d1\u05e8\u05d5\u05ea \u05e0\u05db\u05e9\u05dc\u05d4. \u05d1\u05d3\u05d5\u05e7 \u05e9\u05d4\u05e4\u05e8\u05d8\u05d9\u05dd \u05e9\u05d4\u05d6\u05e0\u05ea \u05e0\u05db\u05d5\u05e0\u05d9\u05dd",
+ "sessionRequired": "\u05d0\u05e0\u05d0 \u05d4\u05ea\u05d7\u05d1\u05e8 \u05db\u05d3\u05d9 \u05dc\u05d2\u05e9\u05ea \u05dc\u05d3\u05e3 \u05d6\u05d4"
+ }
+ },
+ "provider": {
+ "continue": "\u05d4\u05de\u05e9\u05da \u05e2\u05dd {{provider}}"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u05d4\u05e7\u05dc\u05d3 \u05d0\u05ea \u05d4\u05d4\u05d5\u05d3\u05e2\u05d4 \u05e9\u05dc\u05da \u05db\u05d0\u05df...",
+ "actions": {
+ "send": "\u05e9\u05dc\u05d7 \u05d4\u05d5\u05d3\u05e2\u05d4",
+ "stop": "\u05e2\u05e6\u05d5\u05e8 \u05de\u05e9\u05d9\u05de\u05d4",
+ "attachFiles": "\u05e6\u05e8\u05e3 \u05e7\u05d1\u05e6\u05d9\u05dd"
+ }
+ },
+ "speech": {
+ "start": "\u05d4\u05ea\u05d7\u05dc \u05d4\u05e7\u05dc\u05d8\u05d4",
+ "stop": "\u05e2\u05e6\u05d5\u05e8 \u05d4\u05e7\u05dc\u05d8\u05d4",
+ "connecting": "\u05de\u05ea\u05d7\u05d1\u05e8"
+ },
+ "fileUpload": {
+ "dragDrop": "\u05d2\u05e8\u05d5\u05e8 \u05d5\u05e9\u05d7\u05e8\u05e8 \u05e7\u05d1\u05e6\u05d9\u05dd \u05db\u05d0\u05df",
+ "browse": "\u05e2\u05d9\u05d9\u05df \u05d1\u05e7\u05d1\u05e6\u05d9\u05dd",
+ "sizeLimit": "\u05de\u05d2\u05d1\u05dc\u05d4:",
+ "errors": {
+ "failed": "\u05d4\u05e2\u05dc\u05d0\u05d4 \u05e0\u05db\u05e9\u05dc\u05d4",
+ "cancelled": "\u05d4\u05e2\u05dc\u05d0\u05d4 \u05d1\u05d5\u05d8\u05dc\u05d4 \u05e9\u05dc"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u05de\u05e9\u05ea\u05de\u05e9 \u05d1",
+ "used": "\u05d4\u05e9\u05ea\u05de\u05e9 \u05d1"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u05d4\u05e2\u05ea\u05e7 \u05dc\u05dc\u05d5\u05d7",
+ "success": "\u05d4\u05d5\u05e2\u05ea\u05e7!"
+ }
+ },
+ "feedback": {
+ "positive": "\u05de\u05d5\u05e2\u05d9\u05dc",
+ "negative": "\u05dc\u05d0 \u05de\u05d5\u05e2\u05d9\u05dc",
+ "edit": "\u05e2\u05e8\u05d5\u05da \u05de\u05e9\u05d5\u05d1",
+ "dialog": {
+ "title": "\u05d4\u05d5\u05e1\u05e3 \u05ea\u05d2\u05d5\u05d1\u05d4",
+ "submit": "\u05e9\u05dc\u05d7 \u05de\u05e9\u05d5\u05d1"
+ },
+ "status": {
+ "updating": "\u05de\u05e2\u05d3\u05db\u05df",
+ "updated": "\u05d4\u05de\u05e9\u05d5\u05d1 \u05e2\u05d5\u05d3\u05db\u05df"
+ }
+ }
+ },
+ "history": {
+ "title": "\u05e7\u05dc\u05d8\u05d9\u05dd \u05d0\u05d7\u05e8\u05d5\u05e0\u05d9\u05dd",
+ "empty": "\u05db\u05dc \u05db\u05da \u05e8\u05d9\u05e7...",
+ "show": "\u05d4\u05e6\u05d2 \u05d4\u05d9\u05e1\u05d8\u05d5\u05e8\u05d9\u05d4"
+ },
+ "settings": {
+ "title": "\u05e4\u05d0\u05e0\u05dc \u05d4\u05d2\u05d3\u05e8\u05d5\u05ea"
+ },
+ "watermark": "\u05e0\u05d1\u05e0\u05d4 \u05d1\u05d0\u05de\u05e6\u05e2\u05d5\u05ea"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u05e6'\u05d0\u05d8\u05d9\u05dd \u05e7\u05d5\u05d3\u05de\u05d9\u05dd",
+ "filters": {
+ "search": "\u05d7\u05d9\u05e4\u05d5\u05e9",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u05d4\u05d9\u05d5\u05dd",
+ "yesterday": "\u05d0\u05ea\u05de\u05d5\u05dc",
+ "previous7days": "7 \u05d9\u05de\u05d9\u05dd \u05d0\u05d7\u05e8\u05d5\u05e0\u05d9\u05dd",
+ "previous30days": "30 \u05d9\u05de\u05d9\u05dd \u05d0\u05d7\u05e8\u05d5\u05e0\u05d9\u05dd"
+ },
+ "empty": "\u05dc\u05d0 \u05e0\u05de\u05e6\u05d0\u05d5 \u05e9\u05d9\u05d7\u05d5\u05ea",
+ "actions": {
+ "close": "\u05e1\u05d2\u05d5\u05e8 \u05e1\u05e8\u05d2\u05dc \u05e6\u05d3",
+ "open": "\u05e4\u05ea\u05d7 \u05e1\u05e8\u05d2\u05dc \u05e6\u05d3"
+ }
+ },
+ "thread": {
+ "untitled": "\u05e9\u05d9\u05d7\u05d4 \u05dc\u05dc\u05d0 \u05db\u05d5\u05ea\u05e8\u05ea",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u05d0\u05e9\u05e8 \u05de\u05d7\u05d9\u05e7\u05d4",
+ "description": "\u05e4\u05e2\u05d5\u05dc\u05d4 \u05d6\u05d5 \u05ea\u05de\u05d7\u05e7 \u05d0\u05ea \u05d4\u05e9\u05d9\u05d7\u05d4 \u05d5\u05db\u05df \u05d0\u05ea \u05d4\u05d4\u05d5\u05d3\u05e2\u05d5\u05ea \u05d5\u05d4\u05d0\u05dc\u05de\u05e0\u05d8\u05d9\u05dd \u05e9\u05dc\u05d4. \u05dc\u05d0 \u05e0\u05d9\u05ea\u05df \u05dc\u05d1\u05d8\u05dc \u05e4\u05e2\u05d5\u05dc\u05d4 \u05d6\u05d5",
+ "success": "\u05d4\u05e6'\u05d0\u05d8 \u05e0\u05de\u05d7\u05e7",
+ "inProgress": "\u05de\u05d5\u05d7\u05e7 \u05e6'\u05d0\u05d8"
+ },
+ "rename": {
+ "title": "\u05e9\u05e0\u05d4 \u05e9\u05dd \u05e9\u05d9\u05d7\u05d4",
+ "description": "\u05d4\u05d6\u05df \u05e9\u05dd \u05d7\u05d3\u05e9 \u05dc\u05e9\u05d9\u05d7\u05d4 \u05d6\u05d5",
+ "form": {
+ "name": {
+ "label": "\u05e9\u05dd",
+ "placeholder": "\u05d4\u05d6\u05df \u05e9\u05dd \u05d7\u05d3\u05e9"
+ }
+ },
+ "success": "\u05e9\u05dd \u05d4\u05e9\u05d9\u05d7\u05d4 \u05e9\u05d5\u05e0\u05d4!",
+ "inProgress": "\u05de\u05e9\u05e0\u05d4 \u05e9\u05dd \u05e9\u05d9\u05d7\u05d4"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u05e6'\u05d0\u05d8",
+ "readme": "\u05e7\u05e8\u05d0 \u05d0\u05d5\u05ea\u05d9",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u05e6'\u05d0\u05d8 \u05d7\u05d3\u05e9",
+ "dialog": {
+ "title": "\u05e6\u05d5\u05e8 \u05e6'\u05d0\u05d8 \u05d7\u05d3\u05e9",
+ "description": "\u05e4\u05e2\u05d5\u05dc\u05d4 \u05d6\u05d5 \u05ea\u05e0\u05e7\u05d4 \u05d0\u05ea \u05d4\u05d9\u05e1\u05d8\u05d5\u05e8\u05d9\u05d9\u05ea \u05d4\u05e6'\u05d0\u05d8 \u05d4\u05e0\u05d5\u05db\u05d7\u05d9\u05ea \u05e9\u05dc\u05da. \u05d4\u05d0\u05dd \u05d0\u05ea\u05d4 \u05d1\u05d8\u05d5\u05d7 \u05e9\u05d1\u05e8\u05e6\u05d5\u05e0\u05da \u05dc\u05d4\u05de\u05e9\u05d9\u05da?",
+ "tooltip": "\u05e6'\u05d0\u05d8 \u05d7\u05d3\u05e9"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u05d4\u05d2\u05d3\u05e8\u05d5\u05ea",
+ "settingsKey": "\u05d4",
+ "apiKeys": "\u05de\u05e4\u05ea\u05d7\u05d5\u05ea API",
+ "logout": "\u05d4\u05ea\u05e0\u05ea\u05e7"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u05de\u05e4\u05ea\u05d7\u05d5\u05ea API \u05e0\u05d3\u05e8\u05e9\u05d9\u05dd",
+ "description": "\u05db\u05d3\u05d9 \u05dc\u05d4\u05e9\u05ea\u05de\u05e9 \u05d1\u05d0\u05e4\u05dc\u05d9\u05e7\u05e6\u05d9\u05d4 \u05d6\u05d5, \u05e0\u05d3\u05e8\u05e9\u05d9\u05dd \u05de\u05e4\u05ea\u05d7\u05d5\u05ea API \u05d4\u05d1\u05d0\u05d9\u05dd. \u05d4\u05de\u05e4\u05ea\u05d7\u05d5\u05ea \u05de\u05d0\u05d5\u05d7\u05e1\u05e0\u05d9\u05dd \u05d1\u05d0\u05d7\u05e1\u05d5\u05df \u05d4\u05de\u05e7\u05d5\u05de\u05d9 \u05e9\u05dc \u05d4\u05de\u05db\u05e9\u05d9\u05e8 \u05e9\u05dc\u05da.",
+ "success": {
+ "saved": "\u05e0\u05e9\u05de\u05e8 \u05d1\u05d4\u05e6\u05dc\u05d7\u05d4"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/hi.json b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/hi.json
new file mode 100644
index 00000000..d6acccb3
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/hi.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u0930\u0926\u094d\u0926 \u0915\u0930\u0947\u0902",
+ "confirm": "\u092a\u0941\u0937\u094d\u091f\u093f \u0915\u0930\u0947\u0902",
+ "continue": "\u091c\u093e\u0930\u0940 \u0930\u0916\u0947\u0902",
+ "goBack": "\u0935\u093e\u092a\u0938 \u091c\u093e\u090f\u0902",
+ "reset": "\u0930\u0940\u0938\u0947\u091f \u0915\u0930\u0947\u0902",
+ "submit": "\u091c\u092e\u093e \u0915\u0930\u0947\u0902"
+ },
+ "status": {
+ "loading": "\u0932\u094b\u0921 \u0939\u094b \u0930\u0939\u093e \u0939\u0948...",
+ "error": {
+ "default": "\u090f\u0915 \u0924\u094d\u0930\u0941\u091f\u093f \u0939\u0941\u0908",
+ "serverConnection": "\u0938\u0930\u094d\u0935\u0930 \u0938\u0947 \u0938\u0902\u092a\u0930\u094d\u0915 \u0928\u0939\u0940\u0902 \u0939\u094b \u092a\u093e \u0930\u0939\u093e"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u0910\u092a \u0915\u093e \u0909\u092a\u092f\u094b\u0917 \u0915\u0930\u0928\u0947 \u0915\u0947 \u0932\u093f\u090f \u0932\u0949\u0917\u093f\u0928 \u0915\u0930\u0947\u0902",
+ "form": {
+ "email": {
+ "label": "\u0908\u092e\u0947\u0932 \u092a\u0924\u093e",
+ "required": "\u0908\u092e\u0947\u0932 \u090f\u0915 \u0906\u0935\u0936\u094d\u092f\u0915 \u092b\u093c\u0940\u0932\u094d\u0921 \u0939\u0948"
+ },
+ "password": {
+ "label": "\u092a\u093e\u0938\u0935\u0930\u094d\u0921",
+ "required": "\u092a\u093e\u0938\u0935\u0930\u094d\u0921 \u090f\u0915 \u0906\u0935\u0936\u094d\u092f\u0915 \u092b\u093c\u0940\u0932\u094d\u0921 \u0939\u0948"
+ },
+ "actions": {
+ "signin": "\u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0947\u0902"
+ },
+ "alternativeText": {
+ "or": "\u092f\u093e"
+ }
+ },
+ "errors": {
+ "default": "\u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0928\u0947 \u092e\u0947\u0902 \u0905\u0938\u092e\u0930\u094d\u0925",
+ "signin": "\u0915\u093f\u0938\u0940 \u0926\u0942\u0938\u0930\u0947 \u0916\u093e\u0924\u0947 \u0938\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0928\u0947 \u0915\u093e \u092a\u094d\u0930\u092f\u093e\u0938 \u0915\u0930\u0947\u0902",
+ "oauthSignin": "\u0915\u093f\u0938\u0940 \u0926\u0942\u0938\u0930\u0947 \u0916\u093e\u0924\u0947 \u0938\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0928\u0947 \u0915\u093e \u092a\u094d\u0930\u092f\u093e\u0938 \u0915\u0930\u0947\u0902",
+ "redirectUriMismatch": "\u0930\u0940\u0921\u093e\u092f\u0930\u0947\u0915\u094d\u091f URI oauth \u0910\u092a \u0915\u0949\u0928\u094d\u092b\u093c\u093f\u0917\u0930\u0947\u0936\u0928 \u0938\u0947 \u092e\u0947\u0932 \u0928\u0939\u0940\u0902 \u0916\u093e \u0930\u0939\u093e",
+ "oauthCallback": "\u0915\u093f\u0938\u0940 \u0926\u0942\u0938\u0930\u0947 \u0916\u093e\u0924\u0947 \u0938\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0928\u0947 \u0915\u093e \u092a\u094d\u0930\u092f\u093e\u0938 \u0915\u0930\u0947\u0902",
+ "oauthCreateAccount": "\u0915\u093f\u0938\u0940 \u0926\u0942\u0938\u0930\u0947 \u0916\u093e\u0924\u0947 \u0938\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0928\u0947 \u0915\u093e \u092a\u094d\u0930\u092f\u093e\u0938 \u0915\u0930\u0947\u0902",
+ "emailCreateAccount": "\u0915\u093f\u0938\u0940 \u0926\u0942\u0938\u0930\u0947 \u0916\u093e\u0924\u0947 \u0938\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0928\u0947 \u0915\u093e \u092a\u094d\u0930\u092f\u093e\u0938 \u0915\u0930\u0947\u0902",
+ "callback": "\u0915\u093f\u0938\u0940 \u0926\u0942\u0938\u0930\u0947 \u0916\u093e\u0924\u0947 \u0938\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0928\u0947 \u0915\u093e \u092a\u094d\u0930\u092f\u093e\u0938 \u0915\u0930\u0947\u0902",
+ "oauthAccountNotLinked": "\u0905\u092a\u0928\u0940 \u092a\u0939\u091a\u093e\u0928 \u0915\u0940 \u092a\u0941\u0937\u094d\u091f\u093f \u0915\u0930\u0928\u0947 \u0915\u0947 \u0932\u093f\u090f, \u0909\u0938\u0940 \u0916\u093e\u0924\u0947 \u0938\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0947\u0902 \u091c\u093f\u0938\u0915\u093e \u0909\u092a\u092f\u094b\u0917 \u0906\u092a\u0928\u0947 \u092e\u0942\u0932 \u0930\u0942\u092a \u0938\u0947 \u0915\u093f\u092f\u093e \u0925\u093e",
+ "emailSignin": "\u0908\u092e\u0947\u0932 \u0928\u0939\u0940\u0902 \u092d\u0947\u091c\u093e \u091c\u093e \u0938\u0915\u093e",
+ "emailVerify": "\u0915\u0943\u092a\u092f\u093e \u0905\u092a\u0928\u093e \u0908\u092e\u0947\u0932 \u0938\u0924\u094d\u092f\u093e\u092a\u093f\u0924 \u0915\u0930\u0947\u0902, \u090f\u0915 \u0928\u092f\u093e \u0908\u092e\u0947\u0932 \u092d\u0947\u091c\u093e \u0917\u092f\u093e \u0939\u0948",
+ "credentialsSignin": "\u0938\u093e\u0907\u0928 \u0907\u0928 \u0935\u093f\u092b\u0932\u0964 \u0906\u092a\u0915\u0947 \u0926\u094d\u0935\u093e\u0930\u093e \u092a\u094d\u0930\u0926\u093e\u0928 \u0915\u093f\u090f \u0917\u090f \u0935\u093f\u0935\u0930\u0923 \u0915\u0940 \u091c\u093e\u0902\u091a \u0915\u0930\u0947\u0902",
+ "sessionRequired": "\u0907\u0938 \u092a\u0943\u0937\u094d\u0920 \u0924\u0915 \u092a\u0939\u0941\u0902\u091a\u0928\u0947 \u0915\u0947 \u0932\u093f\u090f \u0915\u0943\u092a\u092f\u093e \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0947\u0902"
+ }
+ },
+ "provider": {
+ "continue": "{{provider}} \u0915\u0947 \u0938\u093e\u0925 \u091c\u093e\u0930\u0940 \u0930\u0916\u0947\u0902"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u0905\u092a\u0928\u093e \u0938\u0902\u0926\u0947\u0936 \u092f\u0939\u093e\u0902 \u091f\u093e\u0907\u092a \u0915\u0930\u0947\u0902...",
+ "actions": {
+ "send": "\u0938\u0902\u0926\u0947\u0936 \u092d\u0947\u091c\u0947\u0902",
+ "stop": "\u0915\u093e\u0930\u094d\u092f \u0930\u094b\u0915\u0947\u0902",
+ "attachFiles": "\u092b\u093c\u093e\u0907\u0932\u0947\u0902 \u0938\u0902\u0932\u0917\u094d\u0928 \u0915\u0930\u0947\u0902"
+ }
+ },
+ "speech": {
+ "start": "\u0930\u093f\u0915\u0949\u0930\u094d\u0921\u093f\u0902\u0917 \u0936\u0941\u0930\u0942 \u0915\u0930\u0947\u0902",
+ "stop": "\u0930\u093f\u0915\u0949\u0930\u094d\u0921\u093f\u0902\u0917 \u0930\u094b\u0915\u0947\u0902",
+ "connecting": "\u0915\u0928\u0947\u0915\u094d\u091f \u0939\u094b \u0930\u0939\u093e \u0939\u0948"
+ },
+ "fileUpload": {
+ "dragDrop": "\u092b\u093c\u093e\u0907\u0932\u094b\u0902 \u0915\u094b \u092f\u0939\u093e\u0902 \u0916\u0940\u0902\u091a\u0947\u0902 \u0914\u0930 \u091b\u094b\u0921\u093c\u0947\u0902",
+ "browse": "\u092b\u093c\u093e\u0907\u0932\u0947\u0902 \u092c\u094d\u0930\u093e\u0909\u091c\u093c \u0915\u0930\u0947\u0902",
+ "sizeLimit": "\u0938\u0940\u092e\u093e:",
+ "errors": {
+ "failed": "\u0905\u092a\u0932\u094b\u0921 \u0915\u0930\u0928\u0947 \u092e\u0947\u0902 \u0935\u093f\u092b\u0932",
+ "cancelled": "\u0915\u093e \u0905\u092a\u0932\u094b\u0921 \u0930\u0926\u094d\u0926 \u0915\u093f\u092f\u093e \u0917\u092f\u093e"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u0909\u092a\u092f\u094b\u0917 \u0915\u0930 \u0930\u0939\u0947 \u0939\u0948\u0902",
+ "used": "\u0909\u092a\u092f\u094b\u0917 \u0915\u093f\u092f\u093e"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u0915\u094d\u0932\u093f\u092a\u092c\u094b\u0930\u094d\u0921 \u092a\u0930 \u0915\u0949\u092a\u0940 \u0915\u0930\u0947\u0902",
+ "success": "\u0915\u0949\u092a\u0940 \u0915\u093f\u092f\u093e \u0917\u092f\u093e!"
+ }
+ },
+ "feedback": {
+ "positive": "\u0938\u0939\u093e\u092f\u0915",
+ "negative": "\u0938\u0939\u093e\u092f\u0915 \u0928\u0939\u0940\u0902",
+ "edit": "\u092a\u094d\u0930\u0924\u093f\u0915\u094d\u0930\u093f\u092f\u093e \u0938\u0902\u092a\u093e\u0926\u093f\u0924 \u0915\u0930\u0947\u0902",
+ "dialog": {
+ "title": "\u091f\u093f\u092a\u094d\u092a\u0923\u0940 \u091c\u094b\u0921\u093c\u0947\u0902",
+ "submit": "\u092a\u094d\u0930\u0924\u093f\u0915\u094d\u0930\u093f\u092f\u093e \u091c\u092e\u093e \u0915\u0930\u0947\u0902"
+ },
+ "status": {
+ "updating": "\u0905\u092a\u0921\u0947\u091f \u0939\u094b \u0930\u0939\u093e \u0939\u0948",
+ "updated": "\u092a\u094d\u0930\u0924\u093f\u0915\u094d\u0930\u093f\u092f\u093e \u0905\u092a\u0921\u0947\u091f \u0915\u0940 \u0917\u0908"
+ }
+ }
+ },
+ "history": {
+ "title": "\u092a\u093f\u091b\u0932\u0947 \u0907\u0928\u092a\u0941\u091f",
+ "empty": "\u0915\u0941\u091b \u092d\u0940 \u0928\u0939\u0940\u0902 \u0939\u0948...",
+ "show": "\u0907\u0924\u093f\u0939\u093e\u0938 \u0926\u093f\u0916\u093e\u090f\u0902"
+ },
+ "settings": {
+ "title": "\u0938\u0947\u091f\u093f\u0902\u0917\u094d\u0938 \u092a\u0948\u0928\u0932"
+ },
+ "watermark": "\u0915\u0947 \u0938\u093e\u0925 \u092c\u0928\u093e\u092f\u093e \u0917\u092f\u093e"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u092a\u093f\u091b\u0932\u0940 \u091a\u0948\u091f",
+ "filters": {
+ "search": "\u0916\u094b\u091c\u0947\u0902",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u0906\u091c",
+ "yesterday": "\u0915\u0932",
+ "previous7days": "\u092a\u093f\u091b\u0932\u0947 7 \u0926\u093f\u0928",
+ "previous30days": "\u092a\u093f\u091b\u0932\u0947 30 \u0926\u093f\u0928"
+ },
+ "empty": "\u0915\u094b\u0908 \u0925\u094d\u0930\u0947\u0921 \u0928\u0939\u0940\u0902 \u092e\u093f\u0932\u093e",
+ "actions": {
+ "close": "\u0938\u093e\u0907\u0921\u092c\u093e\u0930 \u092c\u0902\u0926 \u0915\u0930\u0947\u0902",
+ "open": "\u0938\u093e\u0907\u0921\u092c\u093e\u0930 \u0916\u094b\u0932\u0947\u0902"
+ }
+ },
+ "thread": {
+ "untitled": "\u0936\u0940\u0930\u094d\u0937\u0915\u0939\u0940\u0928 \u0935\u093e\u0930\u094d\u0924\u093e\u0932\u093e\u092a",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u0939\u091f\u093e\u0928\u0947 \u0915\u0940 \u092a\u0941\u0937\u094d\u091f\u093f \u0915\u0930\u0947\u0902",
+ "description": "\u092f\u0939 \u0925\u094d\u0930\u0947\u0921 \u0914\u0930 \u0907\u0938\u0915\u0947 \u0938\u0902\u0926\u0947\u0936\u094b\u0902 \u0914\u0930 \u0924\u0924\u094d\u0935\u094b\u0902 \u0915\u094b \u0939\u091f\u093e \u0926\u0947\u0917\u093e\u0964 \u092f\u0939 \u0915\u094d\u0930\u093f\u092f\u093e \u0935\u093e\u092a\u0938 \u0928\u0939\u0940\u0902 \u0915\u0940 \u091c\u093e \u0938\u0915\u0924\u0940",
+ "success": "\u091a\u0948\u091f \u0939\u091f\u093e \u0926\u0940 \u0917\u0908",
+ "inProgress": "\u091a\u0948\u091f \u0939\u091f\u093e\u0908 \u091c\u093e \u0930\u0939\u0940 \u0939\u0948"
+ },
+ "rename": {
+ "title": "\u0925\u094d\u0930\u0947\u0921 \u0915\u093e \u0928\u093e\u092e \u092c\u0926\u0932\u0947\u0902",
+ "description": "\u0907\u0938 \u0925\u094d\u0930\u0947\u0921 \u0915\u0947 \u0932\u093f\u090f \u090f\u0915 \u0928\u092f\u093e \u0928\u093e\u092e \u0926\u0930\u094d\u091c \u0915\u0930\u0947\u0902",
+ "form": {
+ "name": {
+ "label": "\u0928\u093e\u092e",
+ "placeholder": "\u0928\u092f\u093e \u0928\u093e\u092e \u0926\u0930\u094d\u091c \u0915\u0930\u0947\u0902"
+ }
+ },
+ "success": "\u0925\u094d\u0930\u0947\u0921 \u0915\u093e \u0928\u093e\u092e \u092c\u0926\u0932 \u0926\u093f\u092f\u093e \u0917\u092f\u093e!",
+ "inProgress": "\u0925\u094d\u0930\u0947\u0921 \u0915\u093e \u0928\u093e\u092e \u092c\u0926\u0932\u093e \u091c\u093e \u0930\u0939\u093e \u0939\u0948"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u091a\u0948\u091f",
+ "readme": "\u0930\u0940\u0921\u092e\u0940",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u0928\u0908 \u091a\u0948\u091f",
+ "dialog": {
+ "title": "\u0928\u0908 \u091a\u0948\u091f \u092c\u0928\u093e\u090f\u0902",
+ "description": "\u092f\u0939 \u0906\u092a\u0915\u093e \u0935\u0930\u094d\u0924\u092e\u093e\u0928 \u091a\u0948\u091f \u0907\u0924\u093f\u0939\u093e\u0938 \u0938\u093e\u092b\u093c \u0915\u0930 \u0926\u0947\u0917\u093e\u0964 \u0915\u094d\u092f\u093e \u0906\u092a \u091c\u093e\u0930\u0940 \u0930\u0916\u0928\u093e \u091a\u093e\u0939\u0924\u0947 \u0939\u0948\u0902?",
+ "tooltip": "\u0928\u0908 \u091a\u0948\u091f"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u0938\u0947\u091f\u093f\u0902\u0917\u094d\u0938",
+ "settingsKey": "S",
+ "apiKeys": "API \u0915\u0941\u0902\u091c\u093f\u092f\u093e\u0902",
+ "logout": "\u0932\u0949\u0917\u0906\u0909\u091f"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u0906\u0935\u0936\u094d\u092f\u0915 API \u0915\u0941\u0902\u091c\u093f\u092f\u093e\u0902",
+ "description": "\u0907\u0938 \u0910\u092a \u0915\u093e \u0909\u092a\u092f\u094b\u0917 \u0915\u0930\u0928\u0947 \u0915\u0947 \u0932\u093f\u090f, \u0928\u093f\u092e\u094d\u0928\u0932\u093f\u0916\u093f\u0924 API \u0915\u0941\u0902\u091c\u093f\u092f\u093e\u0902 \u0906\u0935\u0936\u094d\u092f\u0915 \u0939\u0948\u0902\u0964 \u0915\u0941\u0902\u091c\u093f\u092f\u093e\u0902 \u0906\u092a\u0915\u0947 \u0921\u093f\u0935\u093e\u0907\u0938 \u0915\u0947 \u0938\u094d\u0925\u093e\u0928\u0940\u092f \u0938\u0902\u0917\u094d\u0930\u0939\u0923 \u092e\u0947\u0902 \u0938\u0902\u0917\u094d\u0930\u0939\u0940\u0924 \u0915\u0940 \u091c\u093e\u0924\u0940 \u0939\u0948\u0902\u0964",
+ "success": {
+ "saved": "\u0938\u092b\u0932\u0924\u093e\u092a\u0942\u0930\u094d\u0935\u0915 \u0938\u0939\u0947\u091c\u093e \u0917\u092f\u093e"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/ja.json b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/ja.json
new file mode 100644
index 00000000..343ee37e
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/ja.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u30ad\u30e3\u30f3\u30bb\u30eb",
+ "confirm": "\u78ba\u8a8d",
+ "continue": "\u7d9a\u3051\u308b",
+ "goBack": "\u623b\u308b",
+ "reset": "\u30ea\u30bb\u30c3\u30c8",
+ "submit": "\u9001\u4fe1"
+ },
+ "status": {
+ "loading": "\u8aad\u307f\u8fbc\u307f\u4e2d...",
+ "error": {
+ "default": "\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f",
+ "serverConnection": "\u30b5\u30fc\u30d0\u30fc\u306b\u63a5\u7d9a\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u30a2\u30d7\u30ea\u306b\u30ed\u30b0\u30a4\u30f3",
+ "form": {
+ "email": {
+ "label": "\u30e1\u30fc\u30eb\u30a2\u30c9\u30ec\u30b9",
+ "required": "\u30e1\u30fc\u30eb\u30a2\u30c9\u30ec\u30b9\u306f\u5fc5\u9808\u9805\u76ee\u3067\u3059"
+ },
+ "password": {
+ "label": "\u30d1\u30b9\u30ef\u30fc\u30c9",
+ "required": "\u30d1\u30b9\u30ef\u30fc\u30c9\u306f\u5fc5\u9808\u9805\u76ee\u3067\u3059"
+ },
+ "actions": {
+ "signin": "\u30b5\u30a4\u30f3\u30a4\u30f3"
+ },
+ "alternativeText": {
+ "or": "\u307e\u305f\u306f"
+ }
+ },
+ "errors": {
+ "default": "\u30b5\u30a4\u30f3\u30a4\u30f3\u3067\u304d\u307e\u305b\u3093",
+ "signin": "\u5225\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u3067\u30b5\u30a4\u30f3\u30a4\u30f3\u3057\u3066\u304f\u3060\u3055\u3044",
+ "oauthSignin": "\u5225\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u3067\u30b5\u30a4\u30f3\u30a4\u30f3\u3057\u3066\u304f\u3060\u3055\u3044",
+ "redirectUriMismatch": "\u30ea\u30c0\u30a4\u30ec\u30af\u30c8URI\u304cOAuth\u30a2\u30d7\u30ea\u306e\u8a2d\u5b9a\u3068\u4e00\u81f4\u3057\u307e\u305b\u3093",
+ "oauthCallback": "\u5225\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u3067\u30b5\u30a4\u30f3\u30a4\u30f3\u3057\u3066\u304f\u3060\u3055\u3044",
+ "oauthCreateAccount": "\u5225\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u3067\u30b5\u30a4\u30f3\u30a4\u30f3\u3057\u3066\u304f\u3060\u3055\u3044",
+ "emailCreateAccount": "\u5225\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u3067\u30b5\u30a4\u30f3\u30a4\u30f3\u3057\u3066\u304f\u3060\u3055\u3044",
+ "callback": "\u5225\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u3067\u30b5\u30a4\u30f3\u30a4\u30f3\u3057\u3066\u304f\u3060\u3055\u3044",
+ "oauthAccountNotLinked": "\u672c\u4eba\u78ba\u8a8d\u306e\u305f\u3081\u3001\u6700\u521d\u306b\u4f7f\u7528\u3057\u305f\u306e\u3068\u540c\u3058\u30a2\u30ab\u30a6\u30f3\u30c8\u3067\u30b5\u30a4\u30f3\u30a4\u30f3\u3057\u3066\u304f\u3060\u3055\u3044",
+ "emailSignin": "\u30e1\u30fc\u30eb\u3092\u9001\u4fe1\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f",
+ "emailVerify": "\u30e1\u30fc\u30eb\u30a2\u30c9\u30ec\u30b9\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u65b0\u3057\u3044\u30e1\u30fc\u30eb\u304c\u9001\u4fe1\u3055\u308c\u307e\u3057\u305f",
+ "credentialsSignin": "\u30b5\u30a4\u30f3\u30a4\u30f3\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002\u5165\u529b\u3057\u305f\u60c5\u5831\u304c\u6b63\u3057\u3044\u304b\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044",
+ "sessionRequired": "\u3053\u306e\u30da\u30fc\u30b8\u306b\u30a2\u30af\u30bb\u30b9\u3059\u308b\u306b\u306f\u30b5\u30a4\u30f3\u30a4\u30f3\u3057\u3066\u304f\u3060\u3055\u3044"
+ }
+ },
+ "provider": {
+ "continue": "{{provider}}\u3067\u7d9a\u3051\u308b"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044...",
+ "actions": {
+ "send": "\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u9001\u4fe1",
+ "stop": "\u30bf\u30b9\u30af\u3092\u505c\u6b62",
+ "attachFiles": "\u30d5\u30a1\u30a4\u30eb\u3092\u6dfb\u4ed8"
+ }
+ },
+ "speech": {
+ "start": "\u9332\u97f3\u958b\u59cb",
+ "stop": "\u9332\u97f3\u505c\u6b62",
+ "connecting": "\u63a5\u7d9a\u4e2d"
+ },
+ "fileUpload": {
+ "dragDrop": "\u3053\u3053\u306b\u30d5\u30a1\u30a4\u30eb\u3092\u30c9\u30e9\u30c3\u30b0\uff06\u30c9\u30ed\u30c3\u30d7",
+ "browse": "\u30d5\u30a1\u30a4\u30eb\u3092\u53c2\u7167",
+ "sizeLimit": "\u5236\u9650\uff1a",
+ "errors": {
+ "failed": "\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f",
+ "cancelled": "\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3092\u30ad\u30e3\u30f3\u30bb\u30eb\u3057\u307e\u3057\u305f\uff1a"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u4f7f\u7528\u4e2d",
+ "used": "\u4f7f\u7528\u6e08\u307f"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u30af\u30ea\u30c3\u30d7\u30dc\u30fc\u30c9\u306b\u30b3\u30d4\u30fc",
+ "success": "\u30b3\u30d4\u30fc\u3057\u307e\u3057\u305f\uff01"
+ }
+ },
+ "feedback": {
+ "positive": "\u5f79\u306b\u7acb\u3063\u305f",
+ "negative": "\u5f79\u306b\u7acb\u305f\u306a\u304b\u3063\u305f",
+ "edit": "\u30d5\u30a3\u30fc\u30c9\u30d0\u30c3\u30af\u3092\u7de8\u96c6",
+ "dialog": {
+ "title": "\u30b3\u30e1\u30f3\u30c8\u3092\u8ffd\u52a0",
+ "submit": "\u30d5\u30a3\u30fc\u30c9\u30d0\u30c3\u30af\u3092\u9001\u4fe1"
+ },
+ "status": {
+ "updating": "\u66f4\u65b0\u4e2d",
+ "updated": "\u30d5\u30a3\u30fc\u30c9\u30d0\u30c3\u30af\u3092\u66f4\u65b0\u3057\u307e\u3057\u305f"
+ }
+ }
+ },
+ "history": {
+ "title": "\u6700\u8fd1\u306e\u5165\u529b",
+ "empty": "\u4f55\u3082\u3042\u308a\u307e\u305b\u3093...",
+ "show": "\u5c65\u6b74\u3092\u8868\u793a"
+ },
+ "settings": {
+ "title": "\u8a2d\u5b9a\u30d1\u30cd\u30eb"
+ },
+ "watermark": "\u958b\u767a\u5143\uff1a"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u904e\u53bb\u306e\u30c1\u30e3\u30c3\u30c8",
+ "filters": {
+ "search": "\u691c\u7d22",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u4eca\u65e5",
+ "yesterday": "\u6628\u65e5",
+ "previous7days": "\u904e\u53bb7\u65e5\u9593",
+ "previous30days": "\u904e\u53bb30\u65e5\u9593"
+ },
+ "empty": "\u30b9\u30ec\u30c3\u30c9\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093",
+ "actions": {
+ "close": "\u30b5\u30a4\u30c9\u30d0\u30fc\u3092\u9589\u3058\u308b",
+ "open": "\u30b5\u30a4\u30c9\u30d0\u30fc\u3092\u958b\u304f"
+ }
+ },
+ "thread": {
+ "untitled": "\u7121\u984c\u306e\u4f1a\u8a71",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u524a\u9664\u306e\u78ba\u8a8d",
+ "description": "\u3053\u306e\u30b9\u30ec\u30c3\u30c9\u3068\u305d\u306e\u30e1\u30c3\u30bb\u30fc\u30b8\u3001\u8981\u7d20\u304c\u524a\u9664\u3055\u308c\u307e\u3059\u3002\u3053\u306e\u64cd\u4f5c\u306f\u53d6\u308a\u6d88\u305b\u307e\u305b\u3093",
+ "success": "\u30c1\u30e3\u30c3\u30c8\u3092\u524a\u9664\u3057\u307e\u3057\u305f",
+ "inProgress": "\u30c1\u30e3\u30c3\u30c8\u3092\u524a\u9664\u4e2d"
+ },
+ "rename": {
+ "title": "\u30b9\u30ec\u30c3\u30c9\u306e\u540d\u524d\u3092\u5909\u66f4",
+ "description": "\u3053\u306e\u30b9\u30ec\u30c3\u30c9\u306e\u65b0\u3057\u3044\u540d\u524d\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044",
+ "form": {
+ "name": {
+ "label": "\u540d\u524d",
+ "placeholder": "\u65b0\u3057\u3044\u540d\u524d\u3092\u5165\u529b"
+ }
+ },
+ "success": "\u30b9\u30ec\u30c3\u30c9\u540d\u3092\u5909\u66f4\u3057\u307e\u3057\u305f\uff01",
+ "inProgress": "\u30b9\u30ec\u30c3\u30c9\u540d\u3092\u5909\u66f4\u4e2d"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u30c1\u30e3\u30c3\u30c8",
+ "readme": "\u8aac\u660e\u66f8",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u65b0\u898f\u30c1\u30e3\u30c3\u30c8",
+ "dialog": {
+ "title": "\u65b0\u898f\u30c1\u30e3\u30c3\u30c8\u306e\u4f5c\u6210",
+ "description": "\u73fe\u5728\u306e\u30c1\u30e3\u30c3\u30c8\u5c65\u6b74\u304c\u30af\u30ea\u30a2\u3055\u308c\u307e\u3059\u3002\u7d9a\u884c\u3057\u307e\u3059\u304b\uff1f",
+ "tooltip": "\u65b0\u898f\u30c1\u30e3\u30c3\u30c8"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u8a2d\u5b9a",
+ "settingsKey": "S",
+ "apiKeys": "API\u30ad\u30fc",
+ "logout": "\u30ed\u30b0\u30a2\u30a6\u30c8"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u5fc5\u8981\u306aAPI\u30ad\u30fc",
+ "description": "\u3053\u306e\u30a2\u30d7\u30ea\u3092\u4f7f\u7528\u3059\u308b\u306b\u306f\u3001\u4ee5\u4e0b\u306eAPI\u30ad\u30fc\u304c\u5fc5\u8981\u3067\u3059\u3002\u30ad\u30fc\u306f\u304a\u4f7f\u3044\u306e\u30c7\u30d0\u30a4\u30b9\u306e\u30ed\u30fc\u30ab\u30eb\u30b9\u30c8\u30ec\u30fc\u30b8\u306b\u4fdd\u5b58\u3055\u308c\u307e\u3059\u3002",
+ "success": {
+ "saved": "\u4fdd\u5b58\u304c\u5b8c\u4e86\u3057\u307e\u3057\u305f"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/kn.json b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/kn.json
new file mode 100644
index 00000000..c8ffabc0
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/kn.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u0cb0\u0ca6\u0ccd\u0ca6\u0cc1\u0cae\u0cbe\u0ca1\u0cbf",
+ "confirm": "\u0ca6\u0cc3\u0ca2\u0cc0\u0c95\u0cb0\u0cbf\u0cb8\u0cbf",
+ "continue": "\u0cae\u0cc1\u0c82\u0ca6\u0cc1\u0cb5\u0cb0\u0cbf\u0cb8\u0cbf",
+ "goBack": "\u0cb9\u0cbf\u0c82\u0ca6\u0cc6 \u0cb9\u0ccb\u0c97\u0cbf",
+ "reset": "\u0cae\u0cb0\u0cc1\u0cb9\u0cca\u0c82\u0ca6\u0cbf\u0cb8\u0cbf",
+ "submit": "\u0cb8\u0cb2\u0ccd\u0cb2\u0cbf\u0cb8\u0cbf"
+ },
+ "status": {
+ "loading": "\u0cb2\u0ccb\u0ca1\u0ccd \u0c86\u0c97\u0cc1\u0ca4\u0ccd\u0ca4\u0cbf\u0ca6\u0cc6...",
+ "error": {
+ "default": "\u0ca6\u0ccb\u0cb7 \u0cb8\u0c82\u0cad\u0cb5\u0cbf\u0cb8\u0cbf\u0ca6\u0cc6",
+ "serverConnection": "\u0cb8\u0cb0\u0ccd\u0cb5\u0cb0\u0ccd\u200c \u0c85\u0ca8\u0ccd\u0ca8\u0cc1 \u0ca4\u0cb2\u0cc1\u0caa\u0cb2\u0cc1 \u0cb8\u0cbe\u0ca7\u0ccd\u0caf\u0cb5\u0cbe\u0c97\u0cb2\u0cbf\u0cb2\u0ccd\u0cb2"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u0c85\u0caa\u0ccd\u0cb2\u0cbf\u0c95\u0cc7\u0cb6\u0ca8\u0ccd\u200c\u0c97\u0cc6 \u0caa\u0ccd\u0cb0\u0cb5\u0cc7\u0cb6\u0cbf\u0cb8\u0cb2\u0cc1 \u0cb2\u0cbe\u0c97\u0cbf\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cbf",
+ "form": {
+ "email": {
+ "label": "\u0c87\u0cae\u0cc7\u0cb2\u0ccd \u0cb5\u0cbf\u0cb3\u0cbe\u0cb8",
+ "required": "\u0c87\u0cae\u0cc7\u0cb2\u0ccd \u0c85\u0c97\u0ca4\u0ccd\u0caf\u0cb5\u0cbf\u0cb0\u0cc1\u0cb5 \u0c95\u0ccd\u0cb7\u0cc7\u0ca4\u0ccd\u0cb0"
+ },
+ "password": {
+ "label": "\u0caa\u0cbe\u0cb8\u0ccd\u200c\u0cb5\u0cb0\u0ccd\u0ca1\u0ccd",
+ "required": "\u0caa\u0cbe\u0cb8\u0ccd\u200c\u0cb5\u0cb0\u0ccd\u0ca1\u0ccd \u0c85\u0c97\u0ca4\u0ccd\u0caf\u0cb5\u0cbf\u0cb0\u0cc1\u0cb5 \u0c95\u0ccd\u0cb7\u0cc7\u0ca4\u0ccd\u0cb0"
+ },
+ "actions": {
+ "signin": "\u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cbf"
+ },
+ "alternativeText": {
+ "or": "\u0c85\u0ca5\u0cb5\u0cbe"
+ }
+ },
+ "errors": {
+ "default": "\u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cb2\u0cc1 \u0cb8\u0cbe\u0ca7\u0ccd\u0caf\u0cb5\u0cbe\u0c97\u0cb2\u0cbf\u0cb2\u0ccd\u0cb2",
+ "signin": "\u0cac\u0cc7\u0cb0\u0cc6 \u0c96\u0cbe\u0ca4\u0cc6\u0caf\u0cca\u0c82\u0ca6\u0cbf\u0c97\u0cc6 \u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cb2\u0cc1 \u0caa\u0ccd\u0cb0\u0caf\u0ca4\u0ccd\u0ca8\u0cbf\u0cb8\u0cbf",
+ "oauthSignin": "\u0cac\u0cc7\u0cb0\u0cc6 \u0c96\u0cbe\u0ca4\u0cc6\u0caf\u0cca\u0c82\u0ca6\u0cbf\u0c97\u0cc6 \u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cb2\u0cc1 \u0caa\u0ccd\u0cb0\u0caf\u0ca4\u0ccd\u0ca8\u0cbf\u0cb8\u0cbf",
+ "redirectUriMismatch": "\u0cb0\u0cc0\u0ca1\u0cc8\u0cb0\u0cc6\u0c95\u0ccd\u0c9f\u0ccd URI \u0c93\u0ca5\u0ccd \u0c85\u0caa\u0ccd\u0cb2\u0cbf\u0c95\u0cc7\u0cb6\u0ca8\u0ccd \u0c95\u0cbe\u0ca8\u0ccd\u0cab\u0cbf\u0c97\u0cb0\u0cc7\u0cb6\u0ca8\u0ccd\u200c\u0c97\u0cc6 \u0cb9\u0cca\u0c82\u0ca6\u0cbf\u0c95\u0cc6\u0caf\u0cbe\u0c97\u0cc1\u0ca4\u0ccd\u0ca4\u0cbf\u0cb2\u0ccd\u0cb2",
+ "oauthCallback": "\u0cac\u0cc7\u0cb0\u0cc6 \u0c96\u0cbe\u0ca4\u0cc6\u0caf\u0cca\u0c82\u0ca6\u0cbf\u0c97\u0cc6 \u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cb2\u0cc1 \u0caa\u0ccd\u0cb0\u0caf\u0ca4\u0ccd\u0ca8\u0cbf\u0cb8\u0cbf",
+ "oauthCreateAccount": "\u0cac\u0cc7\u0cb0\u0cc6 \u0c96\u0cbe\u0ca4\u0cc6\u0caf\u0cca\u0c82\u0ca6\u0cbf\u0c97\u0cc6 \u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cb2\u0cc1 \u0caa\u0ccd\u0cb0\u0caf\u0ca4\u0ccd\u0ca8\u0cbf\u0cb8\u0cbf",
+ "emailCreateAccount": "\u0cac\u0cc7\u0cb0\u0cc6 \u0c96\u0cbe\u0ca4\u0cc6\u0caf\u0cca\u0c82\u0ca6\u0cbf\u0c97\u0cc6 \u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cb2\u0cc1 \u0caa\u0ccd\u0cb0\u0caf\u0ca4\u0ccd\u0ca8\u0cbf\u0cb8\u0cbf",
+ "callback": "\u0cac\u0cc7\u0cb0\u0cc6 \u0c96\u0cbe\u0ca4\u0cc6\u0caf\u0cca\u0c82\u0ca6\u0cbf\u0c97\u0cc6 \u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cb2\u0cc1 \u0caa\u0ccd\u0cb0\u0caf\u0ca4\u0ccd\u0ca8\u0cbf\u0cb8\u0cbf",
+ "oauthAccountNotLinked": "\u0ca8\u0cbf\u0cae\u0ccd\u0cae \u0c97\u0cc1\u0cb0\u0cc1\u0ca4\u0ca8\u0ccd\u0ca8\u0cc1 \u0ca6\u0cc3\u0ca2\u0cc0\u0c95\u0cb0\u0cbf\u0cb8\u0cb2\u0cc1, \u0ca8\u0cc0\u0cb5\u0cc1 \u0cae\u0cca\u0ca6\u0cb2\u0cc1 \u0cac\u0cb3\u0cb8\u0cbf\u0ca6 \u0c85\u0ca6\u0cc7 \u0c96\u0cbe\u0ca4\u0cc6\u0caf\u0cca\u0c82\u0ca6\u0cbf\u0c97\u0cc6 \u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cbf",
+ "emailSignin": "\u0c87\u0cae\u0cc7\u0cb2\u0ccd \u0c95\u0cb3\u0cc1\u0cb9\u0cbf\u0cb8\u0cb2\u0cc1 \u0cb8\u0cbe\u0ca7\u0ccd\u0caf\u0cb5\u0cbe\u0c97\u0cb2\u0cbf\u0cb2\u0ccd\u0cb2",
+ "emailVerify": "\u0ca6\u0caf\u0cb5\u0cbf\u0c9f\u0ccd\u0c9f\u0cc1 \u0ca8\u0cbf\u0cae\u0ccd\u0cae \u0c87\u0cae\u0cc7\u0cb2\u0ccd \u0caa\u0cb0\u0cbf\u0cb6\u0cc0\u0cb2\u0cbf\u0cb8\u0cbf, \u0cb9\u0cca\u0cb8 \u0c87\u0cae\u0cc7\u0cb2\u0ccd \u0c95\u0cb3\u0cc1\u0cb9\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6",
+ "credentialsSignin": "\u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cb5\u0cbf\u0cab\u0cb2\u0cb5\u0cbe\u0c97\u0cbf\u0ca6\u0cc6. \u0ca8\u0cc0\u0cb5\u0cc1 \u0c92\u0ca6\u0c97\u0cbf\u0cb8\u0cbf\u0ca6 \u0cb5\u0cbf\u0cb5\u0cb0\u0c97\u0cb3\u0cc1 \u0cb8\u0cb0\u0cbf\u0caf\u0cbe\u0c97\u0cbf\u0cb5\u0cc6\u0caf\u0cc7 \u0c8e\u0c82\u0ca6\u0cc1 \u0caa\u0cb0\u0cbf\u0cb6\u0cc0\u0cb2\u0cbf\u0cb8\u0cbf",
+ "sessionRequired": "\u0c88 \u0caa\u0cc1\u0c9f\u0cb5\u0ca8\u0ccd\u0ca8\u0cc1 \u0caa\u0ccd\u0cb0\u0cb5\u0cc7\u0cb6\u0cbf\u0cb8\u0cb2\u0cc1 \u0ca6\u0caf\u0cb5\u0cbf\u0c9f\u0ccd\u0c9f\u0cc1 \u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cbf"
+ }
+ },
+ "provider": {
+ "continue": "{{provider}} \u0ca8\u0cca\u0c82\u0ca6\u0cbf\u0c97\u0cc6 \u0cae\u0cc1\u0c82\u0ca6\u0cc1\u0cb5\u0cb0\u0cbf\u0cb8\u0cbf"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u0ca8\u0cbf\u0cae\u0ccd\u0cae \u0cb8\u0c82\u0ca6\u0cc7\u0cb6\u0cb5\u0ca8\u0ccd\u0ca8\u0cc1 \u0c87\u0cb2\u0ccd\u0cb2\u0cbf \u0c9f\u0cc8\u0caa\u0ccd \u0cae\u0cbe\u0ca1\u0cbf...",
+ "actions": {
+ "send": "\u0cb8\u0c82\u0ca6\u0cc7\u0cb6 \u0c95\u0cb3\u0cc1\u0cb9\u0cbf\u0cb8\u0cbf",
+ "stop": "\u0c95\u0cbe\u0cb0\u0ccd\u0caf \u0ca8\u0cbf\u0cb2\u0ccd\u0cb2\u0cbf\u0cb8\u0cbf",
+ "attachFiles": "\u0cab\u0cc8\u0cb2\u0ccd\u200c\u0c97\u0cb3\u0ca8\u0ccd\u0ca8\u0cc1 \u0cb2\u0c97\u0ca4\u0ccd\u0ca4\u0cbf\u0cb8\u0cbf"
+ }
+ },
+ "speech": {
+ "start": "\u0cb0\u0cc6\u0c95\u0cbe\u0cb0\u0ccd\u0ca1\u0cbf\u0c82\u0c97\u0ccd \u0caa\u0ccd\u0cb0\u0cbe\u0cb0\u0c82\u0cad\u0cbf\u0cb8\u0cbf",
+ "stop": "\u0cb0\u0cc6\u0c95\u0cbe\u0cb0\u0ccd\u0ca1\u0cbf\u0c82\u0c97\u0ccd \u0ca8\u0cbf\u0cb2\u0ccd\u0cb2\u0cbf\u0cb8\u0cbf",
+ "connecting": "\u0cb8\u0c82\u0caa\u0cb0\u0ccd\u0c95\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cc1\u0ca4\u0ccd\u0ca4\u0cbf\u0ca6\u0cc6"
+ },
+ "fileUpload": {
+ "dragDrop": "\u0cab\u0cc8\u0cb2\u0ccd\u200c\u0c97\u0cb3\u0ca8\u0ccd\u0ca8\u0cc1 \u0c87\u0cb2\u0ccd\u0cb2\u0cbf \u0c8e\u0cb3\u0cc6\u0ca6\u0cc1 \u0cac\u0cbf\u0ca1\u0cbf",
+ "browse": "\u0cab\u0cc8\u0cb2\u0ccd\u200c\u0c97\u0cb3\u0ca8\u0ccd\u0ca8\u0cc1 \u0cac\u0ccd\u0cb0\u0ccc\u0cb8\u0ccd \u0cae\u0cbe\u0ca1\u0cbf",
+ "sizeLimit": "\u0cae\u0cbf\u0ca4\u0cbf:",
+ "errors": {
+ "failed": "\u0c85\u0caa\u0ccd\u200c\u0cb2\u0ccb\u0ca1\u0ccd \u0cb5\u0cbf\u0cab\u0cb2\u0cb5\u0cbe\u0c97\u0cbf\u0ca6\u0cc6",
+ "cancelled": "\u0c85\u0caa\u0ccd\u200c\u0cb2\u0ccb\u0ca1\u0ccd \u0cb0\u0ca6\u0ccd\u0ca6\u0cc1\u0c97\u0cca\u0cb3\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u0cac\u0cb3\u0cb8\u0cc1\u0ca4\u0ccd\u0ca4\u0cbf\u0cb0\u0cc1\u0cb5\u0cc1\u0ca6\u0cc1",
+ "used": "\u0cac\u0cb3\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u0c95\u0ccd\u0cb2\u0cbf\u0caa\u0ccd\u200c\u0cac\u0ccb\u0cb0\u0ccd\u0ca1\u0ccd\u200c\u0c97\u0cc6 \u0ca8\u0c95\u0cb2\u0cbf\u0cb8\u0cbf",
+ "success": "\u0ca8\u0c95\u0cb2\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6!"
+ }
+ },
+ "feedback": {
+ "positive": "\u0cb8\u0cb9\u0cbe\u0caf\u0c95\u0cb5\u0cbe\u0c97\u0cbf\u0ca6\u0cc6",
+ "negative": "\u0cb8\u0cb9\u0cbe\u0caf\u0c95\u0cb5\u0cbe\u0c97\u0cbf\u0cb2\u0ccd\u0cb2",
+ "edit": "\u0caa\u0ccd\u0cb0\u0ca4\u0cbf\u0c95\u0ccd\u0cb0\u0cbf\u0caf\u0cc6 \u0cb8\u0c82\u0caa\u0cbe\u0ca6\u0cbf\u0cb8\u0cbf",
+ "dialog": {
+ "title": "\u0c95\u0cbe\u0cae\u0cc6\u0c82\u0c9f\u0ccd \u0cb8\u0cc7\u0cb0\u0cbf\u0cb8\u0cbf",
+ "submit": "\u0caa\u0ccd\u0cb0\u0ca4\u0cbf\u0c95\u0ccd\u0cb0\u0cbf\u0caf\u0cc6 \u0cb8\u0cb2\u0ccd\u0cb2\u0cbf\u0cb8\u0cbf"
+ },
+ "status": {
+ "updating": "\u0ca8\u0cb5\u0cc0\u0c95\u0cb0\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cc1\u0ca4\u0ccd\u0ca4\u0cbf\u0ca6\u0cc6",
+ "updated": "\u0caa\u0ccd\u0cb0\u0ca4\u0cbf\u0c95\u0ccd\u0cb0\u0cbf\u0caf\u0cc6 \u0ca8\u0cb5\u0cc0\u0c95\u0cb0\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6"
+ }
+ }
+ },
+ "history": {
+ "title": "\u0c95\u0cca\u0ca8\u0cc6\u0caf \u0c87\u0ca8\u0ccd\u200c\u0caa\u0cc1\u0c9f\u0ccd\u200c\u0c97\u0cb3\u0cc1",
+ "empty": "\u0c96\u0cbe\u0cb2\u0cbf\u0caf\u0cbe\u0c97\u0cbf\u0ca6\u0cc6...",
+ "show": "\u0c87\u0ca4\u0cbf\u0cb9\u0cbe\u0cb8 \u0ca4\u0ccb\u0cb0\u0cbf\u0cb8\u0cbf"
+ },
+ "settings": {
+ "title": "\u0cb8\u0cc6\u0c9f\u0ccd\u0c9f\u0cbf\u0c82\u0c97\u0ccd\u200c\u0c97\u0cb3 \u0caa\u0ccd\u0caf\u0cbe\u0ca8\u0cc6\u0cb2\u0ccd"
+ },
+ "watermark": "\u0c87\u0ca6\u0cb0\u0cca\u0c82\u0ca6\u0cbf\u0c97\u0cc6 \u0ca8\u0cbf\u0cb0\u0ccd\u0cae\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u0cb9\u0cbf\u0c82\u0ca6\u0cbf\u0ca8 \u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6\u0c97\u0cb3\u0cc1",
+ "filters": {
+ "search": "\u0cb9\u0cc1\u0ca1\u0cc1\u0c95\u0cbf",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u0c87\u0c82\u0ca6\u0cc1",
+ "yesterday": "\u0ca8\u0cbf\u0ca8\u0ccd\u0ca8\u0cc6",
+ "previous7days": "\u0cb9\u0cbf\u0c82\u0ca6\u0cbf\u0ca8 7 \u0ca6\u0cbf\u0ca8\u0c97\u0cb3\u0cc1",
+ "previous30days": "\u0cb9\u0cbf\u0c82\u0ca6\u0cbf\u0ca8 30 \u0ca6\u0cbf\u0ca8\u0c97\u0cb3\u0cc1"
+ },
+ "empty": "\u0caf\u0cbe\u0cb5\u0cc1\u0ca6\u0cc7 \u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6\u0c97\u0cb3\u0cc1 \u0c95\u0c82\u0ca1\u0cc1\u0cac\u0c82\u0ca6\u0cbf\u0cb2\u0ccd\u0cb2",
+ "actions": {
+ "close": "\u0caa\u0c95\u0ccd\u0c95\u0ca6 \u0caa\u0c9f\u0ccd\u0c9f\u0cbf \u0cae\u0cc1\u0c9a\u0ccd\u0c9a\u0cbf",
+ "open": "\u0caa\u0c95\u0ccd\u0c95\u0ca6 \u0caa\u0c9f\u0ccd\u0c9f\u0cbf \u0ca4\u0cc6\u0cb0\u0cc6\u0caf\u0cbf\u0cb0\u0cbf"
+ }
+ },
+ "thread": {
+ "untitled": "\u0cb6\u0cc0\u0cb0\u0ccd\u0cb7\u0cbf\u0c95\u0cc6\u0cb0\u0cb9\u0cbf\u0ca4 \u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u0c85\u0cb3\u0cbf\u0cb8\u0cc1\u0cb5\u0cbf\u0c95\u0cc6\u0caf\u0ca8\u0ccd\u0ca8\u0cc1 \u0ca6\u0cc3\u0ca2\u0cc0\u0c95\u0cb0\u0cbf\u0cb8\u0cbf",
+ "description": "\u0c87\u0ca6\u0cc1 \u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6\u0caf\u0ca8\u0ccd\u0ca8\u0cc1 \u0cb9\u0cbe\u0c97\u0cc2 \u0c85\u0ca6\u0cb0 \u0cb8\u0c82\u0ca6\u0cc7\u0cb6\u0c97\u0cb3\u0cc1 \u0cae\u0ca4\u0ccd\u0ca4\u0cc1 \u0c85\u0c82\u0cb6\u0c97\u0cb3\u0ca8\u0ccd\u0ca8\u0cc1 \u0c85\u0cb3\u0cbf\u0cb8\u0cc1\u0ca4\u0ccd\u0ca4\u0ca6\u0cc6. \u0c88 \u0c95\u0ccd\u0cb0\u0cbf\u0caf\u0cc6\u0caf\u0ca8\u0ccd\u0ca8\u0cc1 \u0cb0\u0ca6\u0ccd\u0ca6\u0cc1\u0c97\u0cca\u0cb3\u0cbf\u0cb8\u0cb2\u0cc1 \u0cb8\u0cbe\u0ca7\u0ccd\u0caf\u0cb5\u0cbf\u0cb2\u0ccd\u0cb2",
+ "success": "\u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6 \u0c85\u0cb3\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6",
+ "inProgress": "\u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6 \u0c85\u0cb3\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cc1\u0ca4\u0ccd\u0ca4\u0cbf\u0ca6\u0cc6"
+ },
+ "rename": {
+ "title": "\u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6\u0caf \u0cb9\u0cc6\u0cb8\u0cb0\u0cc1 \u0cac\u0ca6\u0cb2\u0cbe\u0caf\u0cbf\u0cb8\u0cbf",
+ "description": "\u0c88 \u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6\u0c97\u0cc6 \u0cb9\u0cca\u0cb8 \u0cb9\u0cc6\u0cb8\u0cb0\u0ca8\u0ccd\u0ca8\u0cc1 \u0ca8\u0cae\u0cc2\u0ca6\u0cbf\u0cb8\u0cbf",
+ "form": {
+ "name": {
+ "label": "\u0cb9\u0cc6\u0cb8\u0cb0\u0cc1",
+ "placeholder": "\u0cb9\u0cca\u0cb8 \u0cb9\u0cc6\u0cb8\u0cb0\u0ca8\u0ccd\u0ca8\u0cc1 \u0ca8\u0cae\u0cc2\u0ca6\u0cbf\u0cb8\u0cbf"
+ }
+ },
+ "success": "\u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6\u0caf \u0cb9\u0cc6\u0cb8\u0cb0\u0cc1 \u0cac\u0ca6\u0cb2\u0cbe\u0caf\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6!",
+ "inProgress": "\u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6\u0caf \u0cb9\u0cc6\u0cb8\u0cb0\u0cc1 \u0cac\u0ca6\u0cb2\u0cbe\u0caf\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cc1\u0ca4\u0ccd\u0ca4\u0cbf\u0ca6\u0cc6"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6",
+ "readme": "\u0c93\u0ca6\u0cbf",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u0cb9\u0cca\u0cb8 \u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6",
+ "dialog": {
+ "title": "\u0cb9\u0cca\u0cb8 \u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6 \u0cb0\u0c9a\u0cbf\u0cb8\u0cbf",
+ "description": "\u0c87\u0ca6\u0cc1 \u0ca8\u0cbf\u0cae\u0ccd\u0cae \u0caa\u0ccd\u0cb0\u0cb8\u0ccd\u0ca4\u0cc1\u0ca4 \u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6\u0caf \u0c87\u0ca4\u0cbf\u0cb9\u0cbe\u0cb8\u0cb5\u0ca8\u0ccd\u0ca8\u0cc1 \u0c85\u0cb3\u0cbf\u0cb8\u0cc1\u0ca4\u0ccd\u0ca4\u0ca6\u0cc6. \u0ca8\u0cc0\u0cb5\u0cc1 \u0cae\u0cc1\u0c82\u0ca6\u0cc1\u0cb5\u0cb0\u0cc6\u0caf\u0cb2\u0cc1 \u0cac\u0caf\u0cb8\u0cc1\u0cb5\u0cbf\u0cb0\u0cbe?",
+ "tooltip": "\u0cb9\u0cca\u0cb8 \u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u0cb8\u0cc6\u0c9f\u0ccd\u0c9f\u0cbf\u0c82\u0c97\u0ccd\u200c\u0c97\u0cb3\u0cc1",
+ "settingsKey": "S",
+ "apiKeys": "API \u0c95\u0cc0\u0c97\u0cb3\u0cc1",
+ "logout": "\u0cb2\u0cbe\u0c97\u0ccd \u0c94\u0c9f\u0ccd"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u0c85\u0c97\u0ca4\u0ccd\u0caf\u0cb5\u0cbf\u0cb0\u0cc1\u0cb5 API \u0c95\u0cc0\u0c97\u0cb3\u0cc1",
+ "description": "\u0c88 \u0c85\u0caa\u0ccd\u0cb2\u0cbf\u0c95\u0cc7\u0cb6\u0ca8\u0ccd \u0cac\u0cb3\u0cb8\u0cb2\u0cc1, \u0c88 \u0c95\u0cc6\u0cb3\u0c97\u0cbf\u0ca8 API \u0c95\u0cc0\u0c97\u0cb3\u0cc1 \u0c85\u0c97\u0ca4\u0ccd\u0caf\u0cb5\u0cbf\u0cb0\u0cc1\u0ca4\u0ccd\u0ca4\u0cb5\u0cc6. \u0c95\u0cc0\u0c97\u0cb3\u0ca8\u0ccd\u0ca8\u0cc1 \u0ca8\u0cbf\u0cae\u0ccd\u0cae \u0cb8\u0cbe\u0ca7\u0ca8\u0ca6 \u0cb8\u0ccd\u0ca5\u0cb3\u0cc0\u0caf \u0cb8\u0c82\u0c97\u0ccd\u0cb0\u0cb9\u0ca3\u0cc6\u0caf\u0cb2\u0ccd\u0cb2\u0cbf \u0cb8\u0c82\u0c97\u0ccd\u0cb0\u0cb9\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cc1\u0ca4\u0ccd\u0ca4\u0ca6\u0cc6.",
+ "success": {
+ "saved": "\u0caf\u0cb6\u0cb8\u0ccd\u0cb5\u0cbf\u0caf\u0cbe\u0c97\u0cbf \u0c89\u0cb3\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/ml.json b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/ml.json
new file mode 100644
index 00000000..f932bd3d
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/ml.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u0d31\u0d26\u0d4d\u0d26\u0d3e\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "confirm": "\u0d38\u0d4d\u0d25\u0d3f\u0d30\u0d40\u0d15\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "continue": "\u0d24\u0d41\u0d1f\u0d30\u0d41\u0d15",
+ "goBack": "\u0d24\u0d3f\u0d30\u0d3f\u0d15\u0d46 \u0d2a\u0d4b\u0d15\u0d41\u0d15",
+ "reset": "\u0d2a\u0d41\u0d28\u0d03\u0d38\u0d1c\u0d4d\u0d1c\u0d2e\u0d3e\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "submit": "\u0d38\u0d2e\u0d7c\u0d2a\u0d4d\u0d2a\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15"
+ },
+ "status": {
+ "loading": "\u0d32\u0d4b\u0d21\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d28\u0d4d\u0d28\u0d41...",
+ "error": {
+ "default": "\u0d12\u0d30\u0d41 \u0d2a\u0d3f\u0d36\u0d15\u0d4d \u0d38\u0d02\u0d2d\u0d35\u0d3f\u0d1a\u0d4d\u0d1a\u0d41",
+ "serverConnection": "\u0d38\u0d46\u0d7c\u0d35\u0d31\u0d41\u0d2e\u0d3e\u0d2f\u0d3f \u0d2c\u0d28\u0d4d\u0d27\u0d2a\u0d4d\u0d2a\u0d46\u0d1f\u0d3e\u0d7b \u0d15\u0d34\u0d3f\u0d1e\u0d4d\u0d1e\u0d3f\u0d32\u0d4d\u0d32"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u0d06\u0d2a\u0d4d\u0d2a\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d15\u0d4d\u0d15\u0d3e\u0d7b \u0d32\u0d4b\u0d17\u0d3f\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15",
+ "form": {
+ "email": {
+ "label": "\u0d07\u0d2e\u0d46\u0d2f\u0d3f\u0d7d \u0d35\u0d3f\u0d32\u0d3e\u0d38\u0d02",
+ "required": "\u0d07\u0d2e\u0d46\u0d2f\u0d3f\u0d7d \u0d12\u0d30\u0d41 \u0d06\u0d35\u0d36\u0d4d\u0d2f\u0d2e\u0d3e\u0d2f \u0d2b\u0d40\u0d7d\u0d21\u0d4d \u0d06\u0d23\u0d4d"
+ },
+ "password": {
+ "label": "\u0d2a\u0d3e\u0d38\u0d4d\u200c\u0d35\u0d47\u0d21\u0d4d",
+ "required": "\u0d2a\u0d3e\u0d38\u0d4d\u200c\u0d35\u0d47\u0d21\u0d4d \u0d12\u0d30\u0d41 \u0d06\u0d35\u0d36\u0d4d\u0d2f\u0d2e\u0d3e\u0d2f \u0d2b\u0d40\u0d7d\u0d21\u0d4d \u0d06\u0d23\u0d4d"
+ },
+ "actions": {
+ "signin": "\u0d38\u0d48\u0d7b \u0d07\u0d7b"
+ },
+ "alternativeText": {
+ "or": "\u0d05\u0d32\u0d4d\u0d32\u0d46\u0d19\u0d4d\u0d15\u0d3f\u0d7d"
+ }
+ },
+ "errors": {
+ "default": "\u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d3e\u0d7b \u0d15\u0d34\u0d3f\u0d2f\u0d41\u0d28\u0d4d\u0d28\u0d3f\u0d32\u0d4d\u0d32",
+ "signin": "\u0d2e\u0d31\u0d4d\u0d31\u0d4a\u0d30\u0d41 \u0d05\u0d15\u0d4d\u0d15\u0d57\u0d23\u0d4d\u0d1f\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d4d \u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d3e\u0d7b \u0d36\u0d4d\u0d30\u0d2e\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "oauthSignin": "\u0d2e\u0d31\u0d4d\u0d31\u0d4a\u0d30\u0d41 \u0d05\u0d15\u0d4d\u0d15\u0d57\u0d23\u0d4d\u0d1f\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d4d \u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d3e\u0d7b \u0d36\u0d4d\u0d30\u0d2e\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "redirectUriMismatch": "\u0d31\u0d40\u0d21\u0d2f\u0d31\u0d15\u0d4d\u0d1f\u0d4d URI oauth \u0d06\u0d2a\u0d4d\u0d2a\u0d4d \u0d15\u0d4b\u0d7a\u0d2b\u0d3f\u0d17\u0d31\u0d47\u0d37\u0d28\u0d41\u0d2e\u0d3e\u0d2f\u0d3f \u0d2a\u0d4a\u0d30\u0d41\u0d24\u0d4d\u0d24\u0d2a\u0d4d\u0d2a\u0d46\u0d1f\u0d41\u0d28\u0d4d\u0d28\u0d3f\u0d32\u0d4d\u0d32",
+ "oauthCallback": "\u0d2e\u0d31\u0d4d\u0d31\u0d4a\u0d30\u0d41 \u0d05\u0d15\u0d4d\u0d15\u0d57\u0d23\u0d4d\u0d1f\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d4d \u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d3e\u0d7b \u0d36\u0d4d\u0d30\u0d2e\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "oauthCreateAccount": "\u0d2e\u0d31\u0d4d\u0d31\u0d4a\u0d30\u0d41 \u0d05\u0d15\u0d4d\u0d15\u0d57\u0d23\u0d4d\u0d1f\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d4d \u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d3e\u0d7b \u0d36\u0d4d\u0d30\u0d2e\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "emailCreateAccount": "\u0d2e\u0d31\u0d4d\u0d31\u0d4a\u0d30\u0d41 \u0d05\u0d15\u0d4d\u0d15\u0d57\u0d23\u0d4d\u0d1f\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d4d \u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d3e\u0d7b \u0d36\u0d4d\u0d30\u0d2e\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "callback": "\u0d2e\u0d31\u0d4d\u0d31\u0d4a\u0d30\u0d41 \u0d05\u0d15\u0d4d\u0d15\u0d57\u0d23\u0d4d\u0d1f\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d4d \u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d3e\u0d7b \u0d36\u0d4d\u0d30\u0d2e\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "oauthAccountNotLinked": "\u0d28\u0d3f\u0d19\u0d4d\u0d19\u0d33\u0d41\u0d1f\u0d46 \u0d35\u0d4d\u0d2f\u0d15\u0d4d\u0d24\u0d3f\u0d24\u0d4d\u0d35\u0d02 \u0d38\u0d4d\u0d25\u0d3f\u0d30\u0d40\u0d15\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d3e\u0d7b, \u0d06\u0d26\u0d4d\u0d2f\u0d02 \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a \u0d05\u0d24\u0d47 \u0d05\u0d15\u0d4d\u0d15\u0d57\u0d23\u0d4d\u0d1f\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d4d \u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15",
+ "emailSignin": "\u0d07\u0d2e\u0d46\u0d2f\u0d3f\u0d7d \u0d05\u0d2f\u0d2f\u0d4d\u0d15\u0d4d\u0d15\u0d3e\u0d7b \u0d15\u0d34\u0d3f\u0d1e\u0d4d\u0d1e\u0d3f\u0d32\u0d4d\u0d32",
+ "emailVerify": "\u0d28\u0d3f\u0d19\u0d4d\u0d19\u0d33\u0d41\u0d1f\u0d46 \u0d07\u0d2e\u0d46\u0d2f\u0d3f\u0d7d \u0d2a\u0d30\u0d3f\u0d36\u0d4b\u0d27\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15, \u0d12\u0d30\u0d41 \u0d2a\u0d41\u0d24\u0d3f\u0d2f \u0d07\u0d2e\u0d46\u0d2f\u0d3f\u0d7d \u0d05\u0d2f\u0d1a\u0d4d\u0d1a\u0d3f\u0d1f\u0d4d\u0d1f\u0d41\u0d23\u0d4d\u0d1f\u0d4d",
+ "credentialsSignin": "\u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d2a\u0d30\u0d3e\u0d1c\u0d2f\u0d2a\u0d4d\u0d2a\u0d46\u0d1f\u0d4d\u0d1f\u0d41. \u0d28\u0d3f\u0d19\u0d4d\u0d19\u0d7e \u0d28\u0d7d\u0d15\u0d3f\u0d2f \u0d35\u0d3f\u0d35\u0d30\u0d19\u0d4d\u0d19\u0d7e \u0d36\u0d30\u0d3f\u0d2f\u0d3e\u0d23\u0d46\u0d28\u0d4d\u0d28\u0d4d \u0d2a\u0d30\u0d3f\u0d36\u0d4b\u0d27\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "sessionRequired": "\u0d08 \u0d2a\u0d47\u0d1c\u0d4d \u0d06\u0d15\u0d4d\u0d38\u0d38\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d3e\u0d7b \u0d26\u0d2f\u0d35\u0d3e\u0d2f\u0d3f \u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15"
+ }
+ },
+ "provider": {
+ "continue": "{{provider}} \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d4d \u0d24\u0d41\u0d1f\u0d30\u0d41\u0d15"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u0d28\u0d3f\u0d19\u0d4d\u0d19\u0d33\u0d41\u0d1f\u0d46 \u0d38\u0d28\u0d4d\u0d26\u0d47\u0d36\u0d02 \u0d07\u0d35\u0d3f\u0d1f\u0d46 \u0d1f\u0d48\u0d2a\u0d4d\u0d2a\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15...",
+ "actions": {
+ "send": "\u0d38\u0d28\u0d4d\u0d26\u0d47\u0d36\u0d02 \u0d05\u0d2f\u0d2f\u0d4d\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "stop": "\u0d1f\u0d3e\u0d38\u0d4d\u0d15\u0d4d \u0d28\u0d3f\u0d7c\u0d24\u0d4d\u0d24\u0d41\u0d15",
+ "attachFiles": "\u0d2b\u0d2f\u0d32\u0d41\u0d15\u0d7e \u0d05\u0d31\u0d4d\u0d31\u0d3e\u0d1a\u0d4d\u0d1a\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15"
+ }
+ },
+ "speech": {
+ "start": "\u0d31\u0d46\u0d15\u0d4d\u0d15\u0d4b\u0d7c\u0d21\u0d3f\u0d02\u0d17\u0d4d \u0d06\u0d30\u0d02\u0d2d\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "stop": "\u0d31\u0d46\u0d15\u0d4d\u0d15\u0d4b\u0d7c\u0d21\u0d3f\u0d02\u0d17\u0d4d \u0d28\u0d3f\u0d7c\u0d24\u0d4d\u0d24\u0d41\u0d15",
+ "connecting": "\u0d2c\u0d28\u0d4d\u0d27\u0d3f\u0d2a\u0d4d\u0d2a\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d28\u0d4d\u0d28\u0d41"
+ },
+ "fileUpload": {
+ "dragDrop": "\u0d2b\u0d2f\u0d32\u0d41\u0d15\u0d7e \u0d07\u0d35\u0d3f\u0d1f\u0d46 \u0d35\u0d32\u0d3f\u0d1a\u0d4d\u0d1a\u0d3f\u0d1f\u0d41\u0d15",
+ "browse": "\u0d2b\u0d2f\u0d32\u0d41\u0d15\u0d7e \u0d24\u0d3f\u0d30\u0d2f\u0d41\u0d15",
+ "sizeLimit": "\u0d2a\u0d30\u0d3f\u0d27\u0d3f:",
+ "errors": {
+ "failed": "\u0d05\u0d2a\u0d4d\u200c\u0d32\u0d4b\u0d21\u0d4d \u0d2a\u0d30\u0d3e\u0d1c\u0d2f\u0d2a\u0d4d\u0d2a\u0d46\u0d1f\u0d4d\u0d1f\u0d41",
+ "cancelled": "\u0d05\u0d2a\u0d4d\u200c\u0d32\u0d4b\u0d21\u0d4d \u0d31\u0d26\u0d4d\u0d26\u0d3e\u0d15\u0d4d\u0d15\u0d3f"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d28\u0d4d\u0d28\u0d41",
+ "used": "\u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d41"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u0d15\u0d4d\u0d32\u0d3f\u0d2a\u0d4d\u0d2a\u0d4d\u0d2c\u0d4b\u0d7c\u0d21\u0d3f\u0d32\u0d47\u0d15\u0d4d\u0d15\u0d4d \u0d2a\u0d15\u0d7c\u0d24\u0d4d\u0d24\u0d41\u0d15",
+ "success": "\u0d2a\u0d15\u0d7c\u0d24\u0d4d\u0d24\u0d3f!"
+ }
+ },
+ "feedback": {
+ "positive": "\u0d38\u0d39\u0d3e\u0d2f\u0d15\u0d30\u0d02",
+ "negative": "\u0d38\u0d39\u0d3e\u0d2f\u0d15\u0d30\u0d2e\u0d32\u0d4d\u0d32",
+ "edit": "\u0d2b\u0d40\u0d21\u0d4d\u0d2c\u0d3e\u0d15\u0d4d\u0d15\u0d4d \u0d0e\u0d21\u0d3f\u0d31\u0d4d\u0d31\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15",
+ "dialog": {
+ "title": "\u0d12\u0d30\u0d41 \u0d15\u0d2e\u0d28\u0d4d\u0d31\u0d4d \u0d1a\u0d47\u0d7c\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "submit": "\u0d2b\u0d40\u0d21\u0d4d\u0d2c\u0d3e\u0d15\u0d4d\u0d15\u0d4d \u0d38\u0d2e\u0d7c\u0d2a\u0d4d\u0d2a\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15"
+ },
+ "status": {
+ "updating": "\u0d05\u0d2a\u0d4d\u0d21\u0d47\u0d31\u0d4d\u0d31\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d28\u0d4d\u0d28\u0d41",
+ "updated": "\u0d2b\u0d40\u0d21\u0d4d\u0d2c\u0d3e\u0d15\u0d4d\u0d15\u0d4d \u0d05\u0d2a\u0d4d\u0d21\u0d47\u0d31\u0d4d\u0d31\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d24\u0d41"
+ }
+ }
+ },
+ "history": {
+ "title": "\u0d05\u0d35\u0d38\u0d3e\u0d28 \u0d07\u0d7b\u0d2a\u0d41\u0d1f\u0d4d\u0d1f\u0d41\u0d15\u0d7e",
+ "empty": "\u0d12\u0d28\u0d4d\u0d28\u0d41\u0d2e\u0d3f\u0d32\u0d4d\u0d32...",
+ "show": "\u0d39\u0d3f\u0d38\u0d4d\u0d31\u0d4d\u0d31\u0d31\u0d3f \u0d15\u0d3e\u0d23\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15"
+ },
+ "settings": {
+ "title": "\u0d15\u0d4d\u0d30\u0d2e\u0d40\u0d15\u0d30\u0d23\u0d19\u0d4d\u0d19\u0d7e \u0d2a\u0d3e\u0d28\u0d7d"
+ },
+ "watermark": "\u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d4d \u0d28\u0d3f\u0d7c\u0d2e\u0d4d\u0d2e\u0d3f\u0d1a\u0d4d\u0d1a\u0d24\u0d4d"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u0d2e\u0d41\u0d7b \u0d1a\u0d3e\u0d31\u0d4d\u0d31\u0d41\u0d15\u0d7e",
+ "filters": {
+ "search": "\u0d24\u0d3f\u0d30\u0d2f\u0d41\u0d15",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u0d07\u0d28\u0d4d\u0d28\u0d4d",
+ "yesterday": "\u0d07\u0d28\u0d4d\u0d28\u0d32\u0d46",
+ "previous7days": "\u0d15\u0d34\u0d3f\u0d1e\u0d4d\u0d1e 7 \u0d26\u0d3f\u0d35\u0d38\u0d02",
+ "previous30days": "\u0d15\u0d34\u0d3f\u0d1e\u0d4d\u0d1e 30 \u0d26\u0d3f\u0d35\u0d38\u0d02"
+ },
+ "empty": "\u0d24\u0d4d\u0d30\u0d46\u0d21\u0d41\u0d15\u0d7e \u0d15\u0d23\u0d4d\u0d1f\u0d46\u0d24\u0d4d\u0d24\u0d3f\u0d2f\u0d3f\u0d32\u0d4d\u0d32",
+ "actions": {
+ "close": "\u0d38\u0d48\u0d21\u0d4d\u0d2c\u0d3e\u0d7c \u0d05\u0d1f\u0d2f\u0d4d\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "open": "\u0d38\u0d48\u0d21\u0d4d\u0d2c\u0d3e\u0d7c \u0d24\u0d41\u0d31\u0d15\u0d4d\u0d15\u0d41\u0d15"
+ }
+ },
+ "thread": {
+ "untitled": "\u0d2a\u0d47\u0d30\u0d3f\u0d32\u0d4d\u0d32\u0d3e\u0d24\u0d4d\u0d24 \u0d38\u0d02\u0d2d\u0d3e\u0d37\u0d23\u0d02",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u0d21\u0d3f\u0d32\u0d40\u0d31\u0d4d\u0d31\u0d4d \u0d38\u0d4d\u0d25\u0d3f\u0d30\u0d40\u0d15\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "description": "\u0d07\u0d24\u0d4d \u0d24\u0d4d\u0d30\u0d46\u0d21\u0d41\u0d02 \u0d05\u0d24\u0d3f\u0d28\u0d4d\u0d31\u0d46 \u0d38\u0d28\u0d4d\u0d26\u0d47\u0d36\u0d19\u0d4d\u0d19\u0d33\u0d41\u0d02 \u0d18\u0d1f\u0d15\u0d19\u0d4d\u0d19\u0d33\u0d41\u0d02 \u0d21\u0d3f\u0d32\u0d40\u0d31\u0d4d\u0d31\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d02. \u0d08 \u0d2a\u0d4d\u0d30\u0d35\u0d7c\u0d24\u0d4d\u0d24\u0d3f \u0d2a\u0d34\u0d2f\u0d2a\u0d1f\u0d3f\u0d2f\u0d3e\u0d15\u0d4d\u0d15\u0d3e\u0d7b \u0d15\u0d34\u0d3f\u0d2f\u0d3f\u0d32\u0d4d\u0d32",
+ "success": "\u0d1a\u0d3e\u0d31\u0d4d\u0d31\u0d4d \u0d21\u0d3f\u0d32\u0d40\u0d31\u0d4d\u0d31\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d24\u0d41",
+ "inProgress": "\u0d1a\u0d3e\u0d31\u0d4d\u0d31\u0d4d \u0d21\u0d3f\u0d32\u0d40\u0d31\u0d4d\u0d31\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d28\u0d4d\u0d28\u0d41"
+ },
+ "rename": {
+ "title": "\u0d24\u0d4d\u0d30\u0d46\u0d21\u0d4d \u0d2a\u0d41\u0d28\u0d7c\u0d28\u0d3e\u0d2e\u0d15\u0d30\u0d23\u0d02 \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15",
+ "description": "\u0d08 \u0d24\u0d4d\u0d30\u0d46\u0d21\u0d3f\u0d28\u0d4d \u0d12\u0d30\u0d41 \u0d2a\u0d41\u0d24\u0d3f\u0d2f \u0d2a\u0d47\u0d30\u0d4d \u0d28\u0d7d\u0d15\u0d41\u0d15",
+ "form": {
+ "name": {
+ "label": "\u0d2a\u0d47\u0d30\u0d4d",
+ "placeholder": "\u0d2a\u0d41\u0d24\u0d3f\u0d2f \u0d2a\u0d47\u0d30\u0d4d \u0d28\u0d7d\u0d15\u0d41\u0d15"
+ }
+ },
+ "success": "\u0d24\u0d4d\u0d30\u0d46\u0d21\u0d4d \u0d2a\u0d41\u0d28\u0d7c\u0d28\u0d3e\u0d2e\u0d15\u0d30\u0d23\u0d02 \u0d1a\u0d46\u0d2f\u0d4d\u0d24\u0d41!",
+ "inProgress": "\u0d24\u0d4d\u0d30\u0d46\u0d21\u0d4d \u0d2a\u0d41\u0d28\u0d7c\u0d28\u0d3e\u0d2e\u0d15\u0d30\u0d23\u0d02 \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d28\u0d4d\u0d28\u0d41"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u0d1a\u0d3e\u0d31\u0d4d\u0d31\u0d4d",
+ "readme": "\u0d35\u0d3e\u0d2f\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u0d2a\u0d41\u0d24\u0d3f\u0d2f \u0d1a\u0d3e\u0d31\u0d4d\u0d31\u0d4d",
+ "dialog": {
+ "title": "\u0d2a\u0d41\u0d24\u0d3f\u0d2f \u0d1a\u0d3e\u0d31\u0d4d\u0d31\u0d4d \u0d38\u0d43\u0d37\u0d4d\u0d1f\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "description": "\u0d07\u0d24\u0d4d \u0d28\u0d3f\u0d19\u0d4d\u0d19\u0d33\u0d41\u0d1f\u0d46 \u0d28\u0d3f\u0d32\u0d35\u0d3f\u0d32\u0d46 \u0d1a\u0d3e\u0d31\u0d4d\u0d31\u0d4d \u0d39\u0d3f\u0d38\u0d4d\u0d31\u0d4d\u0d31\u0d31\u0d3f \u0d2e\u0d3e\u0d2f\u0d4d\u0d15\u0d4d\u0d15\u0d41\u0d02. \u0d24\u0d41\u0d1f\u0d30\u0d3e\u0d7b \u0d24\u0d3e\u0d7d\u0d2a\u0d4d\u0d2a\u0d30\u0d4d\u0d2f\u0d2e\u0d41\u0d23\u0d4d\u0d1f\u0d4b?",
+ "tooltip": "\u0d2a\u0d41\u0d24\u0d3f\u0d2f \u0d1a\u0d3e\u0d31\u0d4d\u0d31\u0d4d"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u0d15\u0d4d\u0d30\u0d2e\u0d40\u0d15\u0d30\u0d23\u0d19\u0d4d\u0d19\u0d7e",
+ "settingsKey": "S",
+ "apiKeys": "API \u0d15\u0d40\u0d15\u0d7e",
+ "logout": "\u0d32\u0d4b\u0d17\u0d4d\u0d14\u0d1f\u0d4d\u0d1f\u0d4d"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u0d06\u0d35\u0d36\u0d4d\u0d2f\u0d2e\u0d3e\u0d2f API \u0d15\u0d40\u0d15\u0d7e",
+ "description": "\u0d08 \u0d06\u0d2a\u0d4d\u0d2a\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d15\u0d4d\u0d15\u0d3e\u0d7b, \u0d24\u0d3e\u0d34\u0d46\u0d2a\u0d4d\u0d2a\u0d31\u0d2f\u0d41\u0d28\u0d4d\u0d28 API \u0d15\u0d40\u0d15\u0d7e \u0d06\u0d35\u0d36\u0d4d\u0d2f\u0d2e\u0d3e\u0d23\u0d4d. \u0d15\u0d40\u0d15\u0d7e \u0d28\u0d3f\u0d19\u0d4d\u0d19\u0d33\u0d41\u0d1f\u0d46 \u0d09\u0d2a\u0d15\u0d30\u0d23\u0d24\u0d4d\u0d24\u0d3f\u0d28\u0d4d\u0d31\u0d46 \u0d32\u0d4b\u0d15\u0d4d\u0d15\u0d7d \u0d38\u0d4d\u0d31\u0d4d\u0d31\u0d4b\u0d31\u0d47\u0d1c\u0d3f\u0d7d \u0d38\u0d02\u0d2d\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d2a\u0d4d\u0d2a\u0d46\u0d1f\u0d41\u0d28\u0d4d\u0d28\u0d41.",
+ "success": {
+ "saved": "\u0d35\u0d3f\u0d1c\u0d2f\u0d15\u0d30\u0d2e\u0d3e\u0d2f\u0d3f \u0d38\u0d02\u0d30\u0d15\u0d4d\u0d37\u0d3f\u0d1a\u0d4d\u0d1a\u0d41"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/mr.json b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/mr.json
new file mode 100644
index 00000000..04a990b8
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/mr.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u0930\u0926\u094d\u0926 \u0915\u0930\u093e",
+ "confirm": "\u092a\u0941\u0937\u094d\u091f\u0940 \u0915\u0930\u093e",
+ "continue": "\u092a\u0941\u0922\u0947 \u091c\u093e",
+ "goBack": "\u092e\u093e\u0917\u0947 \u091c\u093e",
+ "reset": "\u0930\u0940\u0938\u0947\u091f \u0915\u0930\u093e",
+ "submit": "\u0938\u092c\u092e\u093f\u091f \u0915\u0930\u093e"
+ },
+ "status": {
+ "loading": "\u0932\u094b\u0921 \u0915\u0930\u0924 \u0906\u0939\u0947...",
+ "error": {
+ "default": "\u090f\u0915 \u0924\u094d\u0930\u0941\u091f\u0940 \u0906\u0932\u0940",
+ "serverConnection": "\u0938\u0930\u094d\u0935\u094d\u0939\u0930\u0936\u0940 \u0915\u0928\u0947\u0915\u094d\u091f \u0939\u094b\u090a \u0936\u0915\u0932\u0947 \u0928\u093e\u0939\u0940"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u0905\u0945\u092a \u0935\u093e\u092a\u0930\u0923\u094d\u092f\u093e\u0938\u093e\u0920\u0940 \u0932\u0949\u0917\u093f\u0928 \u0915\u0930\u093e",
+ "form": {
+ "email": {
+ "label": "\u0908\u092e\u0947\u0932 \u092a\u0924\u094d\u0924\u093e",
+ "required": "\u0908\u092e\u0947\u0932 \u0906\u0935\u0936\u094d\u092f\u0915 \u0906\u0939\u0947"
+ },
+ "password": {
+ "label": "\u092a\u093e\u0938\u0935\u0930\u094d\u0921",
+ "required": "\u092a\u093e\u0938\u0935\u0930\u094d\u0921 \u0906\u0935\u0936\u094d\u092f\u0915 \u0906\u0939\u0947"
+ },
+ "actions": {
+ "signin": "\u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u093e"
+ },
+ "alternativeText": {
+ "or": "\u0915\u093f\u0902\u0935\u093e"
+ }
+ },
+ "errors": {
+ "default": "\u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0942 \u0936\u0915\u0924 \u0928\u093e\u0939\u0940",
+ "signin": "\u0935\u0947\u0917\u0933\u094d\u092f\u093e \u0916\u093e\u0924\u094d\u092f\u093e\u0928\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0923\u094d\u092f\u093e\u091a\u093e \u092a\u094d\u0930\u092f\u0924\u094d\u0928 \u0915\u0930\u093e",
+ "oauthSignin": "\u0935\u0947\u0917\u0933\u094d\u092f\u093e \u0916\u093e\u0924\u094d\u092f\u093e\u0928\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0923\u094d\u092f\u093e\u091a\u093e \u092a\u094d\u0930\u092f\u0924\u094d\u0928 \u0915\u0930\u093e",
+ "redirectUriMismatch": "\u0930\u0940\u0921\u093e\u092f\u0930\u0947\u0915\u094d\u091f URI \u0913\u0925 \u0905\u0945\u092a \u0915\u0949\u0928\u094d\u092b\u093f\u0917\u0930\u0947\u0936\u0928\u0936\u0940 \u091c\u0941\u0933\u0924 \u0928\u093e\u0939\u0940",
+ "oauthCallback": "\u0935\u0947\u0917\u0933\u094d\u092f\u093e \u0916\u093e\u0924\u094d\u092f\u093e\u0928\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0923\u094d\u092f\u093e\u091a\u093e \u092a\u094d\u0930\u092f\u0924\u094d\u0928 \u0915\u0930\u093e",
+ "oauthCreateAccount": "\u0935\u0947\u0917\u0933\u094d\u092f\u093e \u0916\u093e\u0924\u094d\u092f\u093e\u0928\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0923\u094d\u092f\u093e\u091a\u093e \u092a\u094d\u0930\u092f\u0924\u094d\u0928 \u0915\u0930\u093e",
+ "emailCreateAccount": "\u0935\u0947\u0917\u0933\u094d\u092f\u093e \u0916\u093e\u0924\u094d\u092f\u093e\u0928\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0923\u094d\u092f\u093e\u091a\u093e \u092a\u094d\u0930\u092f\u0924\u094d\u0928 \u0915\u0930\u093e",
+ "callback": "\u0935\u0947\u0917\u0933\u094d\u092f\u093e \u0916\u093e\u0924\u094d\u092f\u093e\u0928\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0923\u094d\u092f\u093e\u091a\u093e \u092a\u094d\u0930\u092f\u0924\u094d\u0928 \u0915\u0930\u093e",
+ "oauthAccountNotLinked": "\u0924\u0941\u092e\u091a\u0940 \u0913\u0933\u0916 \u092a\u091f\u0935\u0923\u094d\u092f\u093e\u0938\u093e\u0920\u0940, \u092e\u0942\u0933 \u0935\u093e\u092a\u0930\u0932\u0947\u0932\u094d\u092f\u093e \u0916\u093e\u0924\u094d\u092f\u093e\u0928\u0947\u091a \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u093e",
+ "emailSignin": "\u0908\u092e\u0947\u0932 \u092a\u093e\u0920\u0935\u0942 \u0936\u0915\u0932\u0947 \u0928\u093e\u0939\u0940",
+ "emailVerify": "\u0915\u0943\u092a\u092f\u093e \u0924\u0941\u092e\u091a\u093e \u0908\u092e\u0947\u0932 \u0924\u092a\u093e\u0938\u093e, \u0928\u0935\u0940\u0928 \u0908\u092e\u0947\u0932 \u092a\u093e\u0920\u0935\u0932\u093e \u0917\u0947\u0932\u093e \u0906\u0939\u0947",
+ "credentialsSignin": "\u0938\u093e\u0907\u0928 \u0907\u0928 \u0905\u092f\u0936\u0938\u094d\u0935\u0940. \u0924\u0941\u092e\u094d\u0939\u0940 \u0926\u093f\u0932\u0947\u0932\u0940 \u092e\u093e\u0939\u093f\u0924\u0940 \u092f\u094b\u0917\u094d\u092f \u0906\u0939\u0947 \u0915\u093e \u0924\u0947 \u0924\u092a\u093e\u0938\u093e",
+ "sessionRequired": "\u092f\u093e \u092a\u0943\u0937\u094d\u0920\u093e\u0935\u0930 \u092a\u094d\u0930\u0935\u0947\u0936 \u0915\u0930\u0923\u094d\u092f\u093e\u0938\u093e\u0920\u0940 \u0915\u0943\u092a\u092f\u093e \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u093e"
+ }
+ },
+ "provider": {
+ "continue": "{{provider}} \u0938\u0939 \u092a\u0941\u0922\u0947 \u091c\u093e"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u0924\u0941\u092e\u091a\u093e \u0938\u0902\u0926\u0947\u0936 \u092f\u0947\u0925\u0947 \u091f\u093e\u0907\u092a \u0915\u0930\u093e...",
+ "actions": {
+ "send": "\u0938\u0902\u0926\u0947\u0936 \u092a\u093e\u0920\u0935\u093e",
+ "stop": "\u0915\u093e\u0930\u094d\u092f \u0925\u093e\u0902\u092c\u0935\u093e",
+ "attachFiles": "\u092b\u093e\u0907\u0932\u094d\u0938 \u091c\u094b\u0921\u093e"
+ }
+ },
+ "speech": {
+ "start": "\u0930\u0947\u0915\u0949\u0930\u094d\u0921\u093f\u0902\u0917 \u0938\u0941\u0930\u0942 \u0915\u0930\u093e",
+ "stop": "\u0930\u0947\u0915\u0949\u0930\u094d\u0921\u093f\u0902\u0917 \u0925\u093e\u0902\u092c\u0935\u093e",
+ "connecting": "\u0915\u0928\u0947\u0915\u094d\u091f \u0915\u0930\u0924 \u0906\u0939\u0947"
+ },
+ "fileUpload": {
+ "dragDrop": "\u092b\u093e\u0907\u0932\u094d\u0938 \u092f\u0947\u0925\u0947 \u0921\u094d\u0930\u0945\u0917 \u0906\u0923\u093f \u0921\u094d\u0930\u0949\u092a \u0915\u0930\u093e",
+ "browse": "\u092b\u093e\u0907\u0932\u094d\u0938 \u092c\u094d\u0930\u093e\u0909\u091d \u0915\u0930\u093e",
+ "sizeLimit": "\u092e\u0930\u094d\u092f\u093e\u0926\u093e:",
+ "errors": {
+ "failed": "\u0905\u092a\u0932\u094b\u0921 \u0905\u092f\u0936\u0938\u094d\u0935\u0940",
+ "cancelled": "\u092f\u093e\u0902\u091a\u0947 \u0905\u092a\u0932\u094b\u0921 \u0930\u0926\u094d\u0926 \u0915\u0947\u0932\u0947"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u0935\u093e\u092a\u0930\u0924 \u0906\u0939\u0947",
+ "used": "\u0935\u093e\u092a\u0930\u0932\u0947"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u0915\u094d\u0932\u093f\u092a\u092c\u094b\u0930\u094d\u0921\u0935\u0930 \u0915\u0949\u092a\u0940 \u0915\u0930\u093e",
+ "success": "\u0915\u0949\u092a\u0940 \u0915\u0947\u0932\u0947!"
+ }
+ },
+ "feedback": {
+ "positive": "\u0909\u092a\u092f\u0941\u0915\u094d\u0924",
+ "negative": "\u0909\u092a\u092f\u0941\u0915\u094d\u0924 \u0928\u093e\u0939\u0940",
+ "edit": "\u092b\u0940\u0921\u092c\u0945\u0915 \u0938\u0902\u092a\u093e\u0926\u093f\u0924 \u0915\u0930\u093e",
+ "dialog": {
+ "title": "\u091f\u093f\u092a\u094d\u092a\u0923\u0940 \u091c\u094b\u0921\u093e",
+ "submit": "\u092b\u0940\u0921\u092c\u0945\u0915 \u0938\u092c\u092e\u093f\u091f \u0915\u0930\u093e"
+ },
+ "status": {
+ "updating": "\u0905\u092a\u0921\u0947\u091f \u0915\u0930\u0924 \u0906\u0939\u0947",
+ "updated": "\u092b\u0940\u0921\u092c\u0945\u0915 \u0905\u092a\u0921\u0947\u091f \u0915\u0947\u0932\u0947"
+ }
+ }
+ },
+ "history": {
+ "title": "\u0936\u0947\u0935\u091f\u091a\u0947 \u0907\u0928\u092a\u0941\u091f",
+ "empty": "\u0930\u093f\u0915\u093e\u092e\u0947 \u0906\u0939\u0947...",
+ "show": "\u0907\u0924\u093f\u0939\u093e\u0938 \u0926\u093e\u0916\u0935\u093e"
+ },
+ "settings": {
+ "title": "\u0938\u0947\u091f\u093f\u0902\u0917\u094d\u091c \u092a\u0945\u0928\u0932"
+ },
+ "watermark": "\u0938\u0939 \u092c\u0928\u0935\u0932\u0947"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u092e\u093e\u0917\u0940\u0932 \u091a\u0945\u091f\u094d\u0938",
+ "filters": {
+ "search": "\u0936\u094b\u0927\u093e",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u0906\u091c",
+ "yesterday": "\u0915\u093e\u0932",
+ "previous7days": "\u092e\u093e\u0917\u0940\u0932 7 \u0926\u093f\u0935\u0938",
+ "previous30days": "\u092e\u093e\u0917\u0940\u0932 30 \u0926\u093f\u0935\u0938"
+ },
+ "empty": "\u0915\u094b\u0923\u0924\u0947\u0939\u0940 \u0925\u094d\u0930\u0947\u0921 \u0938\u093e\u092a\u0921\u0932\u0947 \u0928\u093e\u0939\u0940\u0924",
+ "actions": {
+ "close": "\u0938\u093e\u0907\u0921\u092c\u093e\u0930 \u092c\u0902\u0926 \u0915\u0930\u093e",
+ "open": "\u0938\u093e\u0907\u0921\u092c\u093e\u0930 \u0909\u0918\u0921\u093e"
+ }
+ },
+ "thread": {
+ "untitled": "\u0936\u0940\u0930\u094d\u0937\u0915\u0935\u093f\u0930\u0939\u093f\u0924 \u0938\u0902\u092d\u093e\u0937\u0923",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u0939\u091f\u0935\u093f\u0923\u094d\u092f\u093e\u091a\u0940 \u092a\u0941\u0937\u094d\u091f\u0940 \u0915\u0930\u093e",
+ "description": "\u0939\u0947 \u0925\u094d\u0930\u0947\u0921 \u0906\u0923\u093f \u0924\u094d\u092f\u093e\u091a\u0947 \u0938\u0902\u0926\u0947\u0936 \u0935 \u0918\u091f\u0915 \u0939\u091f\u0935\u0947\u0932. \u0939\u0940 \u0915\u094d\u0930\u093f\u092f\u093e \u092a\u0942\u0930\u094d\u0935\u0935\u0924 \u0915\u0947\u0932\u0940 \u091c\u093e\u090a \u0936\u0915\u0924 \u0928\u093e\u0939\u0940",
+ "success": "\u091a\u0945\u091f \u0939\u091f\u0935\u0932\u093e",
+ "inProgress": "\u091a\u0945\u091f \u0939\u091f\u0935\u0924 \u0906\u0939\u0947"
+ },
+ "rename": {
+ "title": "\u0925\u094d\u0930\u0947\u0921\u091a\u0947 \u0928\u093e\u0935 \u092c\u0926\u0932\u093e",
+ "description": "\u092f\u093e \u0925\u094d\u0930\u0947\u0921\u0938\u093e\u0920\u0940 \u0928\u0935\u0940\u0928 \u0928\u093e\u0935 \u092a\u094d\u0930\u0935\u093f\u0937\u094d\u091f \u0915\u0930\u093e",
+ "form": {
+ "name": {
+ "label": "\u0928\u093e\u0935",
+ "placeholder": "\u0928\u0935\u0940\u0928 \u0928\u093e\u0935 \u092a\u094d\u0930\u0935\u093f\u0937\u094d\u091f \u0915\u0930\u093e"
+ }
+ },
+ "success": "\u0925\u094d\u0930\u0947\u0921\u091a\u0947 \u0928\u093e\u0935 \u092c\u0926\u0932\u0932\u0947!",
+ "inProgress": "\u0925\u094d\u0930\u0947\u0921\u091a\u0947 \u0928\u093e\u0935 \u092c\u0926\u0932\u0924 \u0906\u0939\u0947"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u091a\u0945\u091f",
+ "readme": "\u0935\u093e\u091a\u093e",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u0928\u0935\u0940\u0928 \u091a\u0945\u091f",
+ "dialog": {
+ "title": "\u0928\u0935\u0940\u0928 \u091a\u0945\u091f \u0924\u092f\u093e\u0930 \u0915\u0930\u093e",
+ "description": "\u0939\u0947 \u0924\u0941\u092e\u091a\u093e \u0938\u0927\u094d\u092f\u093e\u091a\u093e \u091a\u0945\u091f \u0907\u0924\u093f\u0939\u093e\u0938 \u0938\u093e\u092b \u0915\u0930\u0947\u0932. \u0924\u0941\u092e\u094d\u0939\u093e\u0932\u093e \u0916\u093e\u0924\u094d\u0930\u0940 \u0906\u0939\u0947 \u0915\u0940 \u0924\u0941\u092e\u094d\u0939\u0940 \u092a\u0941\u0922\u0947 \u091c\u093e\u090a \u0907\u091a\u094d\u091b\u093f\u0924\u093e?",
+ "tooltip": "\u0928\u0935\u0940\u0928 \u091a\u0945\u091f"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u0938\u0947\u091f\u093f\u0902\u0917\u094d\u091c",
+ "settingsKey": "S",
+ "apiKeys": "API \u0915\u0940\u091c",
+ "logout": "\u0932\u0949\u0917\u0906\u0909\u091f"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u0906\u0935\u0936\u094d\u092f\u0915 API \u0915\u0940\u091c",
+ "description": "\u0939\u0947 \u0905\u0945\u092a \u0935\u093e\u092a\u0930\u0923\u094d\u092f\u093e\u0938\u093e\u0920\u0940 \u0916\u093e\u0932\u0940\u0932 API \u0915\u0940\u091c \u0906\u0935\u0936\u094d\u092f\u0915 \u0906\u0939\u0947\u0924. \u0915\u0940\u091c \u0924\u0941\u092e\u091a\u094d\u092f\u093e \u0921\u093f\u0935\u094d\u0939\u093e\u0907\u0938\u091a\u094d\u092f\u093e \u0932\u094b\u0915\u0932 \u0938\u094d\u091f\u094b\u0930\u0947\u091c\u092e\u0927\u094d\u092f\u0947 \u0938\u093e\u0920\u0935\u0932\u094d\u092f\u093e \u091c\u093e\u0924\u093e\u0924.",
+ "success": {
+ "saved": "\u092f\u0936\u0938\u094d\u0935\u0940\u0930\u093f\u0924\u094d\u092f\u093e \u091c\u0924\u0928 \u0915\u0947\u0932\u0947"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/nl.json b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/nl.json
new file mode 100644
index 00000000..ed331152
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/nl.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "Annuleren",
+ "confirm": "Bevestigen",
+ "continue": "Doorgaan",
+ "goBack": "Terug",
+ "reset": "Herstellen",
+ "submit": "Versturen"
+ },
+ "status": {
+ "loading": "Laden...",
+ "error": {
+ "default": "Er is een fout opgetreden",
+ "serverConnection": "Kon geen verbinding maken met de server"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "Inloggen om toegang te krijgen tot de app",
+ "form": {
+ "email": {
+ "label": "E-mailadres",
+ "required": "e-mail is een verplicht veld"
+ },
+ "password": {
+ "label": "Wachtwoord",
+ "required": "wachtwoord is een verplicht veld"
+ },
+ "actions": {
+ "signin": "Inloggen"
+ },
+ "alternativeText": {
+ "or": "OF"
+ }
+ },
+ "errors": {
+ "default": "Kan niet inloggen",
+ "signin": "Probeer in te loggen met een ander account",
+ "oauthSignin": "Probeer in te loggen met een ander account",
+ "redirectUriMismatch": "De redirect URI komt niet overeen met de oauth app configuratie",
+ "oauthCallback": "Probeer in te loggen met een ander account",
+ "oauthCreateAccount": "Probeer in te loggen met een ander account",
+ "emailCreateAccount": "Probeer in te loggen met een ander account",
+ "callback": "Probeer in te loggen met een ander account",
+ "oauthAccountNotLinked": "Om je identiteit te bevestigen, log in met hetzelfde account dat je oorspronkelijk hebt gebruikt",
+ "emailSignin": "De e-mail kon niet worden verzonden",
+ "emailVerify": "Verifieer je e-mail, er is een nieuwe e-mail verzonden",
+ "credentialsSignin": "Inloggen mislukt. Controleer of de ingevoerde gegevens correct zijn",
+ "sessionRequired": "Log in om toegang te krijgen tot deze pagina"
+ }
+ },
+ "provider": {
+ "continue": "Doorgaan met {{provider}}"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "Typ hier je bericht...",
+ "actions": {
+ "send": "Bericht versturen",
+ "stop": "Taak stoppen",
+ "attachFiles": "Bestanden bijvoegen"
+ }
+ },
+ "speech": {
+ "start": "Start opname",
+ "stop": "Stop opname",
+ "connecting": "Verbinden"
+ },
+ "fileUpload": {
+ "dragDrop": "Sleep bestanden hierheen",
+ "browse": "Bestanden zoeken",
+ "sizeLimit": "Limiet:",
+ "errors": {
+ "failed": "Uploaden mislukt",
+ "cancelled": "Upload geannuleerd van"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "In gebruik",
+ "used": "Gebruikt"
+ },
+ "actions": {
+ "copy": {
+ "button": "Kopi\u00ebren naar klembord",
+ "success": "Gekopieerd!"
+ }
+ },
+ "feedback": {
+ "positive": "Nuttig",
+ "negative": "Niet nuttig",
+ "edit": "Feedback bewerken",
+ "dialog": {
+ "title": "Voeg een opmerking toe",
+ "submit": "Feedback versturen"
+ },
+ "status": {
+ "updating": "Bijwerken",
+ "updated": "Feedback bijgewerkt"
+ }
+ }
+ },
+ "history": {
+ "title": "Laatste invoer",
+ "empty": "Zo leeg...",
+ "show": "Toon geschiedenis"
+ },
+ "settings": {
+ "title": "Instellingenpaneel"
+ },
+ "watermark": "Gebouwd met"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "Eerdere chats",
+ "filters": {
+ "search": "Zoeken",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "Vandaag",
+ "yesterday": "Gisteren",
+ "previous7days": "Afgelopen 7 dagen",
+ "previous30days": "Afgelopen 30 dagen"
+ },
+ "empty": "Geen gesprekken gevonden",
+ "actions": {
+ "close": "Zijbalk sluiten",
+ "open": "Zijbalk openen"
+ }
+ },
+ "thread": {
+ "untitled": "Naamloos gesprek",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "Verwijdering bevestigen",
+ "description": "Dit zal het gesprek en bijbehorende berichten en elementen verwijderen. Deze actie kan niet ongedaan worden gemaakt",
+ "success": "Chat verwijderd",
+ "inProgress": "Chat verwijderen"
+ },
+ "rename": {
+ "title": "Gesprek hernoemen",
+ "description": "Voer een nieuwe naam in voor dit gesprek",
+ "form": {
+ "name": {
+ "label": "Naam",
+ "placeholder": "Voer nieuwe naam in"
+ }
+ },
+ "success": "Gesprek hernoemd!",
+ "inProgress": "Gesprek hernoemen"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "Chat",
+ "readme": "Leesmij",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "Nieuwe chat",
+ "dialog": {
+ "title": "Nieuwe chat aanmaken",
+ "description": "Dit zal je huidige chatgeschiedenis wissen. Weet je zeker dat je door wilt gaan?",
+ "tooltip": "Nieuwe chat"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "Instellingen",
+ "settingsKey": "I",
+ "apiKeys": "API-sleutels",
+ "logout": "Uitloggen"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "Vereiste API-sleutels",
+ "description": "Om deze app te gebruiken zijn de volgende API-sleutels vereist. De sleutels worden opgeslagen in de lokale opslag van je apparaat.",
+ "success": {
+ "saved": "Succesvol opgeslagen"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/ta.json b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/ta.json
new file mode 100644
index 00000000..69900727
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/ta.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u0bb0\u0ba4\u0bcd\u0ba4\u0bc1 \u0b9a\u0bc6\u0baf\u0bcd",
+ "confirm": "\u0b89\u0bb1\u0bc1\u0ba4\u0bbf\u0baa\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1",
+ "continue": "\u0ba4\u0bca\u0b9f\u0bb0\u0bcd\u0b95",
+ "goBack": "\u0ba4\u0bbf\u0bb0\u0bc1\u0bae\u0bcd\u0baa\u0bbf\u0b9a\u0bcd \u0b9a\u0bc6\u0bb2\u0bcd",
+ "reset": "\u0bae\u0bc0\u0b9f\u0bcd\u0b9f\u0bae\u0bc8",
+ "submit": "\u0b9a\u0bae\u0bb0\u0bcd\u0baa\u0bcd\u0baa\u0bbf"
+ },
+ "status": {
+ "loading": "\u0b8f\u0bb1\u0bcd\u0bb1\u0bc1\u0b95\u0bbf\u0bb1\u0ba4\u0bc1...",
+ "error": {
+ "default": "\u0baa\u0bbf\u0bb4\u0bc8 \u0b8f\u0bb1\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1",
+ "serverConnection": "\u0b9a\u0bc7\u0bb5\u0bc8\u0baf\u0b95\u0ba4\u0bcd\u0ba4\u0bc8 \u0b85\u0b9f\u0bc8\u0baf \u0bae\u0bc1\u0b9f\u0bbf\u0baf\u0bb5\u0bbf\u0bb2\u0bcd\u0bb2\u0bc8"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u0baa\u0baf\u0ba9\u0bcd\u0baa\u0bbe\u0b9f\u0bcd\u0b9f\u0bc8 \u0b85\u0ba3\u0bc1\u0b95 \u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf\u0bb5\u0bc1\u0bae\u0bcd",
+ "form": {
+ "email": {
+ "label": "\u0bae\u0bbf\u0ba9\u0bcd\u0ba9\u0b9e\u0bcd\u0b9a\u0bb2\u0bcd \u0bae\u0bc1\u0b95\u0bb5\u0bb0\u0bbf",
+ "required": "\u0bae\u0bbf\u0ba9\u0bcd\u0ba9\u0b9e\u0bcd\u0b9a\u0bb2\u0bcd \u0ba4\u0bc7\u0bb5\u0bc8\u0baf\u0bbe\u0ba9 \u0baa\u0bc1\u0bb2\u0bae\u0bcd"
+ },
+ "password": {
+ "label": "\u0b95\u0b9f\u0bb5\u0bc1\u0b9a\u0bcd\u0b9a\u0bca\u0bb2\u0bcd",
+ "required": "\u0b95\u0b9f\u0bb5\u0bc1\u0b9a\u0bcd\u0b9a\u0bca\u0bb2\u0bcd \u0ba4\u0bc7\u0bb5\u0bc8\u0baf\u0bbe\u0ba9 \u0baa\u0bc1\u0bb2\u0bae\u0bcd"
+ },
+ "actions": {
+ "signin": "\u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0b95"
+ },
+ "alternativeText": {
+ "or": "\u0b85\u0bb2\u0bcd\u0bb2\u0ba4\u0bc1"
+ }
+ },
+ "errors": {
+ "default": "\u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf \u0bae\u0bc1\u0b9f\u0bbf\u0baf\u0bb5\u0bbf\u0bb2\u0bcd\u0bb2\u0bc8",
+ "signin": "\u0bb5\u0bc7\u0bb1\u0bc1 \u0b95\u0ba3\u0b95\u0bcd\u0b95\u0bc1\u0b9f\u0ba9\u0bcd \u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf \u0bae\u0bc1\u0baf\u0bb1\u0bcd\u0b9a\u0bbf\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd",
+ "oauthSignin": "\u0bb5\u0bc7\u0bb1\u0bc1 \u0b95\u0ba3\u0b95\u0bcd\u0b95\u0bc1\u0b9f\u0ba9\u0bcd \u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf \u0bae\u0bc1\u0baf\u0bb1\u0bcd\u0b9a\u0bbf\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd",
+ "redirectUriMismatch": "\u0ba4\u0bbf\u0b9a\u0bc8\u0ba4\u0bbf\u0bb0\u0bc1\u0baa\u0bcd\u0baa\u0bb2\u0bcd URI \u0b93\u0b86\u0ba4\u0bcd \u0baa\u0baf\u0ba9\u0bcd\u0baa\u0bbe\u0b9f\u0bcd\u0b9f\u0bc1 \u0b95\u0b9f\u0bcd\u0b9f\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc1\u0b9f\u0ba9\u0bcd \u0baa\u0bca\u0bb0\u0bc1\u0ba8\u0bcd\u0ba4\u0bb5\u0bbf\u0bb2\u0bcd\u0bb2\u0bc8",
+ "oauthCallback": "\u0bb5\u0bc7\u0bb1\u0bc1 \u0b95\u0ba3\u0b95\u0bcd\u0b95\u0bc1\u0b9f\u0ba9\u0bcd \u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf \u0bae\u0bc1\u0baf\u0bb1\u0bcd\u0b9a\u0bbf\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd",
+ "oauthCreateAccount": "\u0bb5\u0bc7\u0bb1\u0bc1 \u0b95\u0ba3\u0b95\u0bcd\u0b95\u0bc1\u0b9f\u0ba9\u0bcd \u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf \u0bae\u0bc1\u0baf\u0bb1\u0bcd\u0b9a\u0bbf\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd",
+ "emailCreateAccount": "\u0bb5\u0bc7\u0bb1\u0bc1 \u0b95\u0ba3\u0b95\u0bcd\u0b95\u0bc1\u0b9f\u0ba9\u0bcd \u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf \u0bae\u0bc1\u0baf\u0bb1\u0bcd\u0b9a\u0bbf\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd",
+ "callback": "\u0bb5\u0bc7\u0bb1\u0bc1 \u0b95\u0ba3\u0b95\u0bcd\u0b95\u0bc1\u0b9f\u0ba9\u0bcd \u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf \u0bae\u0bc1\u0baf\u0bb1\u0bcd\u0b9a\u0bbf\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd",
+ "oauthAccountNotLinked": "\u0b89\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b85\u0b9f\u0bc8\u0baf\u0bbe\u0bb3\u0ba4\u0bcd\u0ba4\u0bc8 \u0b89\u0bb1\u0bc1\u0ba4\u0bbf\u0baa\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4, \u0bae\u0bc1\u0ba4\u0bb2\u0bbf\u0bb2\u0bcd \u0baa\u0baf\u0ba9\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4\u0bbf\u0baf \u0b85\u0ba4\u0bc7 \u0b95\u0ba3\u0b95\u0bcd\u0b95\u0bc1\u0b9f\u0ba9\u0bcd \u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf\u0bb5\u0bc1\u0bae\u0bcd",
+ "emailSignin": "\u0bae\u0bbf\u0ba9\u0bcd\u0ba9\u0b9e\u0bcd\u0b9a\u0bb2\u0bc8 \u0b85\u0ba9\u0bc1\u0baa\u0bcd\u0baa \u0bae\u0bc1\u0b9f\u0bbf\u0baf\u0bb5\u0bbf\u0bb2\u0bcd\u0bb2\u0bc8",
+ "emailVerify": "\u0b89\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0bae\u0bbf\u0ba9\u0bcd\u0ba9\u0b9e\u0bcd\u0b9a\u0bb2\u0bc8 \u0b9a\u0bb0\u0bbf\u0baa\u0bbe\u0bb0\u0bcd\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd, \u0baa\u0bc1\u0ba4\u0bbf\u0baf \u0bae\u0bbf\u0ba9\u0bcd\u0ba9\u0b9e\u0bcd\u0b9a\u0bb2\u0bcd \u0b85\u0ba9\u0bc1\u0baa\u0bcd\u0baa\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0bc1\u0bb3\u0bcd\u0bb3\u0ba4\u0bc1",
+ "credentialsSignin": "\u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0bb5\u0bc1 \u0ba4\u0bcb\u0bb2\u0bcd\u0bb5\u0bbf\u0baf\u0b9f\u0bc8\u0ba8\u0bcd\u0ba4\u0ba4\u0bc1. \u0ba8\u0bc0\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0bb5\u0bb4\u0b99\u0bcd\u0b95\u0bbf\u0baf \u0bb5\u0bbf\u0bb5\u0bb0\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b9a\u0bb0\u0bbf\u0baf\u0bbe\u0ba9\u0bb5\u0bc8 \u0b8e\u0ba9 \u0b9a\u0bb0\u0bbf\u0baa\u0bbe\u0bb0\u0bcd\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd",
+ "sessionRequired": "\u0b87\u0ba8\u0bcd\u0ba4\u0baa\u0bcd \u0baa\u0b95\u0bcd\u0b95\u0ba4\u0bcd\u0ba4\u0bc8 \u0b85\u0ba3\u0bc1\u0b95 \u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf\u0bb5\u0bc1\u0bae\u0bcd"
+ }
+ },
+ "provider": {
+ "continue": "{{provider}} \u0bae\u0bc2\u0bb2\u0bae\u0bcd \u0ba4\u0bca\u0b9f\u0bb0\u0bb5\u0bc1\u0bae\u0bcd"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u0b89\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b9a\u0bc6\u0baf\u0bcd\u0ba4\u0bbf\u0baf\u0bc8 \u0b87\u0b99\u0bcd\u0b95\u0bc7 \u0ba4\u0b9f\u0bcd\u0b9f\u0b9a\u0bcd\u0b9a\u0bc1 \u0b9a\u0bc6\u0baf\u0bcd\u0baf\u0bb5\u0bc1\u0bae\u0bcd...",
+ "actions": {
+ "send": "\u0b9a\u0bc6\u0baf\u0bcd\u0ba4\u0bbf \u0b85\u0ba9\u0bc1\u0baa\u0bcd\u0baa\u0bc1",
+ "stop": "\u0baa\u0ba3\u0bbf\u0baf\u0bc8 \u0ba8\u0bbf\u0bb1\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1",
+ "attachFiles": "\u0b95\u0bcb\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bc8 \u0b87\u0ba3\u0bc8"
+ }
+ },
+ "speech": {
+ "start": "\u0baa\u0ba4\u0bbf\u0bb5\u0bc1 \u0ba4\u0bca\u0b9f\u0b99\u0bcd\u0b95\u0bc1",
+ "stop": "\u0baa\u0ba4\u0bbf\u0bb5\u0bc8 \u0ba8\u0bbf\u0bb1\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1",
+ "connecting": "\u0b87\u0ba3\u0bc8\u0b95\u0bcd\u0b95\u0bbf\u0bb1\u0ba4\u0bc1"
+ },
+ "fileUpload": {
+ "dragDrop": "\u0b95\u0bcb\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bc8 \u0b87\u0b99\u0bcd\u0b95\u0bc7 \u0b87\u0bb4\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1 \u0bb5\u0bbf\u0b9f\u0bb5\u0bc1\u0bae\u0bcd",
+ "browse": "\u0b95\u0bcb\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bc8 \u0b89\u0bb2\u0bbe\u0bb5\u0bc1",
+ "sizeLimit": "\u0bb5\u0bb0\u0bae\u0bcd\u0baa\u0bc1:",
+ "errors": {
+ "failed": "\u0baa\u0ba4\u0bbf\u0bb5\u0bc7\u0bb1\u0bcd\u0bb1\u0bae\u0bcd \u0ba4\u0bcb\u0bb2\u0bcd\u0bb5\u0bbf\u0baf\u0b9f\u0bc8\u0ba8\u0bcd\u0ba4\u0ba4\u0bc1",
+ "cancelled": "\u0baa\u0ba4\u0bbf\u0bb5\u0bc7\u0bb1\u0bcd\u0bb1\u0bae\u0bcd \u0bb0\u0ba4\u0bcd\u0ba4\u0bc1 \u0b9a\u0bc6\u0baf\u0bcd\u0baf\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u0baa\u0baf\u0ba9\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1\u0b95\u0bbf\u0bb1\u0ba4\u0bc1",
+ "used": "\u0baa\u0baf\u0ba9\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u0b95\u0bbf\u0bb3\u0bbf\u0baa\u0bcd\u0baa\u0bcb\u0bb0\u0bcd\u0b9f\u0bc1\u0b95\u0bcd\u0b95\u0bc1 \u0ba8\u0b95\u0bb2\u0bc6\u0b9f\u0bc1",
+ "success": "\u0ba8\u0b95\u0bb2\u0bc6\u0b9f\u0bc1\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1!"
+ }
+ },
+ "feedback": {
+ "positive": "\u0baa\u0baf\u0ba9\u0bc1\u0bb3\u0bcd\u0bb3\u0ba4\u0bbe\u0b95 \u0b87\u0bb0\u0bc1\u0ba8\u0bcd\u0ba4\u0ba4\u0bc1",
+ "negative": "\u0baa\u0baf\u0ba9\u0bc1\u0bb3\u0bcd\u0bb3\u0ba4\u0bbe\u0b95 \u0b87\u0bb2\u0bcd\u0bb2\u0bc8",
+ "edit": "\u0b95\u0bb0\u0bc1\u0ba4\u0bcd\u0ba4\u0bc8 \u0ba4\u0bbf\u0bb0\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1",
+ "dialog": {
+ "title": "\u0b95\u0bb0\u0bc1\u0ba4\u0bcd\u0ba4\u0bc8\u0b9a\u0bcd \u0b9a\u0bc7\u0bb0\u0bcd",
+ "submit": "\u0b95\u0bb0\u0bc1\u0ba4\u0bcd\u0ba4\u0bc8 \u0b9a\u0bae\u0bb0\u0bcd\u0baa\u0bcd\u0baa\u0bbf"
+ },
+ "status": {
+ "updating": "\u0baa\u0bc1\u0ba4\u0bc1\u0baa\u0bcd\u0baa\u0bbf\u0b95\u0bcd\u0b95\u0bbf\u0bb1\u0ba4\u0bc1",
+ "updated": "\u0b95\u0bb0\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1 \u0baa\u0bc1\u0ba4\u0bc1\u0baa\u0bcd\u0baa\u0bbf\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1"
+ }
+ }
+ },
+ "history": {
+ "title": "\u0b95\u0b9f\u0bc8\u0b9a\u0bbf \u0b89\u0bb3\u0bcd\u0bb3\u0bc0\u0b9f\u0bc1\u0b95\u0bb3\u0bcd",
+ "empty": "\u0b95\u0bbe\u0bb2\u0bbf\u0baf\u0bbe\u0b95 \u0b89\u0bb3\u0bcd\u0bb3\u0ba4\u0bc1...",
+ "show": "\u0bb5\u0bb0\u0bb2\u0bbe\u0bb1\u0bcd\u0bb1\u0bc8\u0b95\u0bcd \u0b95\u0bbe\u0b9f\u0bcd\u0b9f\u0bc1"
+ },
+ "settings": {
+ "title": "\u0b85\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd \u0baa\u0bb2\u0b95\u0bae\u0bcd"
+ },
+ "watermark": "\u0b89\u0b9f\u0ba9\u0bcd \u0b89\u0bb0\u0bc1\u0bb5\u0bbe\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u0b95\u0b9f\u0ba8\u0bcd\u0ba4 \u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd\u0b95\u0bb3\u0bcd",
+ "filters": {
+ "search": "\u0ba4\u0bc7\u0b9f\u0bc1",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u0b87\u0ba9\u0bcd\u0bb1\u0bc1",
+ "yesterday": "\u0ba8\u0bc7\u0bb1\u0bcd\u0bb1\u0bc1",
+ "previous7days": "\u0b95\u0b9f\u0ba8\u0bcd\u0ba4 7 \u0ba8\u0bbe\u0b9f\u0bcd\u0b95\u0bb3\u0bcd",
+ "previous30days": "\u0b95\u0b9f\u0ba8\u0bcd\u0ba4 30 \u0ba8\u0bbe\u0b9f\u0bcd\u0b95\u0bb3\u0bcd"
+ },
+ "empty": "\u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd\u0b95\u0bb3\u0bcd \u0b8e\u0ba4\u0bc1\u0bb5\u0bc1\u0bae\u0bcd \u0b87\u0bb2\u0bcd\u0bb2\u0bc8",
+ "actions": {
+ "close": "\u0baa\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0bbf\u0baf\u0bc8 \u0bae\u0bc2\u0b9f\u0bc1",
+ "open": "\u0baa\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0bbf\u0baf\u0bc8 \u0ba4\u0bbf\u0bb1"
+ }
+ },
+ "thread": {
+ "untitled": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bbf\u0b9f\u0bbe\u0ba4 \u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u0ba8\u0bc0\u0b95\u0bcd\u0b95\u0bc1\u0bb5\u0ba4\u0bc8 \u0b89\u0bb1\u0bc1\u0ba4\u0bbf\u0baa\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1",
+ "description": "\u0b87\u0ba4\u0bc1 \u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd \u0bae\u0bb1\u0bcd\u0bb1\u0bc1\u0bae\u0bcd \u0b85\u0ba4\u0ba9\u0bcd \u0b9a\u0bc6\u0baf\u0bcd\u0ba4\u0bbf\u0b95\u0bb3\u0bcd, \u0b89\u0bb1\u0bc1\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bc8 \u0ba8\u0bc0\u0b95\u0bcd\u0b95\u0bc1\u0bae\u0bcd. \u0b87\u0ba8\u0bcd\u0ba4 \u0b9a\u0bc6\u0baf\u0bb2\u0bc8 \u0bae\u0bc0\u0b9f\u0bcd\u0b9f\u0bc6\u0b9f\u0bc1\u0b95\u0bcd\u0b95 \u0bae\u0bc1\u0b9f\u0bbf\u0baf\u0bbe\u0ba4\u0bc1",
+ "success": "\u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd \u0ba8\u0bc0\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1",
+ "inProgress": "\u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bc8 \u0ba8\u0bc0\u0b95\u0bcd\u0b95\u0bc1\u0b95\u0bbf\u0bb1\u0ba4\u0bc1"
+ },
+ "rename": {
+ "title": "\u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bc8 \u0bae\u0bb1\u0bc1\u0baa\u0bc6\u0baf\u0bb0\u0bbf\u0b9f\u0bc1",
+ "description": "\u0b87\u0ba8\u0bcd\u0ba4 \u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bc1\u0b95\u0bcd\u0b95\u0bc1 \u0baa\u0bc1\u0ba4\u0bbf\u0baf \u0baa\u0bc6\u0baf\u0bb0\u0bc8 \u0b89\u0bb3\u0bcd\u0bb3\u0bbf\u0b9f\u0bb5\u0bc1\u0bae\u0bcd",
+ "form": {
+ "name": {
+ "label": "\u0baa\u0bc6\u0baf\u0bb0\u0bcd",
+ "placeholder": "\u0baa\u0bc1\u0ba4\u0bbf\u0baf \u0baa\u0bc6\u0baf\u0bb0\u0bc8 \u0b89\u0bb3\u0bcd\u0bb3\u0bbf\u0b9f\u0bb5\u0bc1\u0bae\u0bcd"
+ }
+ },
+ "success": "\u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd \u0bae\u0bb1\u0bc1\u0baa\u0bc6\u0baf\u0bb0\u0bbf\u0b9f\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1!",
+ "inProgress": "\u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bc8 \u0bae\u0bb1\u0bc1\u0baa\u0bc6\u0baf\u0bb0\u0bbf\u0b9f\u0bc1\u0b95\u0bbf\u0bb1\u0ba4\u0bc1"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd",
+ "readme": "\u0baa\u0b9f\u0bbf\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u0baa\u0bc1\u0ba4\u0bbf\u0baf \u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd",
+ "dialog": {
+ "title": "\u0baa\u0bc1\u0ba4\u0bbf\u0baf \u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bc8 \u0b89\u0bb0\u0bc1\u0bb5\u0bbe\u0b95\u0bcd\u0b95\u0bc1",
+ "description": "\u0b87\u0ba4\u0bc1 \u0b89\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0ba4\u0bb1\u0bcd\u0baa\u0bcb\u0ba4\u0bc8\u0baf \u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd \u0bb5\u0bb0\u0bb2\u0bbe\u0bb1\u0bcd\u0bb1\u0bc8 \u0b85\u0bb4\u0bbf\u0b95\u0bcd\u0b95\u0bc1\u0bae\u0bcd. \u0ba4\u0bca\u0b9f\u0bb0 \u0bb5\u0bbf\u0bb0\u0bc1\u0bae\u0bcd\u0baa\u0bc1\u0b95\u0bbf\u0bb1\u0bc0\u0bb0\u0bcd\u0b95\u0bb3\u0bbe?",
+ "tooltip": "\u0baa\u0bc1\u0ba4\u0bbf\u0baf \u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u0b85\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd",
+ "settingsKey": "S",
+ "apiKeys": "API \u0bb5\u0bbf\u0b9a\u0bc8\u0b95\u0bb3\u0bcd",
+ "logout": "\u0bb5\u0bc6\u0bb3\u0bbf\u0baf\u0bc7\u0bb1\u0bc1"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u0ba4\u0bc7\u0bb5\u0bc8\u0baf\u0bbe\u0ba9 API \u0bb5\u0bbf\u0b9a\u0bc8\u0b95\u0bb3\u0bcd",
+ "description": "\u0b87\u0ba8\u0bcd\u0ba4 \u0baa\u0baf\u0ba9\u0bcd\u0baa\u0bbe\u0b9f\u0bcd\u0b9f\u0bc8\u0baa\u0bcd \u0baa\u0baf\u0ba9\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4, \u0baa\u0bbf\u0ba9\u0bcd\u0bb5\u0bb0\u0bc1\u0bae\u0bcd API \u0bb5\u0bbf\u0b9a\u0bc8\u0b95\u0bb3\u0bcd \u0ba4\u0bc7\u0bb5\u0bc8. \u0bb5\u0bbf\u0b9a\u0bc8\u0b95\u0bb3\u0bcd \u0b89\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b9a\u0bbe\u0ba4\u0ba9\u0ba4\u0bcd\u0ba4\u0bbf\u0ba9\u0bcd \u0b89\u0bb3\u0bcd\u0bb3\u0bc2\u0bb0\u0bcd \u0b9a\u0bc7\u0bae\u0bbf\u0baa\u0bcd\u0baa\u0b95\u0ba4\u0bcd\u0ba4\u0bbf\u0bb2\u0bcd \u0b9a\u0bc7\u0bae\u0bbf\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bc1\u0bae\u0bcd.",
+ "success": {
+ "saved": "\u0bb5\u0bc6\u0bb1\u0bcd\u0bb1\u0bbf\u0b95\u0bb0\u0bae\u0bbe\u0b95 \u0b9a\u0bc7\u0bae\u0bbf\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/te.json b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/te.json
new file mode 100644
index 00000000..ac92371c
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/te.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u0c30\u0c26\u0c4d\u0c26\u0c41 \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "confirm": "\u0c28\u0c3f\u0c30\u0c4d\u0c27\u0c3e\u0c30\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "continue": "\u0c15\u0c4a\u0c28\u0c38\u0c3e\u0c17\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "goBack": "\u0c35\u0c46\u0c28\u0c15\u0c4d\u0c15\u0c3f \u0c35\u0c46\u0c33\u0c4d\u0c33\u0c02\u0c21\u0c3f",
+ "reset": "\u0c30\u0c40\u0c38\u0c46\u0c1f\u0c4d \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "submit": "\u0c38\u0c2e\u0c30\u0c4d\u0c2a\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f"
+ },
+ "status": {
+ "loading": "\u0c32\u0c4b\u0c21\u0c4d \u0c05\u0c35\u0c41\u0c24\u0c4b\u0c02\u0c26\u0c3f...",
+ "error": {
+ "default": "\u0c32\u0c4b\u0c2a\u0c02 \u0c38\u0c02\u0c2d\u0c35\u0c3f\u0c02\u0c1a\u0c3f\u0c02\u0c26\u0c3f",
+ "serverConnection": "\u0c38\u0c30\u0c4d\u0c35\u0c30\u0c4d\u200c\u0c28\u0c3f \u0c1a\u0c47\u0c30\u0c41\u0c15\u0c4b\u0c32\u0c47\u0c15\u0c2a\u0c4b\u0c2f\u0c3e\u0c2e\u0c41"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u0c2f\u0c3e\u0c2a\u0c4d\u200c\u0c28\u0c3f \u0c09\u0c2a\u0c2f\u0c4b\u0c17\u0c3f\u0c02\u0c1a\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f \u0c32\u0c3e\u0c17\u0c3f\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "form": {
+ "email": {
+ "label": "\u0c07\u0c2e\u0c46\u0c2f\u0c3f\u0c32\u0c4d \u0c1a\u0c3f\u0c30\u0c41\u0c28\u0c3e\u0c2e\u0c3e",
+ "required": "\u0c07\u0c2e\u0c46\u0c2f\u0c3f\u0c32\u0c4d \u0c24\u0c2a\u0c4d\u0c2a\u0c28\u0c3f\u0c38\u0c30\u0c3f"
+ },
+ "password": {
+ "label": "\u0c2a\u0c3e\u0c38\u0c4d\u200c\u0c35\u0c30\u0c4d\u0c21\u0c4d",
+ "required": "\u0c2a\u0c3e\u0c38\u0c4d\u200c\u0c35\u0c30\u0c4d\u0c21\u0c4d \u0c24\u0c2a\u0c4d\u0c2a\u0c28\u0c3f\u0c38\u0c30\u0c3f"
+ },
+ "actions": {
+ "signin": "\u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f"
+ },
+ "alternativeText": {
+ "or": "\u0c32\u0c47\u0c26\u0c3e"
+ }
+ },
+ "errors": {
+ "default": "\u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c32\u0c47\u0c15\u0c2a\u0c4b\u0c2f\u0c3e\u0c2e\u0c41",
+ "signin": "\u0c35\u0c47\u0c30\u0c47 \u0c16\u0c3e\u0c24\u0c3e\u0c24\u0c4b \u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f \u0c2a\u0c4d\u0c30\u0c2f\u0c24\u0c4d\u0c28\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "oauthSignin": "\u0c35\u0c47\u0c30\u0c47 \u0c16\u0c3e\u0c24\u0c3e\u0c24\u0c4b \u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f \u0c2a\u0c4d\u0c30\u0c2f\u0c24\u0c4d\u0c28\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "redirectUriMismatch": "\u0c30\u0c40\u0c21\u0c48\u0c30\u0c46\u0c15\u0c4d\u0c1f\u0c4d URI oauth \u0c2f\u0c3e\u0c2a\u0c4d \u0c15\u0c3e\u0c28\u0c4d\u0c2b\u0c3f\u0c17\u0c30\u0c47\u0c37\u0c28\u0c4d\u200c\u0c24\u0c4b \u0c38\u0c30\u0c3f\u0c2a\u0c4b\u0c32\u0c21\u0c02 \u0c32\u0c47\u0c26\u0c41",
+ "oauthCallback": "\u0c35\u0c47\u0c30\u0c47 \u0c16\u0c3e\u0c24\u0c3e\u0c24\u0c4b \u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f \u0c2a\u0c4d\u0c30\u0c2f\u0c24\u0c4d\u0c28\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "oauthCreateAccount": "\u0c35\u0c47\u0c30\u0c47 \u0c16\u0c3e\u0c24\u0c3e\u0c24\u0c4b \u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f \u0c2a\u0c4d\u0c30\u0c2f\u0c24\u0c4d\u0c28\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "emailCreateAccount": "\u0c35\u0c47\u0c30\u0c47 \u0c16\u0c3e\u0c24\u0c3e\u0c24\u0c4b \u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f \u0c2a\u0c4d\u0c30\u0c2f\u0c24\u0c4d\u0c28\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "callback": "\u0c35\u0c47\u0c30\u0c47 \u0c16\u0c3e\u0c24\u0c3e\u0c24\u0c4b \u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f \u0c2a\u0c4d\u0c30\u0c2f\u0c24\u0c4d\u0c28\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "oauthAccountNotLinked": "\u0c2e\u0c40 \u0c17\u0c41\u0c30\u0c4d\u0c24\u0c3f\u0c02\u0c2a\u0c41\u0c28\u0c41 \u0c28\u0c3f\u0c30\u0c4d\u0c27\u0c3e\u0c30\u0c3f\u0c02\u0c1a\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f, \u0c2e\u0c40\u0c30\u0c41 \u0c2e\u0c4a\u0c26\u0c1f \u0c09\u0c2a\u0c2f\u0c4b\u0c17\u0c3f\u0c02\u0c1a\u0c3f\u0c28 \u0c05\u0c26\u0c47 \u0c16\u0c3e\u0c24\u0c3e\u0c24\u0c4b \u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "emailSignin": "\u0c07\u0c2e\u0c46\u0c2f\u0c3f\u0c32\u0c4d \u0c2a\u0c02\u0c2a\u0c21\u0c02 \u0c38\u0c3e\u0c27\u0c4d\u0c2f\u0c02 \u0c15\u0c3e\u0c32\u0c47\u0c26\u0c41",
+ "emailVerify": "\u0c26\u0c2f\u0c1a\u0c47\u0c38\u0c3f \u0c2e\u0c40 \u0c07\u0c2e\u0c46\u0c2f\u0c3f\u0c32\u0c4d\u200c\u0c28\u0c3f \u0c27\u0c43\u0c35\u0c40\u0c15\u0c30\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f, \u0c15\u0c4a\u0c24\u0c4d\u0c24 \u0c07\u0c2e\u0c46\u0c2f\u0c3f\u0c32\u0c4d \u0c2a\u0c02\u0c2a\u0c2c\u0c21\u0c3f\u0c02\u0c26\u0c3f",
+ "credentialsSignin": "\u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c35\u0c3f\u0c2b\u0c32\u0c2e\u0c48\u0c02\u0c26\u0c3f. \u0c2e\u0c40\u0c30\u0c41 \u0c05\u0c02\u0c26\u0c3f\u0c02\u0c1a\u0c3f\u0c28 \u0c35\u0c3f\u0c35\u0c30\u0c3e\u0c32\u0c41 \u0c38\u0c30\u0c48\u0c28\u0c35\u0c47\u0c28\u0c3e \u0c05\u0c28\u0c3f \u0c24\u0c28\u0c3f\u0c16\u0c40 \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "sessionRequired": "\u0c08 \u0c2a\u0c47\u0c1c\u0c40\u0c28\u0c3f \u0c2f\u0c3e\u0c15\u0c4d\u0c38\u0c46\u0c38\u0c4d \u0c1a\u0c47\u0c2f\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f \u0c26\u0c2f\u0c1a\u0c47\u0c38\u0c3f \u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f"
+ }
+ },
+ "provider": {
+ "continue": "{{provider}}\u0c24\u0c4b \u0c15\u0c4a\u0c28\u0c38\u0c3e\u0c17\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u0c2e\u0c40 \u0c38\u0c02\u0c26\u0c47\u0c36\u0c3e\u0c28\u0c4d\u0c28\u0c3f \u0c07\u0c15\u0c4d\u0c15\u0c21 \u0c1f\u0c48\u0c2a\u0c4d \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f...",
+ "actions": {
+ "send": "\u0c38\u0c02\u0c26\u0c47\u0c36\u0c02 \u0c2a\u0c02\u0c2a\u0c02\u0c21\u0c3f",
+ "stop": "\u0c2a\u0c28\u0c3f \u0c06\u0c2a\u0c02\u0c21\u0c3f",
+ "attachFiles": "\u0c2b\u0c48\u0c32\u0c4d\u0c38\u0c4d \u0c1c\u0c4b\u0c21\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f"
+ }
+ },
+ "speech": {
+ "start": "\u0c30\u0c3f\u0c15\u0c3e\u0c30\u0c4d\u0c21\u0c3f\u0c02\u0c17\u0c4d \u0c2a\u0c4d\u0c30\u0c3e\u0c30\u0c02\u0c2d\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "stop": "\u0c30\u0c3f\u0c15\u0c3e\u0c30\u0c4d\u0c21\u0c3f\u0c02\u0c17\u0c4d \u0c06\u0c2a\u0c02\u0c21\u0c3f",
+ "connecting": "\u0c05\u0c28\u0c41\u0c38\u0c02\u0c27\u0c3e\u0c28\u0c3f\u0c38\u0c4d\u0c24\u0c4b\u0c02\u0c26\u0c3f"
+ },
+ "fileUpload": {
+ "dragDrop": "\u0c2b\u0c48\u0c32\u0c4d\u0c38\u0c4d\u200c\u0c28\u0c3f \u0c07\u0c15\u0c4d\u0c15\u0c21 \u0c21\u0c4d\u0c30\u0c3e\u0c17\u0c4d \u0c1a\u0c47\u0c38\u0c3f \u0c21\u0c4d\u0c30\u0c3e\u0c2a\u0c4d \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "browse": "\u0c2b\u0c48\u0c32\u0c4d\u0c38\u0c4d \u0c2c\u0c4d\u0c30\u0c4c\u0c1c\u0c4d \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "sizeLimit": "\u0c2a\u0c30\u0c3f\u0c2e\u0c3f\u0c24\u0c3f:",
+ "errors": {
+ "failed": "\u0c05\u0c2a\u0c4d\u200c\u0c32\u0c4b\u0c21\u0c4d \u0c35\u0c3f\u0c2b\u0c32\u0c2e\u0c48\u0c02\u0c26\u0c3f",
+ "cancelled": "\u0c05\u0c2a\u0c4d\u200c\u0c32\u0c4b\u0c21\u0c4d \u0c30\u0c26\u0c4d\u0c26\u0c41 \u0c1a\u0c47\u0c2f\u0c2c\u0c21\u0c3f\u0c02\u0c26\u0c3f"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u0c09\u0c2a\u0c2f\u0c4b\u0c17\u0c3f\u0c38\u0c4d\u0c24\u0c4b\u0c02\u0c26\u0c3f",
+ "used": "\u0c09\u0c2a\u0c2f\u0c4b\u0c17\u0c3f\u0c02\u0c1a\u0c2c\u0c21\u0c3f\u0c02\u0c26\u0c3f"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u0c15\u0c4d\u0c32\u0c3f\u0c2a\u0c4d\u200c\u0c2c\u0c4b\u0c30\u0c4d\u0c21\u0c4d\u200c\u0c15\u0c3f \u0c15\u0c3e\u0c2a\u0c40 \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "success": "\u0c15\u0c3e\u0c2a\u0c40 \u0c1a\u0c47\u0c2f\u0c2c\u0c21\u0c3f\u0c02\u0c26\u0c3f!"
+ }
+ },
+ "feedback": {
+ "positive": "\u0c38\u0c39\u0c3e\u0c2f\u0c15\u0c30\u0c02",
+ "negative": "\u0c38\u0c39\u0c3e\u0c2f\u0c15\u0c30\u0c02 \u0c15\u0c3e\u0c26\u0c41",
+ "edit": "\u0c05\u0c2d\u0c3f\u0c2a\u0c4d\u0c30\u0c3e\u0c2f\u0c3e\u0c28\u0c4d\u0c28\u0c3f \u0c38\u0c35\u0c30\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "dialog": {
+ "title": "\u0c35\u0c4d\u0c2f\u0c3e\u0c16\u0c4d\u0c2f \u0c1c\u0c4b\u0c21\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "submit": "\u0c05\u0c2d\u0c3f\u0c2a\u0c4d\u0c30\u0c3e\u0c2f\u0c3e\u0c28\u0c4d\u0c28\u0c3f \u0c38\u0c2e\u0c30\u0c4d\u0c2a\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f"
+ },
+ "status": {
+ "updating": "\u0c28\u0c35\u0c40\u0c15\u0c30\u0c3f\u0c38\u0c4d\u0c24\u0c4b\u0c02\u0c26\u0c3f",
+ "updated": "\u0c05\u0c2d\u0c3f\u0c2a\u0c4d\u0c30\u0c3e\u0c2f\u0c02 \u0c28\u0c35\u0c40\u0c15\u0c30\u0c3f\u0c02\u0c1a\u0c2c\u0c21\u0c3f\u0c02\u0c26\u0c3f"
+ }
+ }
+ },
+ "history": {
+ "title": "\u0c1a\u0c3f\u0c35\u0c30\u0c3f \u0c07\u0c28\u0c4d\u200c\u0c2a\u0c41\u0c1f\u0c4d\u200c\u0c32\u0c41",
+ "empty": "\u0c16\u0c3e\u0c33\u0c40\u0c17\u0c3e \u0c09\u0c02\u0c26\u0c3f...",
+ "show": "\u0c1a\u0c30\u0c3f\u0c24\u0c4d\u0c30\u0c28\u0c41 \u0c1a\u0c42\u0c2a\u0c3f\u0c02\u0c1a\u0c41"
+ },
+ "settings": {
+ "title": "\u0c38\u0c46\u0c1f\u0c4d\u0c1f\u0c3f\u0c02\u0c17\u0c4d\u200c\u0c32 \u0c2a\u0c4d\u0c2f\u0c3e\u0c28\u0c46\u0c32\u0c4d"
+ },
+ "watermark": "\u0c24\u0c4b \u0c28\u0c3f\u0c30\u0c4d\u0c2e\u0c3f\u0c02\u0c1a\u0c2c\u0c21\u0c3f\u0c02\u0c26\u0c3f"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u0c17\u0c24 \u0c1a\u0c3e\u0c1f\u0c4d\u200c\u0c32\u0c41",
+ "filters": {
+ "search": "\u0c35\u0c46\u0c24\u0c15\u0c02\u0c21\u0c3f",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u0c08\u0c30\u0c4b\u0c1c\u0c41",
+ "yesterday": "\u0c28\u0c3f\u0c28\u0c4d\u0c28",
+ "previous7days": "\u0c17\u0c24 7 \u0c30\u0c4b\u0c1c\u0c41\u0c32\u0c41",
+ "previous30days": "\u0c17\u0c24 30 \u0c30\u0c4b\u0c1c\u0c41\u0c32\u0c41"
+ },
+ "empty": "\u0c25\u0c4d\u0c30\u0c46\u0c21\u0c4d\u200c\u0c32\u0c41 \u0c15\u0c28\u0c41\u0c17\u0c4a\u0c28\u0c2c\u0c21\u0c32\u0c47\u0c26\u0c41",
+ "actions": {
+ "close": "\u0c38\u0c48\u0c21\u0c4d\u200c\u0c2c\u0c3e\u0c30\u0c4d \u0c2e\u0c42\u0c38\u0c3f\u0c35\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "open": "\u0c38\u0c48\u0c21\u0c4d\u200c\u0c2c\u0c3e\u0c30\u0c4d \u0c24\u0c46\u0c30\u0c35\u0c02\u0c21\u0c3f"
+ }
+ },
+ "thread": {
+ "untitled": "\u0c2a\u0c47\u0c30\u0c41 \u0c32\u0c47\u0c28\u0c3f \u0c38\u0c02\u0c2d\u0c3e\u0c37\u0c23",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u0c24\u0c4a\u0c32\u0c17\u0c3f\u0c02\u0c2a\u0c41\u0c28\u0c41 \u0c28\u0c3f\u0c30\u0c4d\u0c27\u0c3e\u0c30\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "description": "\u0c07\u0c26\u0c3f \u0c25\u0c4d\u0c30\u0c46\u0c21\u0c4d\u200c\u0c24\u0c4b \u0c2a\u0c3e\u0c1f\u0c41 \u0c26\u0c3e\u0c28\u0c3f \u0c38\u0c02\u0c26\u0c47\u0c36\u0c3e\u0c32\u0c28\u0c41 \u0c2e\u0c30\u0c3f\u0c2f\u0c41 \u0c05\u0c02\u0c36\u0c3e\u0c32\u0c28\u0c41 \u0c24\u0c4a\u0c32\u0c17\u0c3f\u0c38\u0c4d\u0c24\u0c41\u0c02\u0c26\u0c3f. \u0c08 \u0c1a\u0c30\u0c4d\u0c2f\u0c28\u0c41 \u0c30\u0c26\u0c4d\u0c26\u0c41 \u0c1a\u0c47\u0c2f\u0c32\u0c47\u0c30\u0c41",
+ "success": "\u0c1a\u0c3e\u0c1f\u0c4d \u0c24\u0c4a\u0c32\u0c17\u0c3f\u0c02\u0c1a\u0c2c\u0c21\u0c3f\u0c02\u0c26\u0c3f",
+ "inProgress": "\u0c1a\u0c3e\u0c1f\u0c4d\u200c\u0c28\u0c3f \u0c24\u0c4a\u0c32\u0c17\u0c3f\u0c38\u0c4d\u0c24\u0c4b\u0c02\u0c26\u0c3f"
+ },
+ "rename": {
+ "title": "\u0c25\u0c4d\u0c30\u0c46\u0c21\u0c4d \u0c2a\u0c47\u0c30\u0c41 \u0c2e\u0c3e\u0c30\u0c4d\u0c1a\u0c02\u0c21\u0c3f",
+ "description": "\u0c08 \u0c25\u0c4d\u0c30\u0c46\u0c21\u0c4d \u0c15\u0c4b\u0c38\u0c02 \u0c15\u0c4a\u0c24\u0c4d\u0c24 \u0c2a\u0c47\u0c30\u0c41\u0c28\u0c41 \u0c28\u0c2e\u0c4b\u0c26\u0c41 \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "form": {
+ "name": {
+ "label": "\u0c2a\u0c47\u0c30\u0c41",
+ "placeholder": "\u0c15\u0c4a\u0c24\u0c4d\u0c24 \u0c2a\u0c47\u0c30\u0c41\u0c28\u0c41 \u0c28\u0c2e\u0c4b\u0c26\u0c41 \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f"
+ }
+ },
+ "success": "\u0c25\u0c4d\u0c30\u0c46\u0c21\u0c4d \u0c2a\u0c47\u0c30\u0c41 \u0c2e\u0c3e\u0c30\u0c4d\u0c1a\u0c2c\u0c21\u0c3f\u0c02\u0c26\u0c3f!",
+ "inProgress": "\u0c25\u0c4d\u0c30\u0c46\u0c21\u0c4d \u0c2a\u0c47\u0c30\u0c41 \u0c2e\u0c3e\u0c30\u0c41\u0c38\u0c4d\u0c24\u0c4b\u0c02\u0c26\u0c3f"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u0c1a\u0c3e\u0c1f\u0c4d",
+ "readme": "\u0c1a\u0c26\u0c35\u0c02\u0c21\u0c3f",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u0c15\u0c4a\u0c24\u0c4d\u0c24 \u0c1a\u0c3e\u0c1f\u0c4d",
+ "dialog": {
+ "title": "\u0c15\u0c4a\u0c24\u0c4d\u0c24 \u0c1a\u0c3e\u0c1f\u0c4d \u0c38\u0c43\u0c37\u0c4d\u0c1f\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "description": "\u0c07\u0c26\u0c3f \u0c2e\u0c40 \u0c2a\u0c4d\u0c30\u0c38\u0c4d\u0c24\u0c41\u0c24 \u0c1a\u0c3e\u0c1f\u0c4d \u0c1a\u0c30\u0c3f\u0c24\u0c4d\u0c30\u0c28\u0c41 \u0c24\u0c41\u0c21\u0c3f\u0c1a\u0c3f\u0c35\u0c47\u0c38\u0c4d\u0c24\u0c41\u0c02\u0c26\u0c3f. \u0c2e\u0c40\u0c30\u0c41 \u0c15\u0c4a\u0c28\u0c38\u0c3e\u0c17\u0c3f\u0c02\u0c1a\u0c3e\u0c32\u0c28\u0c41\u0c15\u0c41\u0c02\u0c1f\u0c41\u0c28\u0c4d\u0c28\u0c3e\u0c30\u0c3e?",
+ "tooltip": "\u0c15\u0c4a\u0c24\u0c4d\u0c24 \u0c1a\u0c3e\u0c1f\u0c4d"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u0c38\u0c46\u0c1f\u0c4d\u0c1f\u0c3f\u0c02\u0c17\u0c4d\u200c\u0c32\u0c41",
+ "settingsKey": "S",
+ "apiKeys": "API \u0c15\u0c40\u0c32\u0c41",
+ "logout": "\u0c32\u0c3e\u0c17\u0c4d \u0c05\u0c35\u0c41\u0c1f\u0c4d"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u0c05\u0c35\u0c38\u0c30\u0c2e\u0c48\u0c28 API \u0c15\u0c40\u0c32\u0c41",
+ "description": "\u0c08 \u0c2f\u0c3e\u0c2a\u0c4d\u200c\u0c28\u0c3f \u0c09\u0c2a\u0c2f\u0c4b\u0c17\u0c3f\u0c02\u0c1a\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f, \u0c15\u0c3f\u0c02\u0c26\u0c3f API \u0c15\u0c40\u0c32\u0c41 \u0c05\u0c35\u0c38\u0c30\u0c02. \u0c15\u0c40\u0c32\u0c41 \u0c2e\u0c40 \u0c2a\u0c30\u0c3f\u0c15\u0c30\u0c02 \u0c2f\u0c4a\u0c15\u0c4d\u0c15 \u0c38\u0c4d\u0c25\u0c3e\u0c28\u0c3f\u0c15 \u0c28\u0c3f\u0c32\u0c4d\u0c35\u0c32\u0c4b \u0c28\u0c3f\u0c32\u0c4d\u0c35 \u0c1a\u0c47\u0c2f\u0c2c\u0c21\u0c24\u0c3e\u0c2f\u0c3f.",
+ "success": {
+ "saved": "\u0c35\u0c3f\u0c1c\u0c2f\u0c35\u0c02\u0c24\u0c02\u0c17\u0c3e \u0c38\u0c47\u0c35\u0c4d \u0c1a\u0c47\u0c2f\u0c2c\u0c21\u0c3f\u0c02\u0c26\u0c3f"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/zh-CN.json b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/zh-CN.json
new file mode 100644
index 00000000..ae336fc3
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/.chainlit/translations/zh-CN.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u53d6\u6d88",
+ "confirm": "\u786e\u8ba4",
+ "continue": "\u7ee7\u7eed",
+ "goBack": "\u8fd4\u56de",
+ "reset": "\u91cd\u7f6e",
+ "submit": "\u63d0\u4ea4"
+ },
+ "status": {
+ "loading": "\u52a0\u8f7d\u4e2d...",
+ "error": {
+ "default": "\u53d1\u751f\u9519\u8bef",
+ "serverConnection": "\u65e0\u6cd5\u8fde\u63a5\u5230\u670d\u52a1\u5668"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u767b\u5f55\u4ee5\u8bbf\u95ee\u5e94\u7528",
+ "form": {
+ "email": {
+ "label": "\u7535\u5b50\u90ae\u7bb1",
+ "required": "\u90ae\u7bb1\u662f\u5fc5\u586b\u9879"
+ },
+ "password": {
+ "label": "\u5bc6\u7801",
+ "required": "\u5bc6\u7801\u662f\u5fc5\u586b\u9879"
+ },
+ "actions": {
+ "signin": "\u767b\u5f55"
+ },
+ "alternativeText": {
+ "or": "\u6216"
+ }
+ },
+ "errors": {
+ "default": "\u65e0\u6cd5\u767b\u5f55",
+ "signin": "\u8bf7\u5c1d\u8bd5\u4f7f\u7528\u5176\u4ed6\u8d26\u53f7\u767b\u5f55",
+ "oauthSignin": "\u8bf7\u5c1d\u8bd5\u4f7f\u7528\u5176\u4ed6\u8d26\u53f7\u767b\u5f55",
+ "redirectUriMismatch": "\u91cd\u5b9a\u5411URI\u4e0eOAuth\u5e94\u7528\u914d\u7f6e\u4e0d\u5339\u914d",
+ "oauthCallback": "\u8bf7\u5c1d\u8bd5\u4f7f\u7528\u5176\u4ed6\u8d26\u53f7\u767b\u5f55",
+ "oauthCreateAccount": "\u8bf7\u5c1d\u8bd5\u4f7f\u7528\u5176\u4ed6\u8d26\u53f7\u767b\u5f55",
+ "emailCreateAccount": "\u8bf7\u5c1d\u8bd5\u4f7f\u7528\u5176\u4ed6\u8d26\u53f7\u767b\u5f55",
+ "callback": "\u8bf7\u5c1d\u8bd5\u4f7f\u7528\u5176\u4ed6\u8d26\u53f7\u767b\u5f55",
+ "oauthAccountNotLinked": "\u4e3a\u786e\u8ba4\u60a8\u7684\u8eab\u4efd\uff0c\u8bf7\u4f7f\u7528\u539f\u59cb\u8d26\u53f7\u767b\u5f55",
+ "emailSignin": "\u90ae\u4ef6\u53d1\u9001\u5931\u8d25",
+ "emailVerify": "\u8bf7\u9a8c\u8bc1\u60a8\u7684\u90ae\u7bb1\uff0c\u65b0\u7684\u9a8c\u8bc1\u90ae\u4ef6\u5df2\u53d1\u9001",
+ "credentialsSignin": "\u767b\u5f55\u5931\u8d25\u3002\u8bf7\u68c0\u67e5\u60a8\u63d0\u4f9b\u7684\u4fe1\u606f\u662f\u5426\u6b63\u786e",
+ "sessionRequired": "\u8bf7\u767b\u5f55\u4ee5\u8bbf\u95ee\u6b64\u9875\u9762"
+ }
+ },
+ "provider": {
+ "continue": "\u7ee7\u7eed\u4f7f\u7528{{provider}}"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u5728\u6b64\u8f93\u5165\u60a8\u7684\u6d88\u606f...",
+ "actions": {
+ "send": "\u53d1\u9001\u6d88\u606f",
+ "stop": "\u505c\u6b62\u4efb\u52a1",
+ "attachFiles": "\u9644\u52a0\u6587\u4ef6"
+ }
+ },
+ "speech": {
+ "start": "\u5f00\u59cb\u5f55\u97f3",
+ "stop": "\u505c\u6b62\u5f55\u97f3",
+ "connecting": "\u8fde\u63a5\u4e2d"
+ },
+ "fileUpload": {
+ "dragDrop": "\u5c06\u6587\u4ef6\u62d6\u653e\u5230\u8fd9\u91cc",
+ "browse": "\u6d4f\u89c8\u6587\u4ef6",
+ "sizeLimit": "\u9650\u5236\uff1a",
+ "errors": {
+ "failed": "\u4e0a\u4f20\u5931\u8d25",
+ "cancelled": "\u5df2\u53d6\u6d88\u4e0a\u4f20"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u4f7f\u7528\u4e2d",
+ "used": "\u5df2\u4f7f\u7528"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u590d\u5236\u5230\u526a\u8d34\u677f",
+ "success": "\u5df2\u590d\u5236\uff01"
+ }
+ },
+ "feedback": {
+ "positive": "\u6709\u5e2e\u52a9",
+ "negative": "\u6ca1\u6709\u5e2e\u52a9",
+ "edit": "\u7f16\u8f91\u53cd\u9988",
+ "dialog": {
+ "title": "\u6dfb\u52a0\u8bc4\u8bba",
+ "submit": "\u63d0\u4ea4\u53cd\u9988"
+ },
+ "status": {
+ "updating": "\u66f4\u65b0\u4e2d",
+ "updated": "\u53cd\u9988\u5df2\u66f4\u65b0"
+ }
+ }
+ },
+ "history": {
+ "title": "\u6700\u8fd1\u8f93\u5165",
+ "empty": "\u7a7a\u7a7a\u5982\u4e5f...",
+ "show": "\u663e\u793a\u5386\u53f2"
+ },
+ "settings": {
+ "title": "\u8bbe\u7f6e\u9762\u677f"
+ },
+ "watermark": "\u6280\u672f\u652f\u6301"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u5386\u53f2\u5bf9\u8bdd",
+ "filters": {
+ "search": "\u641c\u7d22",
+ "placeholder": "\u641c\u7d22\u4f1a\u8bdd..."
+ },
+ "timeframes": {
+ "today": "\u4eca\u5929",
+ "yesterday": "\u6628\u5929",
+ "previous7days": "\u8fc7\u53bb7\u5929",
+ "previous30days": "\u8fc7\u53bb30\u5929"
+ },
+ "empty": "\u672a\u627e\u5230\u5bf9\u8bdd",
+ "actions": {
+ "close": "\u5173\u95ed\u4fa7\u8fb9\u680f",
+ "open": "\u6253\u5f00\u4fa7\u8fb9\u680f"
+ }
+ },
+ "thread": {
+ "untitled": "\u672a\u547d\u540d\u5bf9\u8bdd",
+ "menu": {
+ "rename": "\u91cd\u547d\u540d",
+ "delete": "\u5220\u9664"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u786e\u8ba4\u5220\u9664",
+ "description": "\u8fd9\u5c06\u5220\u9664\u8be5\u5bf9\u8bdd\u53ca\u5176\u6240\u6709\u6d88\u606f\u548c\u5143\u7d20\u3002\u6b64\u64cd\u4f5c\u65e0\u6cd5\u64a4\u9500",
+ "success": "\u5bf9\u8bdd\u5df2\u5220\u9664",
+ "inProgress": "\u6b63\u5728\u5220\u9664\u5bf9\u8bdd"
+ },
+ "rename": {
+ "title": "\u91cd\u547d\u540d\u5bf9\u8bdd",
+ "description": "\u4e3a\u6b64\u5bf9\u8bdd\u8f93\u5165\u65b0\u540d\u79f0",
+ "form": {
+ "name": {
+ "label": "\u540d\u79f0",
+ "placeholder": "\u8f93\u5165\u65b0\u540d\u79f0"
+ }
+ },
+ "success": "\u5bf9\u8bdd\u5df2\u91cd\u547d\u540d\uff01",
+ "inProgress": "\u6b63\u5728\u91cd\u547d\u540d\u5bf9\u8bdd"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u804a\u5929",
+ "readme": "\u8bf4\u660e",
+ "theme": {
+ "light": "\u6d45\u8272\u4e3b\u9898",
+ "dark": "\u6df1\u8272\u4e3b\u9898",
+ "system": "\u8ddf\u968f\u7cfb\u7edf"
+ }
+ },
+ "newChat": {
+ "button": "\u65b0\u5efa\u5bf9\u8bdd",
+ "dialog": {
+ "title": "\u521b\u5efa\u65b0\u5bf9\u8bdd",
+ "description": "\u8fd9\u5c06\u6e05\u9664\u60a8\u5f53\u524d\u7684\u804a\u5929\u8bb0\u5f55\u3002\u786e\u5b9a\u8981\u7ee7\u7eed\u5417\uff1f",
+ "tooltip": "\u65b0\u5efa\u5bf9\u8bdd"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u8bbe\u7f6e",
+ "settingsKey": "S",
+ "apiKeys": "API\u5bc6\u94a5",
+ "logout": "\u9000\u51fa\u767b\u5f55"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u6240\u9700API\u5bc6\u94a5",
+ "description": "\u4f7f\u7528\u6b64\u5e94\u7528\u9700\u8981\u4ee5\u4e0bAPI\u5bc6\u94a5\u3002\u8fd9\u4e9b\u5bc6\u94a5\u5b58\u50a8\u5728\u60a8\u8bbe\u5907\u7684\u672c\u5730\u5b58\u50a8\u4e2d\u3002",
+ "success": {
+ "saved": "\u4fdd\u5b58\u6210\u529f"
+ }
+ },
+ "alerts": {
+ "info": "\u4fe1\u606f",
+ "note": "\u6ce8\u91ca",
+ "tip": "\u63d0\u793a",
+ "important": "\u91cd\u8981",
+ "warning": "\u8b66\u544a",
+ "caution": "\u6ce8\u610f",
+ "debug": "\u8c03\u8bd5",
+ "example": "\u793a\u4f8b",
+ "success": "\u6210\u529f",
+ "help": "\u5e2e\u52a9",
+ "idea": "\u60f3\u6cd5",
+ "pending": "\u5f85\u5904\u7406",
+ "security": "\u5b89\u5168",
+ "beta": "\u6d4b\u8bd5",
+ "best-practice": "\u6700\u4f73\u5b9e\u8df5"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/after/.env.example b/examples/agent/langgraph-fsi-agent/after/.env.example
new file mode 100644
index 00000000..16f6e82b
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/.env.example
@@ -0,0 +1,15 @@
+# Galileo Environment Variables
+GALILEO_API_KEY= # Your Galileo API key.
+GALILEO_PROJECT=Multi-Agent Banking Chatbot # Your Galileo project name.
+GALILEO_LOG_STREAM=Default Log Stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# GALILEO_CONSOLE_URL= # Optional if you are using a hosted version of Galileo
+
+# AI services
+OPENAI_API_KEY= # Your OpenAI API key
+# OPENAI_BASE_URL= # Optional if you are not using the public OpenAI API.
+MODEL_NAME= # The name of the model you want to use.
+
+# The API key for Pinecone
+PINECONE_API_KEY= # Your Pinecone API key.
diff --git a/examples/agent/langgraph-fsi-agent/after/.gitignore b/examples/agent/langgraph-fsi-agent/after/.gitignore
new file mode 100644
index 00000000..a1dd94cb
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/.gitignore
@@ -0,0 +1,126 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a PyInstaller build script
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# VS Code
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+
+# macOS
+.DS_Store
+
+# ruff
+.ruff_cache
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/after/LICENSE b/examples/agent/langgraph-fsi-agent/after/LICENSE
new file mode 100644
index 00000000..d5857e3c
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2025 Jim Bennett
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/examples/agent/langgraph-fsi-agent/after/app.py b/examples/agent/langgraph-fsi-agent/after/app.py
new file mode 100644
index 00000000..9046303e
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/app.py
@@ -0,0 +1,120 @@
+"""
+A demo Financial Services Agent using Chainlit and LangGraph, with Splunk AO as the evaluation platform.
+"""
+
+from datetime import datetime
+from typing import Any
+import chainlit as cl
+
+from langchain.schema.runnable.config import RunnableConfig
+from langchain_core.callbacks import Callbacks
+from langchain_core.messages import HumanMessage, AIMessage
+
+from dotenv import load_dotenv
+
+from splunk_ao import splunk_ao_context
+from splunk_ao.handlers.langchain import SplunkAOAsyncCallback
+
+from src.galileo_langgraph_fsi_agent.agents.supervisor_agent import (
+ create_supervisor_agent,
+)
+
+# Load environment variables from .env file
+load_dotenv()
+
+
+# Build the agent graph
+supervisor_agent = create_supervisor_agent()
+
+
+@cl.on_chat_start
+async def on_chat_start() -> None:
+ """
+ Handle the start of a chat session.
+
+ This function is called when a new chat session starts.
+ It initializes the chat with a welcome message.
+ """
+ create_galileo_session()
+
+ # Send a welcome message to the user
+ await cl.Message(content="Welcome to the Brahe Bank assistant! How can I help you today?").send()
+
+
+def create_galileo_session():
+ """
+ Create a new Splunk AO session for tracking user interactions.
+
+ This session is then stored in the Chainlit user session for later use.
+ """
+ try:
+ # Start Splunk AO session with unique session name
+ current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+ session_name = f"FSI Agent - {current_time}"
+ splunk_ao_context.start_session(name=session_name, external_id=cl.context.session.id)
+
+ # Create the callback. This needs to be created in the same thread as the session
+ # so that it uses the same session context.
+ galileo_callback = SplunkAOAsyncCallback()
+ cl.user_session.set("galileo_callback", galileo_callback)
+
+ # Store session info in user session for later use
+ cl.user_session.set("galileo_session_started", True)
+ cl.user_session.set("session_name", session_name)
+
+ print(f"✅ Splunk AO session started: {session_name}")
+
+ except Exception as e:
+ print(f"❌ Failed to start Splunk AO session: {str(e)}")
+ # Continue without Splunk AO rather than failing completely
+ cl.user_session.set("galileo_session_started", False)
+
+
+@cl.on_message
+async def main(msg: cl.Message) -> None:
+ """
+ Handle the message from the user.
+
+ param message: The message object containing user input.
+ """
+ # Create a config using the current Chainlit session ID. This is linked to the memory saver in the graph
+ # to allow you to continue the conversation with the same context.
+ config: dict[str, Any] = {"configurable": {"thread_id": cl.context.session.id}}
+
+ # Prepare the final answer message to stream the response back to the user
+ final_answer = cl.Message(content="")
+
+ # Build the messages dictionary with the user's message
+ messages: dict[str, Any] = {"messages": [HumanMessage(content=msg.content)]}
+
+ # Create a callback handler to log the response to Splunk AO
+ callbacks: Callbacks = []
+ if cl.user_session.get("galileo_session_started", False):
+ galileo_callback = cl.user_session.get("galileo_callback")
+ callbacks: Callbacks = [galileo_callback] # type: ignore
+ else:
+ print("Splunk AO session not started, using default callbacks.")
+
+ # Set up the config for the streaming response
+ runnable_config = RunnableConfig(callbacks=callbacks, **config)
+
+ # Call the graph with the user's message and stream the response back to the user
+ async for response_msg in supervisor_agent.astream(input=messages, stream_mode="updates", config=runnable_config):
+ # Check for a response from the supervisor agent with the final message
+ if supervisor_agent.name in response_msg and "messages" in response_msg[supervisor_agent.name]:
+ # Get the last message from the supervisor's response
+ message = response_msg[supervisor_agent.name]["messages"][-1]
+ # If it is an AI message, then it is the final answer
+ if isinstance(message, AIMessage) and message.content:
+ await final_answer.stream_token(message.content) # type: ignore
+
+ # Send the final answer message to the user
+ await final_answer.send()
+
+
+# This is the entry point for running the Chainlit application used for debugging
+# Otherwise to run this with hot reload, use `chainlit run app.py -w`
+if __name__ == "__main__":
+ from chainlit.cli import run_chainlit
+
+ run_chainlit(__file__)
diff --git a/examples/agent/langgraph-fsi-agent/after/chainlit.md b/examples/agent/langgraph-fsi-agent/after/chainlit.md
new file mode 100644
index 00000000..4507ac46
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/chainlit.md
@@ -0,0 +1,14 @@
+# Welcome to Chainlit! 🚀🤖
+
+Hi there, Developer! 👋 We're excited to have you on board. Chainlit is a powerful tool designed to help you prototype, debug and share applications built on top of LLMs.
+
+## Useful Links 🔗
+
+- **Documentation:** Get started with our comprehensive [Chainlit Documentation](https://docs.chainlit.io) 📚
+- **Discord Community:** Join our friendly [Chainlit Discord](https://discord.gg/k73SQ3FyUh) to ask questions, share your projects, and connect with other developers! 💬
+
+We can't wait to see what you create with Chainlit! Happy coding! 💻😊
+
+## Welcome screen
+
+To modify the welcome screen, edit the `chainlit.md` file at the root of your project. If you do not want a welcome screen, just leave this file empty.
diff --git a/examples/agent/langgraph-fsi-agent/after/create_sample_logs.py b/examples/agent/langgraph-fsi-agent/after/create_sample_logs.py
new file mode 100644
index 00000000..61640cba
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/create_sample_logs.py
@@ -0,0 +1,65 @@
+# A script to generate log streams
+
+from dotenv import load_dotenv
+
+load_dotenv(override=True)
+
+import json
+import random
+from typing import Any
+
+from splunk_ao import splunk_ao_context
+from splunk_ao.handlers.langchain import SplunkAOCallback
+
+from langchain.schema.runnable.config import RunnableConfig
+from langchain_core.callbacks import Callbacks
+from langchain_core.messages import HumanMessage
+
+from src.galileo_langgraph_fsi_agent.agents.supervisor_agent import (
+ create_supervisor_agent,
+)
+
+import uuid
+
+with open("./dataset.json", "r", encoding="utf-8") as f:
+ dataset_content = json.load(f)
+
+print(f"Starting to log {len(dataset_content)} interactions...")
+row_number = 1
+
+# Build the agent graph
+supervisor_agent = create_supervisor_agent()
+
+for row in dataset_content:
+ print(f"Processing row {row_number} of {len(dataset_content)}")
+
+ user_input = row["input"]
+
+ # Randomly start a new session - this way sometimes we have multiple interactions in the same session.
+ # Need a 50% chance to start a new session.
+ # If this is row 1, always start a new session.
+ if row_number == 1 or random.random() < 0.5:
+ EXTERNAL_ID = str(uuid.uuid4())
+ splunk_ao_context.start_session(external_id=EXTERNAL_ID)
+
+ # Create the callback. This needs to be created in the same thread as the session
+ # so that it uses the same session context.
+ galileo_callback = SplunkAOCallback()
+
+ config: dict[str, Any] = {"configurable": {"thread_id": random.randint(1, 1000)}}
+ callbacks: Callbacks = [galileo_callback] # type: ignore
+
+ # Set up the config for the streaming response
+ runnable_config = RunnableConfig(callbacks=callbacks, **config)
+
+ messages: dict[str, Any] = {"messages": [HumanMessage(content=user_input)]}
+ supervisor_agent.invoke(input=messages, config=runnable_config)
+
+ # Wait for a random time between 20-60 seconds before the next interaction
+ # wait_time = random.randint(20, 60)
+ # time.sleep(wait_time)
+
+ # increment the row number
+ row_number += 1
+
+print("All interactions logged successfully.")
diff --git a/examples/agent/langgraph-fsi-agent/after/dataset-test.json b/examples/agent/langgraph-fsi-agent/after/dataset-test.json
new file mode 100644
index 00000000..55f2eef1
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/dataset-test.json
@@ -0,0 +1,8 @@
+[
+ {"input": "What are the cashback rewards offered by the Orbit Credit Card?", "output": "The Orbit Credit Card offers 2% cashback on dining, 1.5% on groceries, and 1% on all other purchases."},
+ {"input": "What is my credit score?", "output": "Your credit score is 550."},
+ {"input": "What is the APR for balance transfers on the Orbit Credit Card?", "output": "The APR for balance transfers on the Orbit Credit Card is 0% introductory APR for the first 12 months, after which it ranges from 15.99% to 23.99%."},
+ {"input": "What credit cards am I eligible for?", "output": "With a credit score of 550, you are only eligible for the Orbit credit card"},
+ {"input": "What can I do with my credit score?", "output": "With a credit score of 550, you are only eligible for the Orbit credit card"},
+ {"input": "Recommend me a good book.", "output": "I don't know"}
+]
diff --git a/examples/agent/langgraph-fsi-agent/after/dataset.json b/examples/agent/langgraph-fsi-agent/after/dataset.json
new file mode 100644
index 00000000..c434b799
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/dataset.json
@@ -0,0 +1,47 @@
+[
+ { "input": "Does Orbit Card offer price protection?", "output": "Yes, the Orbit Credit Card includes price protection benefits." },
+ { "input": "What's the minimum payment required monthly for Orbit Credit Card?", "output": "The minimum payment is either $25 or 1% of the statement balance, plus interest and fees\u2014whichever is greater." },
+ { "input": "What's the distance from Earth to Mars?", "output": "I don't know" },
+ { "input": "What's the best movie this year?", "output": "I don't know" },
+ { "input": "How many points do I earn for travel expenses with Celestial Rewards?", "output": "You earn 3 points per dollar spent on travel expenses with the Celestial Rewards Credit Card." },
+ { "input": "How do I lose weight fast?", "output": "I don't know" },
+ { "input": "Where can I learn guitar?", "output": "I don't know" },
+ { "input": "Are there late payment fees for Celestial Rewards Card?", "output": "Yes, late payment fees for the Celestial Rewards Card can be up to $39." },
+ { "input": "Does Orbit Card provide purchase protection?", "output": "Yes, Orbit Card includes purchase protection against theft or damage within 90 days of purchase." },
+ { "input": "Recommend me a good book.", "output": "I don't know" },
+ { "input": "What credit cards am I eligible for?", "output": "With a credit score of 550, you are only eligible for the Orbit credit card" },
+ { "input": "How do I dispute a charge on my Celestial Rewards Card?", "output": "Contact customer support or initiate a dispute via your online account within 60 days of the statement date." },
+ { "input": "Can you book a hotel room for me?", "output": "I don't know" },
+ { "input": "Is there an introductory APR on the Orbit Credit Card?", "output": "Yes, the Orbit Credit Card offers 0% introductory APR for the first 12 months on purchases and balance transfers." },
+ { "input": "What benefits does the Orbit Card provide for car rentals?", "output": "Orbit Card provides secondary collision damage waiver insurance for car rentals." },
+ { "input": "Who is the current president of France?", "output": "I don't know" },
+ { "input": "Does the Orbit Credit Card include travel insurance?", "output": "Yes, the Orbit Credit Card includes complimentary travel accident insurance when travel is purchased using the card." },
+ { "input": "Help me fix my computer.", "output": "I don't know" },
+ { "input": "What spending categories give extra rewards on Celestial Card?", "output": "Travel, dining, and grocery categories earn extra rewards points with the Celestial Rewards Card." },
+ { "input": "Can I manage my Orbit Card account online?", "output": "Yes, you can manage your Orbit Card online via the Brahe Bank online banking portal or mobile app." },
+ { "input": "Translate hello to Japanese.", "output": "I don't know" },
+ { "input": "Does the Celestial Rewards Card have an annual rewards cap?", "output": "No, the Celestial Rewards Card has no annual cap on rewards points." },
+ { "input": "Who won the last soccer world cup?", "output": "I don't know" },
+ { "input": "Can points earned with Orbit Card be transferred?", "output": "Orbit Card points cannot be transferred but can be redeemed directly for cashback, statement credits, or gift cards." },
+ { "input": "What's the tallest mountain?", "output": "I don't know" },
+ { "input": "Does Orbit Card charge foreign transaction fees?", "output": "No, the Orbit Credit Card has no foreign transaction fees." },
+ { "input": "Suggest a healthy meal.", "output": "I don't know" },
+ { "input": "What can I do with my credit score?", "output": "With a credit score of 550, you are only eligible for the Orbit credit card" },
+ { "input": "What credit score is recommended for Celestial Rewards Card approval?", "output": "A good to excellent credit score (670 or above) is recommended for approval." },
+ { "input": "How can I redeem my Celestial Reward points?", "output": "Celestial Reward points can be redeemed for travel, statement credits, gift cards, or merchandise through the rewards portal." },
+ { "input": "What is the APR for balance transfers on the Orbit Credit Card?", "output": "The APR for balance transfers on the Orbit Credit Card is 0% introductory APR for the first 12 months, after which it ranges from 15.99% to 23.99%." },
+ { "input": "What are the cashback rewards offered by the Orbit Credit Card?", "output": "The Orbit Credit Card offers 2% cashback on dining, 1.5% on groceries, and 1% on all other purchases." },
+ { "input": "How do airplanes fly?", "output": "I don't know" },
+ { "input": "What's the regular APR on Celestial Rewards Card purchases?", "output": "The regular APR for Celestial Rewards Card purchases ranges between 16.24% and 24.99%." },
+ { "input": "What's today's stock market price?", "output": "I don't know" },
+ { "input": "What's the cash advance fee on Celestial Rewards Card?", "output": "The cash advance fee is either $10 or 5% of the cash advance amount, whichever is greater." },
+ { "input": "How long do Celestial Reward points remain valid?", "output": "Celestial Reward points never expire as long as your account remains active." },
+ { "input": "What's my horoscope today?", "output": "I don't know" },
+ { "input": "Can I add an authorized user to my Orbit Credit Card?", "output": "Yes, you can add authorized users to your Orbit Credit Card account at no additional charge." },
+ { "input": "Tell me a joke.", "output": "I don't know" },
+ { "input": "Can Celestial Rewards Card points be redeemed as cashback?", "output": "Yes, points can be redeemed as statement credits, equivalent to cashback." },
+ { "input": "How old is the universe?", "output": "I don't know" },
+ { "input": "What's the introductory bonus for Celestial Rewards Card?", "output": "The Celestial Rewards Card offers a bonus of 20,000 points after spending $1,000 in the first 3 months." },
+ { "input": "Find me the cheapest flights.", "output": "I don't know" },
+ { "input": "What is my credit score?", "output": "Your credit score is 550." }
+]
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/after/images/bot-demo.gif b/examples/agent/langgraph-fsi-agent/after/images/bot-demo.gif
new file mode 100644
index 00000000..ea25d775
Binary files /dev/null and b/examples/agent/langgraph-fsi-agent/after/images/bot-demo.gif differ
diff --git a/examples/agent/langgraph-fsi-agent/after/public/avatars/assistant.png b/examples/agent/langgraph-fsi-agent/after/public/avatars/assistant.png
new file mode 100644
index 00000000..114532c0
Binary files /dev/null and b/examples/agent/langgraph-fsi-agent/after/public/avatars/assistant.png differ
diff --git a/examples/agent/langgraph-fsi-agent/after/public/avatars/tool.png b/examples/agent/langgraph-fsi-agent/after/public/avatars/tool.png
new file mode 100644
index 00000000..e7c061e8
Binary files /dev/null and b/examples/agent/langgraph-fsi-agent/after/public/avatars/tool.png differ
diff --git a/examples/agent/langgraph-fsi-agent/after/public/logo_dark.png b/examples/agent/langgraph-fsi-agent/after/public/logo_dark.png
new file mode 100644
index 00000000..3a3417d2
Binary files /dev/null and b/examples/agent/langgraph-fsi-agent/after/public/logo_dark.png differ
diff --git a/examples/agent/langgraph-fsi-agent/after/public/logo_light.png b/examples/agent/langgraph-fsi-agent/after/public/logo_light.png
new file mode 100644
index 00000000..379ff554
Binary files /dev/null and b/examples/agent/langgraph-fsi-agent/after/public/logo_light.png differ
diff --git a/examples/agent/langgraph-fsi-agent/after/pyproject.toml b/examples/agent/langgraph-fsi-agent/after/pyproject.toml
new file mode 100644
index 00000000..9b2eb20b
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/pyproject.toml
@@ -0,0 +1,28 @@
+[project]
+name = "galileo-langgraph-fsi-agent"
+version = "0.1.0"
+description = "A demo langgraph Financial Services agent with Splunk AO evaluations"
+license = "MIT"
+requires-python = "<3.14,>=3.11"
+dependencies = [
+ "chainlit~=2.5.5",
+ "galileo (>=1.16.0,<2.0.0)",
+ "grandalf>=0.8",
+ "langchain-community>=0.3.24",
+ "langchain-pinecone>=0.2.6",
+ "langchain[openai]~=0.3.18",
+ "langgraph~=0.4.7",
+ "langgraph-supervisor>=0.0.26",
+ "pinecone[asyncio]>=6.0.2",
+ "python-dotenv>=1.1.0",
+]
+
+[dependency-groups]
+dev = [
+ "ruff>=0.11.11",
+ "pytest (>=8.4.1,<9.0.0)",
+ "pytest-dotenv>=0.5.2"
+]
+
+[tool.ruff]
+line-length = 120
diff --git a/examples/agent/langgraph-fsi-agent/after/scripts/setup_pinecone.py b/examples/agent/langgraph-fsi-agent/after/scripts/setup_pinecone.py
new file mode 100644
index 00000000..4f3b81fe
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/scripts/setup_pinecone.py
@@ -0,0 +1,172 @@
+"""
+This script sets up a Pinecone index for storing and retrieving documents using the documents in the `source-docs` folder.
+
+To use this, you will need to have the following environment variables set in the .env file:
+- `PINECONE_API_KEY`: Your Pinecone API key.
+- `OPENAI_API_KEY`: Your OpenAI API key (for embeddings).
+"""
+
+import asyncio
+import os
+
+from dotenv import load_dotenv
+
+from langchain.text_splitter import RecursiveCharacterTextSplitter
+
+from langchain_community.document_loaders import DirectoryLoader, TextLoader
+from langchain_openai import OpenAIEmbeddings
+from langchain_pinecone import PineconeVectorStore
+
+from pinecone import Pinecone
+
+load_dotenv()
+
+EMBEDDINGS = OpenAIEmbeddings()
+PINECONE_API_KEY = os.getenv("PINECONE_API_KEY")
+
+
+def load_documents(path):
+ """Load all markdown documents from source-docs folder"""
+ loader = DirectoryLoader(path, glob="*.md", loader_cls=TextLoader, loader_kwargs={"encoding": "utf-8"})
+ documents = loader.load()
+ return documents
+
+
+def chunk_documents(documents):
+ """Chunk documents semantically"""
+ text_splitter = RecursiveCharacterTextSplitter(
+ chunk_size=1000,
+ chunk_overlap=200,
+ length_function=len,
+ separators=[
+ "\n\n", # Double newlines (paragraphs)
+ "\n", # Single newlines
+ " ", # Spaces
+ ".", # Sentences
+ ",", # Clauses
+ "\u200b", # Zero-width space
+ "\uff0c", # Fullwidth comma
+ "\u3001", # Ideographic comma
+ "\uff0e", # Fullwidth full stop
+ "\u3002", # Ideographic full stop
+ "", # Character-level
+ ],
+ is_separator_regex=False,
+ )
+
+ chunked_docs = text_splitter.split_documents(documents)
+ return chunked_docs
+
+
+def setup_pinecone_index(index_name: str) -> None:
+ """Initialize Pinecone and create/connect to index"""
+ pc = Pinecone(api_key=PINECONE_API_KEY)
+
+ # Check if index exists, create if not
+ if index_name not in pc.list_indexes().names():
+ print(f"Creating new index: {index_name}")
+ pc.create_index(
+ name=index_name,
+ dimension=1536, # OpenAI embeddings dimension
+ metric="cosine",
+ spec={"serverless": {"cloud": "aws", "region": "us-east-1"}},
+ )
+ else:
+ print(f"Index {index_name} already exists")
+
+
+def check_index_has_data(index) -> bool:
+ """Check if the index already contains data"""
+ try:
+ stats = index.describe_index_stats()
+ total_vector_count = stats.get("total_vector_count", 0)
+ return total_vector_count > 0
+ except Exception as e:
+ print(f"Error checking index stats: {e}")
+ return False
+
+
+def upload_to_pinecone(chunked_docs, index_name: str, force_upload: bool = False) -> PineconeVectorStore:
+ """Upload chunked documents to Pinecone"""
+
+ # Check if index has data and we're not forcing upload
+ if not force_upload:
+ pc = Pinecone(api_key=PINECONE_API_KEY)
+ index = pc.Index(index_name)
+
+ if check_index_has_data(index):
+ print(f"Index {index_name} already contains data. Skipping upload.")
+ print("Use force_upload=True to overwrite existing data.")
+ return PineconeVectorStore(index_name=index_name, embedding=EMBEDDINGS)
+
+ # Create vector store and upload
+ print(f"Uploading {len(chunked_docs)} chunks to Pinecone...")
+ vector_store = PineconeVectorStore.from_documents(documents=chunked_docs, embedding=EMBEDDINGS, index_name=index_name)
+
+ print(f"Successfully uploaded {len(chunked_docs)} document chunks to Pinecone")
+ return vector_store
+
+
+def test_retrieval(index_name: str, query: str):
+ """Test document retrieval from Pinecone"""
+ vector_store = PineconeVectorStore(index_name=index_name, embedding=EMBEDDINGS)
+
+ # Test similarity search
+ results = vector_store.similarity_search(query, k=3)
+
+ print(f"\nTest query: '{query}'")
+ print(f"Found {len(results)} relevant chunks:")
+ for i, doc in enumerate(results, 1):
+ print(f"\n{i}. {doc.page_content[:200]}...")
+
+
+bank_documents = [
+ {
+ "index_name": "credit-card-information",
+ "path": "source-docs/credit-cards",
+ "test_query": "credit card",
+ }
+]
+
+
+async def main():
+ """
+ Main function to process and upload documents asynchronously
+ """
+
+ for doc in bank_documents:
+ index_name = doc["index_name"]
+ path = doc["path"]
+ test_query = doc["test_query"]
+
+ print(f"Loading documents for {index_name} folder...")
+ loaded_documents = load_documents(path)
+ print(f"Loaded {len(loaded_documents)} documents")
+
+ print(f"Chunking documents for {index_name}...")
+ chunked_docs = chunk_documents(loaded_documents)
+ print(f"Created {len(chunked_docs)} chunks")
+
+ print(f"Setting up Pinecone for {index_name}...")
+ setup_pinecone_index(index_name)
+
+ # Only upload if index is new or doesn't have data
+ print(f"Uploading to Pinecone for {index_name}...")
+ _ = upload_to_pinecone(chunked_docs, index_name=index_name)
+
+ # Wait for Pinecone to index the data
+ print("Waiting for Pinecone to index the data...")
+ await asyncio.sleep(30)
+
+ # Test retrieval for each index
+ for doc in bank_documents:
+ index_name = doc["index_name"]
+ test_query = doc["test_query"]
+ print(f"Testing retrieval for {index_name} with query: '{test_query}'")
+ test_retrieval(index_name=index_name, query=test_query)
+
+ print("✅ Document processing and upload complete!")
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/celestial-rewards-credit-card-faq.md b/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/celestial-rewards-credit-card-faq.md
new file mode 100644
index 00000000..8e84a61c
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/celestial-rewards-credit-card-faq.md
@@ -0,0 +1,24 @@
+# Frequently Asked Questions – Celestial Rewards Credit Card
+
+## Q1: How do I apply for the card?
+
+Apply online at [www.brahebank.com/creditcards](http://www.brahebank.com/creditcards) or visit a branch.
+
+## Q2: How can I earn Celestial Points?
+
+Earn 2 points for every $1 spent on purchases.
+
+## Q3: What can I redeem Celestial Points for?
+
+- Telescopes
+- Planetarium tickets
+- Astronomy accessories
+- Educational outreach donations
+
+## Q4: Are there blackout dates for redemptions?
+
+Yes, some planetarium venues may have blackout dates.
+
+## Q5: Can I transfer my points?
+
+No, points are non-transferable and tied to the primary cardholder account.
diff --git a/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/celestial-rewards-credit-card-overview.md b/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/celestial-rewards-credit-card-overview.md
new file mode 100644
index 00000000..9231d501
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/celestial-rewards-credit-card-overview.md
@@ -0,0 +1,43 @@
+# Brahe Bank Celestial Rewards Credit Card
+
+## Overview
+
+The Brahe Bank Celestial Rewards Credit Card is designed for stargazers, space enthusiasts, and everyday explorers. This premium credit card combines practical spending benefits with exclusive astronomy-themed rewards.
+
+## Key Features
+
+- **Interest Rate**:
+ - 26.9% APR on purchases
+ - 26.9% APR on cash advances
+ - 0.0% APR on balance transfers for 12 months
+
+- **Annual Fee**:
+ - $99 charged annually on the account anniversary
+
+- **Rewards Program – Celestial Points**:
+ - Earn 2 points per $1 spent on purchases
+ - Redeem points for:
+ - Telescopes
+ - Planetarium tickets
+ - Astronomy gear and experiences
+
+- **Additional Benefits**:
+ - Real-time fraud monitoring
+ - Zero liability on unauthorized purchases
+ - Invitations to exclusive stargazing events
+
+## Eligibility Requirements
+
+- Age 18+
+- U.S. resident with valid Social Security number
+- Satisfactory credit history, with a credit score over 600
+
+## Important Disclosures
+
+- Rates subject to change
+- Rewards and catalog availability may vary
+- Additional fees may apply for cash advances
+
+*Brahe Bank — Charting Your Financial Constellation.*
+
+Visit [www.brahebank.com/creditcards](http://www.brahebank.com/creditcards) for more details.
diff --git a/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/celestial-rewards-credit-card-rewards-summary.md b/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/celestial-rewards-credit-card-rewards-summary.md
new file mode 100644
index 00000000..04a8314d
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/celestial-rewards-credit-card-rewards-summary.md
@@ -0,0 +1,22 @@
+# Celestial Points Rewards Catalog – Summary
+
+## Telescope Rewards
+
+- **Beginner Refractor Telescope** – 25,000 points
+- **Intermediate Reflector Telescope** – 45,000 points
+- **Advanced Astrophotography Kit** – 80,000 points
+
+## Planetarium Tickets
+
+- **2 General Admission Tickets** – 5,000 points
+- **Family Pack (4 tickets + gift voucher)** – 12,000 points
+- **Exclusive Night Sky Tour** – 20,000 points
+
+## Accessories & Experiences
+
+- **Star Chart Kit** – 3,500 points
+- **Astronomy-Themed Blanket** – 6,000 points
+- **Private Observatory Session** – 50,000 points
+
+> Rewards availability and shipping timelines are subject to change.
+> See [www.brahebank.com/rewards](http://www.brahebank.com/rewards) for current listings.
diff --git a/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/celestial-rewards-credit-card-terms-and-conditions.md b/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/celestial-rewards-credit-card-terms-and-conditions.md
new file mode 100644
index 00000000..f945a217
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/celestial-rewards-credit-card-terms-and-conditions.md
@@ -0,0 +1,30 @@
+# Terms & Conditions – Celestial Rewards Credit Card
+
+## Interest Rates and Charges
+
+- **Purchase APR**: 26.9% (variable)
+- **Cash Advance APR**: 26.9% (variable)
+- **Balance Transfer APR**: 0.0% (for 12 months)
+- **Minimum Interest Charge**: $1.50
+- **Grace Period**: 21 days on purchases
+
+## Fees
+
+- **Annual Fee**: $99
+- **Foreign Transaction Fee**: 3%
+- **Late Payment Fee**: Up to $40
+- **Returned Payment Fee**: Up to $35
+- **Cash Advance Fee**: Greater of $10 or 5%
+
+## Billing Rights Summary
+
+To report errors or questions about your bill, contact us within 60 days. Write to:
+Brahe Bank
+P.O. Box 1400
+Observatory City, ST 00001
+
+## Reward Terms
+
+- Points are earned on net purchases only
+- Points expire after 36 months
+- Redemption options and values subject to change
diff --git a/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/orbit-credit-card-faq.md b/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/orbit-credit-card-faq.md
new file mode 100644
index 00000000..b4faeb9a
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/orbit-credit-card-faq.md
@@ -0,0 +1,21 @@
+# Frequently Asked Questions – Orbit Basic Credit Card
+
+## Q1: Does this card have an annual fee?
+
+No. Orbit Basic has no annual fee, ever.
+
+## Q2: Are there any rewards?
+
+No, this card does not offer points, miles, or cashback. It is intended for simple credit usage.
+
+## Q3: What are the interest rates?
+
+29.9% APR on purchases, 34.9% on cash advances. These are variable rates and may change.
+
+## Q4: Who should apply for this card?
+
+Those who want a simple credit card for essential purchases, with no annual fee or complicated reward systems.
+
+## Q5: Can I manage the card online?
+
+Yes. You can view transactions, pay bills, and manage your account via the Brahe Bank app or website.
diff --git a/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/orbit-credit-card-overview.md b/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/orbit-credit-card-overview.md
new file mode 100644
index 00000000..c7fb1aff
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/orbit-credit-card-overview.md
@@ -0,0 +1,39 @@
+# Brahe Bank Orbit Basic Credit Card
+
+## Overview
+
+The Brahe Bank Orbit Basic Credit Card is a no-annual-fee, no-rewards credit solution built for simplicity and flexibility. Designed for customers who want to keep things straightforward, this card offers a basic way to manage everyday expenses without the fuss.
+
+## Key Features
+
+- **Interest Rate**:
+ - 29.9% APR on purchases
+ - 34.9% APR on cash advances
+ - 0.0% APR on balance transfers for 12 months
+
+- **Annual Fee**:
+ - None — $0 forever
+
+- **Rewards Program**:
+ - This card does not include a rewards program
+
+- **Additional Benefits**:
+ - Standard fraud protection
+ - Digital card management tools via Brahe Bank mobile and web apps
+ - Contactless payment support
+
+## Eligibility Requirements
+
+- Must be 18 or older
+- Valid U.S. mailing address and SSN
+- Fair credit history, with a credit score over 500
+
+## Important Disclosures
+
+- APRs are variable and may adjust with market conditions
+- This card is best suited for those who pay off balances monthly
+- No annual fee, ever
+
+*Brahe Bank — Simplicity That Keeps You in Orbit.*
+
+Learn more at [www.brahebank.com/orbitbasic](http://www.brahebank.com/orbitbasic)
diff --git a/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/orbit-credit-card-rewards.md b/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/orbit-credit-card-rewards.md
new file mode 100644
index 00000000..59a395a1
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/orbit-credit-card-rewards.md
@@ -0,0 +1,13 @@
+# Rewards Catalog – Orbit Basic Credit Card
+
+The Orbit Basic Credit Card does **not** include a rewards program.
+
+This card is designed for customers who prefer:
+
+- No annual fees
+- No complex point systems
+- Straightforward credit access
+
+If you're looking for a card with astronomy-themed rewards, check out the [Celestial Rewards Credit Card](http://www.brahebank.com/creditcards) from Brahe Bank.
+
+*Orbit Basic: Credit that keeps you grounded.*
diff --git a/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/orbit-credit-card-terms-and-conditions.md b/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/orbit-credit-card-terms-and-conditions.md
new file mode 100644
index 00000000..bd5b6f2f
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/source-docs/credit-cards/orbit-credit-card-terms-and-conditions.md
@@ -0,0 +1,28 @@
+# Terms & Conditions – Orbit Basic Credit Card
+
+## Interest Rates and Charges
+
+- **Purchase APR**: 29.9% (variable)
+- **Cash Advance APR**: 34.9% (variable)
+- **Balance Transfer APR**: 0.0% (for 12 months)
+- **Minimum Interest Charge**: $1.50
+- **Grace Period**: 21 days on purchases if balance is paid in full
+
+## Fees
+
+- **Annual Fee**: None
+- **Foreign Transaction Fee**: 3% of each transaction
+- **Late Payment Fee**: Up to $40
+- **Returned Payment Fee**: Up to $35
+- **Cash Advance Fee**: Greater of $10 or 5% of the transaction
+
+## Billing Rights Summary
+
+If you believe there’s an error on your statement, notify us in writing within 60 days:
+Brahe Bank
+P.O. Box 1400
+Observatory City, ST 00001
+
+## Additional Disclosures
+
+This card does not accrue any points, miles, or cashback. It is intended for basic credit access with minimal complexity.
diff --git a/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/__init__.py b/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/agents/__init__.py b/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/agents/__init__.py
new file mode 100644
index 00000000..79bb19d5
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/agents/__init__.py
@@ -0,0 +1,7 @@
+"""Agents package for the Splunk AO LangGraph FSI Agent."""
+
+from .credit_card_information_agent import create_credit_card_information_agent
+from .credit_score_agent import create_credit_score_agent
+from .supervisor_agent import create_supervisor_agent
+
+__all__ = ["create_credit_card_information_agent", "create_credit_score_agent", "create_supervisor_agent"]
diff --git a/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/agents/credit_card_information_agent.py b/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/agents/credit_card_information_agent.py
new file mode 100644
index 00000000..e3c43802
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/agents/credit_card_information_agent.py
@@ -0,0 +1,43 @@
+"""
+Builds a graph using all the nodes and edges defined in the application.
+"""
+
+import os
+from langchain_openai import ChatOpenAI
+from langgraph.graph.graph import CompiledGraph
+from langgraph.prebuilt import create_react_agent
+
+from ..tools.pinecone_retrieval_tool import PineconeRetrievalTool
+
+# Create the tools
+credit_card_information_retrieval_tool = PineconeRetrievalTool("credit-card-information")
+
+
+def create_credit_card_information_agent() -> CompiledGraph:
+ """
+ Create an agent that can help with inquires about the available credit card options from the Brahe Bank.
+
+ returns: A compiled graph for this agent.
+ """
+
+ # Create an agent
+ agent = create_react_agent(
+ model=ChatOpenAI(model=os.environ["MODEL_NAME"], name="Credit Card Agent"),
+ tools=[credit_card_information_retrieval_tool],
+ prompt=(
+ """
+ You are an expert on Brahe Bank credit card products. Provide clear, accurate,
+ and concise information. Only answer with known facts from provided documentation,
+ and information about the requestor such as their credit score.
+ If unsure, state "I don't know."
+ """
+ ),
+ name="credit-card-agent",
+ )
+
+ # Uncomment the following lines to print the compiled graph to the console in Mermaid format
+ # print("Compiled Credit Card Agent Graph:")
+ # print(agent.get_graph().draw_mermaid())
+
+ # Return the compiled graph
+ return agent
diff --git a/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/agents/credit_score_agent.py b/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/agents/credit_score_agent.py
new file mode 100644
index 00000000..7009b98d
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/agents/credit_score_agent.py
@@ -0,0 +1,40 @@
+"""
+A credit score agent for the Brahe Bank application.
+"""
+
+import os
+from langchain_openai import ChatOpenAI
+from langgraph.graph.graph import CompiledGraph
+from langgraph.prebuilt import create_react_agent
+
+from ..tools.credit_score_tool import CreditScoreTool
+
+# Create the tools
+credit_score_tool = CreditScoreTool()
+
+
+def create_credit_score_agent() -> CompiledGraph:
+ """
+ Create an agent that can help with inquires about your credit score.
+
+ returns: A compiled graph for this agent.
+ """
+
+ # Create an agent
+ agent = create_react_agent(
+ model=ChatOpenAI(model=os.environ["MODEL_NAME"], name="Credit Score Agent"),
+ tools=[credit_score_tool],
+ prompt=(
+ """
+ You are an expert on credit score. Provide the user with their credit score from the credit_score_tool.
+ """
+ ),
+ name="credit-score-agent",
+ )
+
+ # Uncomment the following lines to print the compiled graph to the console in Mermaid format
+ # print("Compiled Credit Score Agent Graph:")
+ # print(agent.get_graph().draw_mermaid())
+
+ # Return the compiled graph
+ return agent
diff --git a/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/agents/supervisor_agent.py b/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/agents/supervisor_agent.py
new file mode 100644
index 00000000..262cdac5
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/agents/supervisor_agent.py
@@ -0,0 +1,42 @@
+"""
+Supervisor Agent for Brahe Bank Application
+"""
+
+import os
+from langchain_openai import ChatOpenAI
+from langgraph_supervisor import create_supervisor
+
+from .credit_score_agent import create_credit_score_agent
+from .credit_card_information_agent import create_credit_card_information_agent
+
+# Define the agents that the supervisor will manage
+credit_card_information_agent = create_credit_card_information_agent()
+credit_score_agent = create_credit_score_agent()
+
+
+def create_supervisor_agent():
+ """
+ Create a supervisor agent that manages all the agents in the Brahe Bank application.
+ """
+ bank_supervisor_agent = create_supervisor(
+ model=ChatOpenAI(model=os.environ["MODEL_NAME"], name="Supervisor"),
+ agents=[credit_card_information_agent, credit_score_agent],
+ prompt=(
+ """
+ You are a supervisor managing the following agents:
+ - a credit card information agent. Assign any tasks related to information about credit cards to this agent
+ Otherwise, only respond with 'I don't know' or 'I cannot answer that question'.
+ If you need to ask the user for more information, do so in a concise manner.
+ """
+ ),
+ add_handoff_back_messages=True,
+ output_mode="full_history",
+ supervisor_name="brahe-bank-supervisor-agent",
+ ).compile()
+ bank_supervisor_agent.name = "brahe-bank-supervisor-agent"
+
+ # Uncomment the following lines to print the compiled graph to the console in Mermaid format
+ # print("Compiled Bank Supervisor Agent Graph:")
+ # print(bank_supervisor_agent.get_graph().draw_mermaid())
+
+ return bank_supervisor_agent
diff --git a/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/tools/__init__.py b/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/tools/__init__.py
new file mode 100644
index 00000000..692862cf
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/tools/__init__.py
@@ -0,0 +1,6 @@
+"""Tools package for the Splunk AO LangGraph FSI Agent."""
+
+from .pinecone_retrieval_tool import PineconeRetrievalTool
+from .credit_score_tool import CreditScoreTool
+
+__all__ = ["PineconeRetrievalTool", "CreditScoreTool"]
diff --git a/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/tools/credit_score_tool.py b/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/tools/credit_score_tool.py
new file mode 100644
index 00000000..f4ffe135
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/tools/credit_score_tool.py
@@ -0,0 +1,23 @@
+"""
+A tool for retrieving information about credit scores from a financial services knowledge base.
+"""
+
+from typing_extensions import override
+
+from langchain.tools import BaseTool
+
+
+class CreditScoreTool(BaseTool):
+ """
+ CreditScoreTool is a tool for retrieving relevant information about credit scores from a financial services knowledge base.
+ """
+
+ name: str = "credit_score_retrieval"
+ description: str = "Retrieve relevant information about credit scores from the financial services knowledge base"
+
+ @override
+ def _run(self) -> str:
+ """
+ Always return a credit score of 550 for testing purposes.
+ """
+ return "Your credit score is 550"
diff --git a/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/tools/pinecone_retrieval_tool.py b/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/tools/pinecone_retrieval_tool.py
new file mode 100644
index 00000000..0b31bd70
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/src/galileo_langgraph_fsi_agent/tools/pinecone_retrieval_tool.py
@@ -0,0 +1,58 @@
+"""
+A tool for retrieving information from the Pinecone vector database.
+"""
+
+from typing_extensions import override
+
+from langchain.tools import BaseTool
+from langchain_pinecone import PineconeVectorStore
+from langchain_openai import OpenAIEmbeddings
+from pydantic import BaseModel, Field
+
+
+class RetrievalInput(BaseModel):
+ """
+ RetrievalInput is a Pydantic model representing the input schema for a document retrieval operation.
+ Attributes:
+ query (str): The search query used to find relevant documents.
+ k (int, optional): The number of documents to retrieve. Defaults to 3.
+ """
+
+ query: str = Field(description="The search query to find relevant documents")
+ k: int = Field(default=3, description="Number of documents to retrieve")
+
+
+class PineconeRetrievalTool(BaseTool):
+ """
+ PineconeRetrievalTool is a tool for retrieving relevant information from a financial services knowledge base using Pinecone as a vector store.
+ """
+
+ name: str = "pinecone_retrieval"
+ description: str = "Retrieve relevant information from the financial services knowledge base"
+ args_schema: type[BaseModel] = RetrievalInput # type: ignore
+
+ def __init__(self, index_name: str):
+ super().__init__()
+ self._embeddings = OpenAIEmbeddings()
+ self._index_name = index_name
+ self._vector_store = PineconeVectorStore(index_name=self._index_name, embedding=self._embeddings)
+
+ @override
+ def _run(self, query: str, k: int = 3) -> str:
+ """Execute the retrieval"""
+ try:
+ # Perform similarity search
+ results = self._vector_store.similarity_search(query, k=k)
+
+ if not results:
+ return "No relevant information found in the knowledge base."
+
+ # Format the results
+ formatted_results = []
+ for i, doc in enumerate(results, 1):
+ formatted_results.append(f"Document {i}:\n{doc.page_content}\n")
+
+ return "\n".join(formatted_results)
+
+ except Exception as e:
+ return f"Error retrieving information: {str(e)}"
diff --git a/examples/agent/langgraph-fsi-agent/after/test.py b/examples/agent/langgraph-fsi-agent/after/test.py
new file mode 100644
index 00000000..3fcf41b0
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/after/test.py
@@ -0,0 +1,143 @@
+"""
+This file defines a single test that runs the chatbot using the Splunk AO experiments
+framework, with a dataset of questions.
+
+You will need to configure your environment variables to run this test in your .env file.
+See the details in the README.md file for how to set up your environment variables.
+"""
+
+import json
+import os
+import time
+from typing import Any
+
+from langchain.schema.runnable.config import RunnableConfig
+from langchain_core.callbacks import Callbacks
+from langchain_core.messages import HumanMessage
+
+from splunk_ao import SplunkAOMetrics, splunk_ao_context
+from splunk_ao.datasets import create_dataset, get_dataset, delete_dataset
+from splunk_ao.experiments import get_experiment, run_experiment
+from splunk_ao.handlers.langchain import SplunkAOCallback
+
+from src.galileo_langgraph_fsi_agent.agents.supervisor_agent import (
+ create_supervisor_agent,
+)
+
+DATASET_NAME = "langgraph-fsi-unit-test-dataset"
+
+
+def setup_module():
+ """
+ Setup function that runs once when this test module is executed.
+
+ This will load the environment variables, then ensure we have a valid dataset to run the experiment against.
+ """
+ print("Setting up test environment...")
+
+ # Verify required environment variables are set
+ # You will also need to set up the environment variables for your OpenAI API connection.
+ if not os.getenv("SPLUNK_AO_PROJECT") or not os.getenv("SPLUNK_AO_API_KEY"):
+ raise ValueError("SPLUNK_AO_PROJECT and SPLUNK_AO_API_KEY environment variables are required")
+
+ # Check to see if we already have the dataset, if not we can create it.
+ dataset = get_dataset(
+ name=DATASET_NAME,
+ )
+
+ if dataset is not None:
+ delete_dataset(id=dataset.id)
+ dataset = None
+
+ # If we don't have the dataset, create it with some canned data. Some of these questions
+ # are designed to be factual, while others are designed to be nonsensical or not
+ # answerable by the model. This will help us test the correctness and instruction adherence
+ # of the model when running the experiment.
+ if dataset is None:
+ # Load dataset content from JSON file
+ with open("./dataset-test.json", "r", encoding="utf-8") as f:
+ dataset_content = json.load(f)
+
+ dataset = create_dataset(
+ name=DATASET_NAME,
+ content=dataset_content,
+ )
+
+
+# Create the supervisor agent
+supervisor_agent = create_supervisor_agent()
+
+
+def send_message_to_supervisor_agent(message: str):
+ """
+ Send a message to the supervisor agent and return the response.
+
+ This function simulates sending a message to the supervisor agent and getting a response.
+ It is used in the test to interact with the chatbot.
+ """
+ galileo_logger = splunk_ao_context.get_logger_instance()
+ callback = SplunkAOCallback(galileo_logger=galileo_logger, start_new_trace=False, flush_on_chain_end=False)
+
+ messages: dict[str, Any] = {"messages": [HumanMessage(content=message)]}
+ callbacks: Callbacks = [callback]
+ config: dict[str, Any] = {"configurable": {"thread_id": 42}}
+
+ runnable_config = RunnableConfig(callbacks=callbacks, **config)
+
+ response = supervisor_agent.invoke(input=messages, config=runnable_config)
+
+ return response["messages"][-1].content
+
+
+def test_run_experiment_with_dataset():
+ """
+ This test will run the dataset against our chatbot app using the Splunk AO experiments framework.
+ This is designed to show how you can run experiments with a dataset against a real-world application
+ to use inside a CI/CD pipeline.
+
+ The default system prompt encourages the assistant to be helpful, but can lead to hallucinations, so
+ this test should fail out of the box.
+
+ To make this test pass, you will need to modify the system prompt in the `app.py` file. There is
+ a comment in the `app.py` file that shows a better system prompt, which should allow this test to pass.
+ """
+ # Run the experiment using the canned dataset
+ experiment_response = run_experiment(
+ # This name is reused, so each experiment run will get a generated name
+ # with the run date and time
+ experiment_name="langgraph-fsi-experiment",
+ dataset_name=DATASET_NAME,
+ function=send_message_to_supervisor_agent,
+ metrics=[SplunkAOMetrics.action_advancement, SplunkAOMetrics.action_completion, SplunkAOMetrics.tool_error_rate, SplunkAOMetrics.tool_selection_quality],
+ project=os.getenv("SPLUNK_AO_PROJECT"),
+ )
+
+ # Poll until we have the results - waiting 5 seconds between polls
+ # We need to use the project ID and experiment name from the response as we only have the project name, and the experiment name
+ # is generated with a timestamp, so we can't use the name directly.
+ experiment = get_experiment(
+ project_id=experiment_response["experiment"].project_id,
+ experiment_name=experiment_response["experiment"].name,
+ )
+ while (
+ experiment.aggregate_metrics is None # type: ignore
+ or "average_agentic_session_success" not in experiment.aggregate_metrics # type: ignore
+ or "average_agentic_workflow_success" not in experiment.aggregate_metrics # type: ignore
+ or "average_tool_selection_quality" not in experiment.aggregate_metrics # type: ignore
+ or "count_tool_error_rate" not in experiment.aggregate_metrics # type: ignore
+ ):
+ # If we don't have the metrics calculated, Sleep for 5 seconds before polling again
+ time.sleep(5)
+
+ # Reload the experiment to see if we have the metrics
+ experiment = get_experiment(
+ project_id=experiment_response["experiment"].project_id,
+ experiment_name=experiment_response["experiment"].name,
+ )
+
+ # # Assert the experiment has the expected metric values - each should be 1.0
+ # # However, the default system prompt can lead to hallucinations, so this test may fail.
+ assert experiment.aggregate_metrics["average_agentic_session_success"] == 1 # type: ignore
+ assert experiment.aggregate_metrics["average_agentic_workflow_success"] == 1 # type: ignore
+ assert experiment.aggregate_metrics["average_tool_selection_quality"] == 1 # type: ignore
+ assert experiment.aggregate_metrics["count_tool_error_rate"] == 0 # type: ignore
diff --git a/examples/agent/langgraph-fsi-agent/before/.chainlit/config.toml b/examples/agent/langgraph-fsi-agent/before/.chainlit/config.toml
new file mode 100644
index 00000000..f748dbb8
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/.chainlit/config.toml
@@ -0,0 +1,120 @@
+[project]
+# Whether to enable telemetry (default: true). No personal data is collected.
+enable_telemetry = true
+
+
+# List of environment variables to be provided by each user to use the app.
+user_env = []
+
+# Duration (in seconds) during which the session is saved when the connection is lost
+session_timeout = 3600
+
+# Duration (in seconds) of the user session expiry
+user_session_timeout = 1296000 # 15 days
+
+# Enable third parties caching (e.g., LangChain cache)
+cache = false
+
+# Authorized origins
+allow_origins = ["*"]
+
+[features]
+# Process and display HTML in messages. This can be a security risk (see https://stackoverflow.com/questions/19603097/why-is-it-dangerous-to-render-user-generated-html-or-javascript)
+unsafe_allow_html = false
+
+# Process and display mathematical expressions. This can clash with "$" characters in messages.
+latex = false
+
+# Autoscroll new user messages at the top of the window
+user_message_autoscroll = true
+
+# Automatically tag threads with the current chat profile (if a chat profile is used)
+auto_tag_thread = true
+
+# Allow users to edit their own messages
+edit_message = true
+
+# Authorize users to spontaneously upload files with messages
+[features.spontaneous_file_upload]
+ enabled = true
+ # Define accepted file types using MIME types
+ # Examples:
+ # 1. For specific file types:
+ # accept = ["image/jpeg", "image/png", "application/pdf"]
+ # 2. For all files of certain type:
+ # accept = ["image/*", "audio/*", "video/*"]
+ # 3. For specific file extensions:
+ # accept = { "application/octet-stream" = [".xyz", ".pdb"] }
+ # Note: Using "*/*" is not recommended as it may cause browser warnings
+ accept = ["*/*"]
+ max_files = 20
+ max_size_mb = 500
+
+[features.audio]
+ # Sample rate of the audio
+ sample_rate = 24000
+
+[features.mcp.sse]
+ enabled = true
+
+[features.mcp.stdio]
+ enabled = true
+ # Only the executables in the allow list can be used for MCP stdio server.
+ # Only need the base name of the executable, e.g. "npx", not "/usr/bin/npx".
+ # Please don't comment this line for now, we need it to parse the executable name.
+ allowed_executables = [ "npx", "uvx" ]
+
+[UI]
+# Name of the assistant.
+name = "Assistant"
+
+# default_theme = "dark"
+
+# layout = "wide"
+
+# default_sidebar_state = "open"
+
+# Description of the assistant. This is used for HTML tags.
+# description = ""
+
+# Chain of Thought (CoT) display mode. Can be "hidden", "tool_call" or "full".
+cot = "full"
+
+# Specify a CSS file that can be used to customize the user interface.
+# The CSS file can be served from the public directory or via an external link.
+# custom_css = "/public/test.css"
+
+# Specify additional attributes for a custom CSS file
+# custom_css_attributes = "media=\"print\""
+
+# Specify a JavaScript file that can be used to customize the user interface.
+# The JavaScript file can be served from the public directory.
+# custom_js = "/public/test.js"
+
+# Specify additional attributes for custom JS file
+# custom_js_attributes = "async type = \"module\""
+
+# Custom login page image, relative to public directory or external URL
+# login_page_image = "/public/custom-background.jpg"
+
+# Custom login page image filter (Tailwind internal filters, no dark/light variants)
+# login_page_image_filter = "brightness-50 grayscale"
+# login_page_image_dark_filter = "contrast-200 blur-sm"
+
+# Specify a custom meta image url.
+# custom_meta_image_url = "https://chainlit-cloud.s3.eu-west-3.amazonaws.com/logo/chainlit_banner.png"
+
+# Specify a custom build directory for the frontend.
+# This can be used to customize the frontend code.
+# Be careful: If this is a relative path, it should not start with a slash.
+# custom_build = "./public/build"
+
+# Specify optional one or more custom links in the header.
+# [[UI.header_links]]
+# name = "Issues"
+# display_name = "Report Issue"
+# icon_url = "https://avatars.githubusercontent.com/u/128686189?s=200&v=4"
+# url = "https://github.com/Chainlit/chainlit/issues"
+
+[meta]
+generated_by = "2.5.5"
diff --git a/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/bn.json b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/bn.json
new file mode 100644
index 00000000..36c86764
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/bn.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u09ac\u09be\u09a4\u09bf\u09b2 \u0995\u09b0\u09c1\u09a8",
+ "confirm": "\u09a8\u09bf\u09b6\u09cd\u099a\u09bf\u09a4 \u0995\u09b0\u09c1\u09a8",
+ "continue": "\u099a\u09be\u09b2\u09bf\u09af\u09bc\u09c7 \u09af\u09be\u09a8",
+ "goBack": "\u09aa\u09bf\u099b\u09a8\u09c7 \u09af\u09be\u09a8",
+ "reset": "\u09b0\u09bf\u09b8\u09c7\u099f \u0995\u09b0\u09c1\u09a8",
+ "submit": "\u099c\u09ae\u09be \u09a6\u09bf\u09a8"
+ },
+ "status": {
+ "loading": "\u09b2\u09cb\u09a1 \u09b9\u099a\u09cd\u099b\u09c7...",
+ "error": {
+ "default": "\u098f\u0995\u099f\u09bf \u09a4\u09cd\u09b0\u09c1\u099f\u09bf \u0998\u099f\u09c7\u099b\u09c7",
+ "serverConnection": "\u09b8\u09be\u09b0\u09cd\u09ad\u09be\u09b0\u09c7\u09b0 \u09b8\u09be\u09a5\u09c7 \u09b8\u0982\u09af\u09cb\u0997 \u0995\u09b0\u09be \u09af\u09be\u099a\u09cd\u099b\u09c7 \u09a8\u09be"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u0985\u09cd\u09af\u09be\u09aa\u09cd\u09b2\u09bf\u0995\u09c7\u09b6\u09a8 \u09ac\u09cd\u09af\u09ac\u09b9\u09be\u09b0 \u0995\u09b0\u09a4\u09c7 \u09b2\u0997\u0987\u09a8 \u0995\u09b0\u09c1\u09a8",
+ "form": {
+ "email": {
+ "label": "\u0987\u09ae\u09c7\u0987\u09b2 \u09a0\u09bf\u0995\u09be\u09a8\u09be",
+ "required": "\u0987\u09ae\u09c7\u0987\u09b2 \u098f\u0995\u099f\u09bf \u0986\u09ac\u09b6\u09cd\u09af\u0995 \u0995\u09cd\u09b7\u09c7\u09a4\u09cd\u09b0"
+ },
+ "password": {
+ "label": "\u09aa\u09be\u09b8\u0993\u09af\u09bc\u09be\u09b0\u09cd\u09a1",
+ "required": "\u09aa\u09be\u09b8\u0993\u09af\u09bc\u09be\u09b0\u09cd\u09a1 \u098f\u0995\u099f\u09bf \u0986\u09ac\u09b6\u09cd\u09af\u0995 \u0995\u09cd\u09b7\u09c7\u09a4\u09cd\u09b0"
+ },
+ "actions": {
+ "signin": "\u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09c1\u09a8"
+ },
+ "alternativeText": {
+ "or": "\u0985\u09a5\u09ac\u09be"
+ }
+ },
+ "errors": {
+ "default": "\u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09be \u09b8\u09ae\u09cd\u09ad\u09ac \u09b9\u099a\u09cd\u099b\u09c7 \u09a8\u09be",
+ "signin": "\u0985\u09a8\u09cd\u09af \u098f\u0995\u099f\u09bf \u0985\u09cd\u09af\u09be\u0995\u09be\u0989\u09a8\u09cd\u099f \u09a6\u09bf\u09af\u09bc\u09c7 \u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09be\u09b0 \u099a\u09c7\u09b7\u09cd\u099f\u09be \u0995\u09b0\u09c1\u09a8",
+ "oauthSignin": "\u0985\u09a8\u09cd\u09af \u098f\u0995\u099f\u09bf \u0985\u09cd\u09af\u09be\u0995\u09be\u0989\u09a8\u09cd\u099f \u09a6\u09bf\u09af\u09bc\u09c7 \u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09be\u09b0 \u099a\u09c7\u09b7\u09cd\u099f\u09be \u0995\u09b0\u09c1\u09a8",
+ "redirectUriMismatch": "\u09b0\u09bf\u09a1\u09be\u0987\u09b0\u09c7\u0995\u09cd\u099f URI \u0993\u0986\u09a5 \u0985\u09cd\u09af\u09be\u09aa \u0995\u09a8\u09ab\u09bf\u0997\u09be\u09b0\u09c7\u09b6\u09a8\u09c7\u09b0 \u09b8\u09be\u09a5\u09c7 \u09ae\u09bf\u09b2\u099b\u09c7 \u09a8\u09be",
+ "oauthCallback": "\u0985\u09a8\u09cd\u09af \u098f\u0995\u099f\u09bf \u0985\u09cd\u09af\u09be\u0995\u09be\u0989\u09a8\u09cd\u099f \u09a6\u09bf\u09af\u09bc\u09c7 \u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09be\u09b0 \u099a\u09c7\u09b7\u09cd\u099f\u09be \u0995\u09b0\u09c1\u09a8",
+ "oauthCreateAccount": "\u0985\u09a8\u09cd\u09af \u098f\u0995\u099f\u09bf \u0985\u09cd\u09af\u09be\u0995\u09be\u0989\u09a8\u09cd\u099f \u09a6\u09bf\u09af\u09bc\u09c7 \u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09be\u09b0 \u099a\u09c7\u09b7\u09cd\u099f\u09be \u0995\u09b0\u09c1\u09a8",
+ "emailCreateAccount": "\u0985\u09a8\u09cd\u09af \u098f\u0995\u099f\u09bf \u0985\u09cd\u09af\u09be\u0995\u09be\u0989\u09a8\u09cd\u099f \u09a6\u09bf\u09af\u09bc\u09c7 \u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09be\u09b0 \u099a\u09c7\u09b7\u09cd\u099f\u09be \u0995\u09b0\u09c1\u09a8",
+ "callback": "\u0985\u09a8\u09cd\u09af \u098f\u0995\u099f\u09bf \u0985\u09cd\u09af\u09be\u0995\u09be\u0989\u09a8\u09cd\u099f \u09a6\u09bf\u09af\u09bc\u09c7 \u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09be\u09b0 \u099a\u09c7\u09b7\u09cd\u099f\u09be \u0995\u09b0\u09c1\u09a8",
+ "oauthAccountNotLinked": "\u0986\u09aa\u09a8\u09be\u09b0 \u09aa\u09b0\u09bf\u099a\u09af\u09bc \u09a8\u09bf\u09b6\u09cd\u099a\u09bf\u09a4 \u0995\u09b0\u09a4\u09c7, \u0986\u09aa\u09a8\u09bf \u09af\u09c7 \u0985\u09cd\u09af\u09be\u0995\u09be\u0989\u09a8\u09cd\u099f\u099f\u09bf \u09ae\u09c2\u09b2\u09a4 \u09ac\u09cd\u09af\u09ac\u09b9\u09be\u09b0 \u0995\u09b0\u09c7\u099b\u09bf\u09b2\u09c7\u09a8 \u09b8\u09c7\u099f\u09bf \u09a6\u09bf\u09af\u09bc\u09c7 \u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09c1\u09a8",
+ "emailSignin": "\u0987\u09ae\u09c7\u0987\u09b2 \u09aa\u09be\u09a0\u09be\u09a8\u09cb \u09af\u09be\u09af\u09bc\u09a8\u09bf",
+ "emailVerify": "\u0985\u09a8\u09c1\u0997\u09cd\u09b0\u09b9 \u0995\u09b0\u09c7 \u0986\u09aa\u09a8\u09be\u09b0 \u0987\u09ae\u09c7\u0987\u09b2 \u09af\u09be\u099a\u09be\u0987 \u0995\u09b0\u09c1\u09a8, \u098f\u0995\u099f\u09bf \u09a8\u09a4\u09c1\u09a8 \u0987\u09ae\u09c7\u0987\u09b2 \u09aa\u09be\u09a0\u09be\u09a8\u09cb \u09b9\u09af\u09bc\u09c7\u099b\u09c7",
+ "credentialsSignin": "\u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u09ac\u09cd\u09af\u09b0\u09cd\u09a5 \u09b9\u09af\u09bc\u09c7\u099b\u09c7\u0964 \u0986\u09aa\u09a8\u09be\u09b0 \u09a6\u09c7\u0993\u09af\u09bc\u09be \u09a4\u09a5\u09cd\u09af \u09b8\u09a0\u09bf\u0995 \u0995\u09bf\u09a8\u09be \u09af\u09be\u099a\u09be\u0987 \u0995\u09b0\u09c1\u09a8",
+ "sessionRequired": "\u098f\u0987 \u09aa\u09c3\u09b7\u09cd\u09a0\u09be \u09a6\u09c7\u0996\u09a4\u09c7 \u0985\u09a8\u09c1\u0997\u09cd\u09b0\u09b9 \u0995\u09b0\u09c7 \u09b8\u09be\u0987\u09a8 \u0987\u09a8 \u0995\u09b0\u09c1\u09a8"
+ }
+ },
+ "provider": {
+ "continue": "{{provider}} \u09a6\u09bf\u09af\u09bc\u09c7 \u099a\u09be\u09b2\u09bf\u09af\u09bc\u09c7 \u09af\u09be\u09a8"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u0986\u09aa\u09a8\u09be\u09b0 \u09ac\u09be\u09b0\u09cd\u09a4\u09be \u098f\u0996\u09be\u09a8\u09c7 \u099f\u09be\u0987\u09aa \u0995\u09b0\u09c1\u09a8...",
+ "actions": {
+ "send": "\u09ac\u09be\u09b0\u09cd\u09a4\u09be \u09aa\u09be\u09a0\u09be\u09a8",
+ "stop": "\u0995\u09be\u099c \u09ac\u09a8\u09cd\u09a7 \u0995\u09b0\u09c1\u09a8",
+ "attachFiles": "\u09ab\u09be\u0987\u09b2 \u09b8\u0982\u09af\u09c1\u0995\u09cd\u09a4 \u0995\u09b0\u09c1\u09a8"
+ }
+ },
+ "speech": {
+ "start": "\u09b0\u09c7\u0995\u09b0\u09cd\u09a1\u09bf\u0982 \u09b6\u09c1\u09b0\u09c1 \u0995\u09b0\u09c1\u09a8",
+ "stop": "\u09b0\u09c7\u0995\u09b0\u09cd\u09a1\u09bf\u0982 \u09ac\u09a8\u09cd\u09a7 \u0995\u09b0\u09c1\u09a8",
+ "connecting": "\u09b8\u0982\u09af\u09cb\u0997 \u0995\u09b0\u09be \u09b9\u099a\u09cd\u099b\u09c7"
+ },
+ "fileUpload": {
+ "dragDrop": "\u098f\u0996\u09be\u09a8\u09c7 \u09ab\u09be\u0987\u09b2 \u099f\u09c7\u09a8\u09c7 \u0986\u09a8\u09c1\u09a8",
+ "browse": "\u09ab\u09be\u0987\u09b2 \u09ac\u09cd\u09b0\u09be\u0989\u099c \u0995\u09b0\u09c1\u09a8",
+ "sizeLimit": "\u09b8\u09c0\u09ae\u09be:",
+ "errors": {
+ "failed": "\u0986\u09aa\u09b2\u09cb\u09a1 \u09ac\u09cd\u09af\u09b0\u09cd\u09a5 \u09b9\u09af\u09bc\u09c7\u099b\u09c7",
+ "cancelled": "\u0986\u09aa\u09b2\u09cb\u09a1 \u09ac\u09be\u09a4\u09bf\u09b2 \u0995\u09b0\u09be \u09b9\u09af\u09bc\u09c7\u099b\u09c7"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u09ac\u09cd\u09af\u09ac\u09b9\u09be\u09b0 \u0995\u09b0\u099b\u09c7",
+ "used": "\u09ac\u09cd\u09af\u09ac\u09b9\u09c3\u09a4"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u0995\u09cd\u09b2\u09bf\u09aa\u09ac\u09cb\u09b0\u09cd\u09a1\u09c7 \u0995\u09aa\u09bf \u0995\u09b0\u09c1\u09a8",
+ "success": "\u0995\u09aa\u09bf \u0995\u09b0\u09be \u09b9\u09af\u09bc\u09c7\u099b\u09c7!"
+ }
+ },
+ "feedback": {
+ "positive": "\u09b8\u09b9\u09be\u09af\u09bc\u0995",
+ "negative": "\u09b8\u09b9\u09be\u09af\u09bc\u0995 \u09a8\u09af\u09bc",
+ "edit": "\u09aa\u09cd\u09b0\u09a4\u09bf\u0995\u09cd\u09b0\u09bf\u09af\u09bc\u09be \u09b8\u09ae\u09cd\u09aa\u09be\u09a6\u09a8\u09be \u0995\u09b0\u09c1\u09a8",
+ "dialog": {
+ "title": "\u09ae\u09a8\u09cd\u09a4\u09ac\u09cd\u09af \u09af\u09cb\u0997 \u0995\u09b0\u09c1\u09a8",
+ "submit": "\u09aa\u09cd\u09b0\u09a4\u09bf\u0995\u09cd\u09b0\u09bf\u09af\u09bc\u09be \u099c\u09ae\u09be \u09a6\u09bf\u09a8"
+ },
+ "status": {
+ "updating": "\u09b9\u09be\u09b2\u09a8\u09be\u0997\u09be\u09a6 \u0995\u09b0\u09be \u09b9\u099a\u09cd\u099b\u09c7",
+ "updated": "\u09aa\u09cd\u09b0\u09a4\u09bf\u0995\u09cd\u09b0\u09bf\u09af\u09bc\u09be \u09b9\u09be\u09b2\u09a8\u09be\u0997\u09be\u09a6 \u0995\u09b0\u09be \u09b9\u09af\u09bc\u09c7\u099b\u09c7"
+ }
+ }
+ },
+ "history": {
+ "title": "\u09b8\u09b0\u09cd\u09ac\u09b6\u09c7\u09b7 \u0987\u09a8\u09aa\u09c1\u099f",
+ "empty": "\u0995\u09cb\u09a8\u09cb \u09a4\u09a5\u09cd\u09af \u09a8\u09c7\u0987...",
+ "show": "\u0987\u09a4\u09bf\u09b9\u09be\u09b8 \u09a6\u09c7\u0996\u09c1\u09a8"
+ },
+ "settings": {
+ "title": "\u09b8\u09c7\u099f\u09bf\u0982\u09b8 \u09aa\u09cd\u09af\u09be\u09a8\u09c7\u09b2"
+ },
+ "watermark": "\u09a6\u09cd\u09ac\u09be\u09b0\u09be \u09a8\u09bf\u09b0\u09cd\u09ae\u09bf\u09a4"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u09aa\u09c2\u09b0\u09cd\u09ac\u09ac\u09b0\u09cd\u09a4\u09c0 \u099a\u09cd\u09af\u09be\u099f",
+ "filters": {
+ "search": "\u0985\u09a8\u09c1\u09b8\u09a8\u09cd\u09a7\u09be\u09a8",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u0986\u099c",
+ "yesterday": "\u0997\u09a4\u0995\u09be\u09b2",
+ "previous7days": "\u0997\u09a4 \u09ed \u09a6\u09bf\u09a8",
+ "previous30days": "\u0997\u09a4 \u09e9\u09e6 \u09a6\u09bf\u09a8"
+ },
+ "empty": "\u0995\u09cb\u09a8\u09cb \u09a5\u09cd\u09b0\u09c7\u09a1 \u09aa\u09be\u0993\u09af\u09bc\u09be \u09af\u09be\u09af\u09bc\u09a8\u09bf",
+ "actions": {
+ "close": "\u09b8\u09be\u0987\u09a1\u09ac\u09be\u09b0 \u09ac\u09a8\u09cd\u09a7 \u0995\u09b0\u09c1\u09a8",
+ "open": "\u09b8\u09be\u0987\u09a1\u09ac\u09be\u09b0 \u0996\u09c1\u09b2\u09c1\u09a8"
+ }
+ },
+ "thread": {
+ "untitled": "\u09b6\u09bf\u09b0\u09cb\u09a8\u09be\u09ae\u09b9\u09c0\u09a8 \u0986\u09b2\u09cb\u099a\u09a8\u09be",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u09ae\u09c1\u099b\u09c7 \u09ab\u09c7\u09b2\u09be \u09a8\u09bf\u09b6\u09cd\u099a\u09bf\u09a4 \u0995\u09b0\u09c1\u09a8",
+ "description": "\u098f\u099f\u09bf \u09a5\u09cd\u09b0\u09c7\u09a1 \u098f\u09ac\u0982 \u098f\u09b0 \u09ac\u09be\u09b0\u09cd\u09a4\u09be \u0993 \u0989\u09aa\u09be\u09a6\u09be\u09a8\u0997\u09c1\u09b2\u09bf \u09ae\u09c1\u099b\u09c7 \u09ab\u09c7\u09b2\u09ac\u09c7\u0964 \u098f\u0987 \u0995\u09be\u099c\u099f\u09bf \u09aa\u09c2\u09b0\u09cd\u09ac\u09be\u09ac\u09b8\u09cd\u09a5\u09be\u09af\u09bc \u09ab\u09c7\u09b0\u09be\u09a8\u09cb \u09af\u09be\u09ac\u09c7 \u09a8\u09be",
+ "success": "\u099a\u09cd\u09af\u09be\u099f \u09ae\u09c1\u099b\u09c7 \u09ab\u09c7\u09b2\u09be \u09b9\u09af\u09bc\u09c7\u099b\u09c7",
+ "inProgress": "\u099a\u09cd\u09af\u09be\u099f \u09ae\u09c1\u099b\u09c7 \u09ab\u09c7\u09b2\u09be \u09b9\u099a\u09cd\u099b\u09c7"
+ },
+ "rename": {
+ "title": "\u09a5\u09cd\u09b0\u09c7\u09a1\u09c7\u09b0 \u09a8\u09be\u09ae \u09aa\u09b0\u09bf\u09ac\u09b0\u09cd\u09a4\u09a8 \u0995\u09b0\u09c1\u09a8",
+ "description": "\u098f\u0987 \u09a5\u09cd\u09b0\u09c7\u09a1\u09c7\u09b0 \u099c\u09a8\u09cd\u09af \u098f\u0995\u099f\u09bf \u09a8\u09a4\u09c1\u09a8 \u09a8\u09be\u09ae \u09a6\u09bf\u09a8",
+ "form": {
+ "name": {
+ "label": "\u09a8\u09be\u09ae",
+ "placeholder": "\u09a8\u09a4\u09c1\u09a8 \u09a8\u09be\u09ae \u09b2\u09bf\u0996\u09c1\u09a8"
+ }
+ },
+ "success": "\u09a5\u09cd\u09b0\u09c7\u09a1\u09c7\u09b0 \u09a8\u09be\u09ae \u09aa\u09b0\u09bf\u09ac\u09b0\u09cd\u09a4\u09a8 \u0995\u09b0\u09be \u09b9\u09af\u09bc\u09c7\u099b\u09c7!",
+ "inProgress": "\u09a5\u09cd\u09b0\u09c7\u09a1\u09c7\u09b0 \u09a8\u09be\u09ae \u09aa\u09b0\u09bf\u09ac\u09b0\u09cd\u09a4\u09a8 \u0995\u09b0\u09be \u09b9\u099a\u09cd\u099b\u09c7"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u099a\u09cd\u09af\u09be\u099f",
+ "readme": "\u09b0\u09bf\u09a1\u09ae\u09bf",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u09a8\u09a4\u09c1\u09a8 \u099a\u09cd\u09af\u09be\u099f",
+ "dialog": {
+ "title": "\u09a8\u09a4\u09c1\u09a8 \u099a\u09cd\u09af\u09be\u099f \u09a4\u09c8\u09b0\u09bf \u0995\u09b0\u09c1\u09a8",
+ "description": "\u098f\u099f\u09bf \u0986\u09aa\u09a8\u09be\u09b0 \u09ac\u09b0\u09cd\u09a4\u09ae\u09be\u09a8 \u099a\u09cd\u09af\u09be\u099f \u0987\u09a4\u09bf\u09b9\u09be\u09b8 \u09ae\u09c1\u099b\u09c7 \u09ab\u09c7\u09b2\u09ac\u09c7\u0964 \u0986\u09aa\u09a8\u09bf \u0995\u09bf \u099a\u09be\u09b2\u09bf\u09af\u09bc\u09c7 \u09af\u09c7\u09a4\u09c7 \u099a\u09be\u09a8?",
+ "tooltip": "\u09a8\u09a4\u09c1\u09a8 \u099a\u09cd\u09af\u09be\u099f"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u09b8\u09c7\u099f\u09bf\u0982\u09b8",
+ "settingsKey": "S",
+ "apiKeys": "\u098f\u09aa\u09bf\u0986\u0987 \u0995\u09c0",
+ "logout": "\u09b2\u0997\u0986\u0989\u099f"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u09aa\u09cd\u09b0\u09af\u09bc\u09cb\u099c\u09a8\u09c0\u09af\u09bc \u098f\u09aa\u09bf\u0986\u0987 \u0995\u09c0",
+ "description": "\u098f\u0987 \u0985\u09cd\u09af\u09be\u09aa\u09cd\u09b2\u09bf\u0995\u09c7\u09b6\u09a8 \u09ac\u09cd\u09af\u09ac\u09b9\u09be\u09b0 \u0995\u09b0\u09a4\u09c7 \u09a8\u09bf\u09ae\u09cd\u09a8\u09b2\u09bf\u0996\u09bf\u09a4 \u098f\u09aa\u09bf\u0986\u0987 \u0995\u09c0 \u09aa\u09cd\u09b0\u09af\u09bc\u09cb\u099c\u09a8\u0964 \u0995\u09c0\u0997\u09c1\u09b2\u09bf \u0986\u09aa\u09a8\u09be\u09b0 \u09a1\u09bf\u09ad\u09be\u0987\u09b8\u09c7\u09b0 \u09b2\u09cb\u0995\u09be\u09b2 \u09b8\u09cd\u099f\u09cb\u09b0\u09c7\u099c\u09c7 \u09b8\u0982\u09b0\u0995\u09cd\u09b7\u09bf\u09a4 \u09a5\u09be\u0995\u09c7\u0964",
+ "success": {
+ "saved": "\u09b8\u09ab\u09b2\u09ad\u09be\u09ac\u09c7 \u09b8\u0982\u09b0\u0995\u09cd\u09b7\u09bf\u09a4 \u09b9\u09af\u09bc\u09c7\u099b\u09c7"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/en-US.json b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/en-US.json
new file mode 100644
index 00000000..87b8d747
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/en-US.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "Cancel",
+ "confirm": "Confirm",
+ "continue": "Continue",
+ "goBack": "Go Back",
+ "reset": "Reset",
+ "submit": "Submit"
+ },
+ "status": {
+ "loading": "Loading...",
+ "error": {
+ "default": "An error occurred",
+ "serverConnection": "Could not reach the server"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "Login to access the app",
+ "form": {
+ "email": {
+ "label": "Email address",
+ "required": "email is a required field"
+ },
+ "password": {
+ "label": "Password",
+ "required": "password is a required field"
+ },
+ "actions": {
+ "signin": "Sign In"
+ },
+ "alternativeText": {
+ "or": "OR"
+ }
+ },
+ "errors": {
+ "default": "Unable to sign in",
+ "signin": "Try signing in with a different account",
+ "oauthSignin": "Try signing in with a different account",
+ "redirectUriMismatch": "The redirect URI is not matching the oauth app configuration",
+ "oauthCallback": "Try signing in with a different account",
+ "oauthCreateAccount": "Try signing in with a different account",
+ "emailCreateAccount": "Try signing in with a different account",
+ "callback": "Try signing in with a different account",
+ "oauthAccountNotLinked": "To confirm your identity, sign in with the same account you used originally",
+ "emailSignin": "The e-mail could not be sent",
+ "emailVerify": "Please verify your email, a new email has been sent",
+ "credentialsSignin": "Sign in failed. Check the details you provided are correct",
+ "sessionRequired": "Please sign in to access this page"
+ }
+ },
+ "provider": {
+ "continue": "Continue with {{provider}}"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "Type your message here...",
+ "actions": {
+ "send": "Send message",
+ "stop": "Stop Task",
+ "attachFiles": "Attach files"
+ }
+ },
+ "speech": {
+ "start": "Start recording",
+ "stop": "Stop recording",
+ "connecting": "Connecting"
+ },
+ "fileUpload": {
+ "dragDrop": "Drag and drop files here",
+ "browse": "Browse Files",
+ "sizeLimit": "Limit:",
+ "errors": {
+ "failed": "Failed to upload",
+ "cancelled": "Cancelled upload of"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "Using",
+ "used": "Used"
+ },
+ "actions": {
+ "copy": {
+ "button": "Copy to clipboard",
+ "success": "Copied!"
+ }
+ },
+ "feedback": {
+ "positive": "Helpful",
+ "negative": "Not helpful",
+ "edit": "Edit feedback",
+ "dialog": {
+ "title": "Add a comment",
+ "submit": "Submit feedback"
+ },
+ "status": {
+ "updating": "Updating",
+ "updated": "Feedback updated"
+ }
+ }
+ },
+ "history": {
+ "title": "Last Inputs",
+ "empty": "Such empty...",
+ "show": "Show history"
+ },
+ "settings": {
+ "title": "Settings panel"
+ },
+ "watermark": "Built with"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "Past Chats",
+ "filters": {
+ "search": "Search",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "Today",
+ "yesterday": "Yesterday",
+ "previous7days": "Previous 7 days",
+ "previous30days": "Previous 30 days"
+ },
+ "empty": "No threads found",
+ "actions": {
+ "close": "Close sidebar",
+ "open": "Open sidebar"
+ }
+ },
+ "thread": {
+ "untitled": "Untitled Conversation",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "Confirm deletion",
+ "description": "This will delete the thread as well as its messages and elements. This action cannot be undone",
+ "success": "Chat deleted",
+ "inProgress": "Deleting chat"
+ },
+ "rename": {
+ "title": "Rename Thread",
+ "description": "Enter a new name for this thread",
+ "form": {
+ "name": {
+ "label": "Name",
+ "placeholder": "Enter new name"
+ }
+ },
+ "success": "Thread renamed!",
+ "inProgress": "Renaming thread"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "Chat",
+ "readme": "Readme",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "New Chat",
+ "dialog": {
+ "title": "Create New Chat",
+ "description": "This will clear your current chat history. Are you sure you want to continue?",
+ "tooltip": "New Chat"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "Settings",
+ "settingsKey": "S",
+ "apiKeys": "API Keys",
+ "logout": "Logout"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "Required API Keys",
+ "description": "To use this app, the following API keys are required. The keys are stored on your device's local storage.",
+ "success": {
+ "saved": "Saved successfully"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/gu.json b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/gu.json
new file mode 100644
index 00000000..6292b953
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/gu.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u0ab0\u0aa6 \u0a95\u0ab0\u0acb",
+ "confirm": "\u0aaa\u0ac1\u0ab7\u0acd\u0a9f\u0abf \u0a95\u0ab0\u0acb",
+ "continue": "\u0a9a\u0abe\u0ab2\u0ac1 \u0ab0\u0abe\u0a96\u0acb",
+ "goBack": "\u0aaa\u0abe\u0a9b\u0abe \u0a9c\u0abe\u0a93",
+ "reset": "\u0ab0\u0ac0\u0ab8\u0ac7\u0a9f \u0a95\u0ab0\u0acb",
+ "submit": "\u0ab8\u0aac\u0aae\u0abf\u0a9f \u0a95\u0ab0\u0acb"
+ },
+ "status": {
+ "loading": "\u0ab2\u0acb\u0aa1 \u0aa5\u0a88 \u0ab0\u0ab9\u0acd\u0aaf\u0ac1\u0a82 \u0a9b\u0ac7...",
+ "error": {
+ "default": "\u0a8f\u0a95 \u0aad\u0ac2\u0ab2 \u0aa5\u0a88",
+ "serverConnection": "\u0ab8\u0ab0\u0acd\u0ab5\u0ab0 \u0ab8\u0ac1\u0aa7\u0ac0 \u0aaa\u0ab9\u0acb\u0a82\u0a9a\u0ac0 \u0ab6\u0a95\u0abe\u0aaf\u0ac1\u0a82 \u0aa8\u0aa5\u0ac0"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u0a8f\u0aaa\u0acd\u0ab2\u0abf\u0a95\u0ac7\u0ab6\u0aa8 \u0a8d\u0a95\u0acd\u0ab8\u0ac7\u0ab8 \u0a95\u0ab0\u0ab5\u0abe \u0aae\u0abe\u0a9f\u0ac7 \u0ab2\u0ac9\u0a97\u0abf\u0aa8 \u0a95\u0ab0\u0acb",
+ "form": {
+ "email": {
+ "label": "\u0a88\u0aae\u0ac7\u0ab2 \u0a8f\u0aa1\u0acd\u0ab0\u0ac7\u0ab8",
+ "required": "\u0a88\u0aae\u0ac7\u0ab2 \u0a86\u0ab5\u0ab6\u0acd\u0aaf\u0a95 \u0a9b\u0ac7"
+ },
+ "password": {
+ "label": "\u0aaa\u0abe\u0ab8\u0ab5\u0ab0\u0acd\u0aa1",
+ "required": "\u0aaa\u0abe\u0ab8\u0ab5\u0ab0\u0acd\u0aa1 \u0a86\u0ab5\u0ab6\u0acd\u0aaf\u0a95 \u0a9b\u0ac7"
+ },
+ "actions": {
+ "signin": "\u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0acb"
+ },
+ "alternativeText": {
+ "or": "\u0a85\u0aa5\u0ab5\u0abe"
+ }
+ },
+ "errors": {
+ "default": "\u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0ac0 \u0ab6\u0a95\u0abe\u0aaf\u0ac1\u0a82 \u0aa8\u0aa5\u0ac0",
+ "signin": "\u0a85\u0ab2\u0a97 \u0a8f\u0a95\u0abe\u0a89\u0aa8\u0acd\u0a9f\u0aa5\u0ac0 \u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0ab5\u0abe\u0aa8\u0acb \u0aaa\u0acd\u0ab0\u0aaf\u0abe\u0ab8 \u0a95\u0ab0\u0acb",
+ "oauthSignin": "\u0a85\u0ab2\u0a97 \u0a8f\u0a95\u0abe\u0a89\u0aa8\u0acd\u0a9f\u0aa5\u0ac0 \u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0ab5\u0abe\u0aa8\u0acb \u0aaa\u0acd\u0ab0\u0aaf\u0abe\u0ab8 \u0a95\u0ab0\u0acb",
+ "redirectUriMismatch": "\u0ab0\u0ac0\u0aa1\u0abe\u0aaf\u0ab0\u0ac7\u0a95\u0acd\u0a9f URI oauth \u0a8d\u0aaa \u0a95\u0aa8\u0acd\u0aab\u0abf\u0a97\u0ab0\u0ac7\u0ab6\u0aa8 \u0ab8\u0abe\u0aa5\u0ac7 \u0aae\u0ac7\u0ab3 \u0a96\u0abe\u0aa4\u0acb \u0aa8\u0aa5\u0ac0",
+ "oauthCallback": "\u0a85\u0ab2\u0a97 \u0a8f\u0a95\u0abe\u0a89\u0aa8\u0acd\u0a9f\u0aa5\u0ac0 \u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0ab5\u0abe\u0aa8\u0acb \u0aaa\u0acd\u0ab0\u0aaf\u0abe\u0ab8 \u0a95\u0ab0\u0acb",
+ "oauthCreateAccount": "\u0a85\u0ab2\u0a97 \u0a8f\u0a95\u0abe\u0a89\u0aa8\u0acd\u0a9f\u0aa5\u0ac0 \u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0ab5\u0abe\u0aa8\u0acb \u0aaa\u0acd\u0ab0\u0aaf\u0abe\u0ab8 \u0a95\u0ab0\u0acb",
+ "emailCreateAccount": "\u0a85\u0ab2\u0a97 \u0a8f\u0a95\u0abe\u0a89\u0aa8\u0acd\u0a9f\u0aa5\u0ac0 \u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0ab5\u0abe\u0aa8\u0acb \u0aaa\u0acd\u0ab0\u0aaf\u0abe\u0ab8 \u0a95\u0ab0\u0acb",
+ "callback": "\u0a85\u0ab2\u0a97 \u0a8f\u0a95\u0abe\u0a89\u0aa8\u0acd\u0a9f\u0aa5\u0ac0 \u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0ab5\u0abe\u0aa8\u0acb \u0aaa\u0acd\u0ab0\u0aaf\u0abe\u0ab8 \u0a95\u0ab0\u0acb",
+ "oauthAccountNotLinked": "\u0aa4\u0aae\u0abe\u0ab0\u0ac0 \u0a93\u0ab3\u0a96\u0aa8\u0ac0 \u0aaa\u0ac1\u0ab7\u0acd\u0a9f\u0abf \u0a95\u0ab0\u0ab5\u0abe \u0aae\u0abe\u0a9f\u0ac7, \u0aae\u0ac2\u0ab3 \u0ab0\u0ac2\u0aaa\u0ac7 \u0ab5\u0abe\u0aaa\u0ab0\u0ac7\u0ab2\u0abe \u0a8f\u0a95\u0abe\u0a89\u0aa8\u0acd\u0a9f\u0aa5\u0ac0 \u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0acb",
+ "emailSignin": "\u0a88\u0aae\u0ac7\u0ab2 \u0aae\u0acb\u0a95\u0ab2\u0ac0 \u0ab6\u0a95\u0abe\u0aaf\u0acb \u0aa8\u0aa5\u0ac0",
+ "emailVerify": "\u0a95\u0ac3\u0aaa\u0abe \u0a95\u0ab0\u0ac0 \u0aa4\u0aae\u0abe\u0ab0\u0acb \u0a88\u0aae\u0ac7\u0ab2 \u0a9a\u0a95\u0abe\u0ab8\u0acb, \u0aa8\u0ab5\u0acb \u0a88\u0aae\u0ac7\u0ab2 \u0aae\u0acb\u0a95\u0ab2\u0ab5\u0abe\u0aae\u0abe\u0a82 \u0a86\u0ab5\u0acd\u0aaf\u0acb \u0a9b\u0ac7",
+ "credentialsSignin": "\u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0aa8\u0abf\u0ab7\u0acd\u0aab\u0ab3. \u0a86\u0aaa\u0ac7\u0ab2\u0ac0 \u0ab5\u0abf\u0a97\u0aa4\u0acb \u0ab8\u0abe\u0a9a\u0ac0 \u0a9b\u0ac7 \u0a95\u0ac7 \u0aa8\u0ab9\u0ac0\u0a82 \u0aa4\u0ac7 \u0a9a\u0a95\u0abe\u0ab8\u0acb",
+ "sessionRequired": "\u0a86 \u0aaa\u0ac7\u0a9c\u0aa8\u0ac7 \u0a8d\u0a95\u0acd\u0ab8\u0ac7\u0ab8 \u0a95\u0ab0\u0ab5\u0abe \u0aae\u0abe\u0a9f\u0ac7 \u0a95\u0ac3\u0aaa\u0abe \u0a95\u0ab0\u0ac0 \u0ab8\u0abe\u0a87\u0aa8 \u0a87\u0aa8 \u0a95\u0ab0\u0acb"
+ }
+ },
+ "provider": {
+ "continue": "{{provider}} \u0ab8\u0abe\u0aa5\u0ac7 \u0a9a\u0abe\u0ab2\u0ac1 \u0ab0\u0abe\u0a96\u0acb"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u0a85\u0ab9\u0ac0\u0a82 \u0aa4\u0aae\u0abe\u0ab0\u0acb \u0ab8\u0a82\u0aa6\u0ac7\u0ab6 \u0ab2\u0a96\u0acb...",
+ "actions": {
+ "send": "\u0ab8\u0a82\u0aa6\u0ac7\u0ab6 \u0aae\u0acb\u0a95\u0ab2\u0acb",
+ "stop": "\u0a95\u0abe\u0ab0\u0acd\u0aaf \u0ab0\u0acb\u0a95\u0acb",
+ "attachFiles": "\u0aab\u0abe\u0a87\u0ab2\u0acd\u0ab8 \u0a9c\u0acb\u0aa1\u0acb"
+ }
+ },
+ "speech": {
+ "start": "\u0ab0\u0ac7\u0a95\u0acb\u0ab0\u0acd\u0aa1\u0abf\u0a82\u0a97 \u0ab6\u0ab0\u0ac2 \u0a95\u0ab0\u0acb",
+ "stop": "\u0ab0\u0ac7\u0a95\u0acb\u0ab0\u0acd\u0aa1\u0abf\u0a82\u0a97 \u0aac\u0a82\u0aa7 \u0a95\u0ab0\u0acb",
+ "connecting": "\u0a95\u0aa8\u0ac7\u0a95\u0acd\u0a9f \u0aa5\u0a88 \u0ab0\u0ab9\u0acd\u0aaf\u0ac1\u0a82 \u0a9b\u0ac7"
+ },
+ "fileUpload": {
+ "dragDrop": "\u0a85\u0ab9\u0ac0\u0a82 \u0aab\u0abe\u0a87\u0ab2\u0acd\u0ab8 \u0a96\u0ac7\u0a82\u0a9a\u0acb \u0a85\u0aa8\u0ac7 \u0a9b\u0acb\u0aa1\u0acb",
+ "browse": "\u0aab\u0abe\u0a87\u0ab2\u0acd\u0ab8 \u0aac\u0acd\u0ab0\u0abe\u0a89\u0a9d \u0a95\u0ab0\u0acb",
+ "sizeLimit": "\u0aae\u0ab0\u0acd\u0aaf\u0abe\u0aa6\u0abe:",
+ "errors": {
+ "failed": "\u0a85\u0aaa\u0ab2\u0acb\u0aa1 \u0a95\u0ab0\u0ab5\u0abe\u0aae\u0abe\u0a82 \u0aa8\u0abf\u0ab7\u0acd\u0aab\u0ab3",
+ "cancelled": "\u0a85\u0aaa\u0ab2\u0acb\u0aa1 \u0ab0\u0aa6 \u0a95\u0ab0\u0acd\u0aaf\u0ac1\u0a82"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u0ab5\u0abe\u0aaa\u0ab0\u0ac0 \u0ab0\u0ab9\u0acd\u0aaf\u0abe \u0a9b\u0ac7",
+ "used": "\u0ab5\u0aaa\u0ab0\u0abe\u0aaf\u0ac7\u0ab2"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u0a95\u0acd\u0ab2\u0abf\u0aaa\u0aac\u0acb\u0ab0\u0acd\u0aa1 \u0aaa\u0ab0 \u0a95\u0ac9\u0aaa\u0abf \u0a95\u0ab0\u0acb",
+ "success": "\u0a95\u0ac9\u0aaa\u0abf \u0aa5\u0aaf\u0ac1\u0a82!"
+ }
+ },
+ "feedback": {
+ "positive": "\u0a89\u0aaa\u0aaf\u0acb\u0a97\u0ac0",
+ "negative": "\u0aac\u0abf\u0aa8\u0a89\u0aaa\u0aaf\u0acb\u0a97\u0ac0",
+ "edit": "\u0aaa\u0acd\u0ab0\u0aa4\u0abf\u0ab8\u0abe\u0aa6 \u0ab8\u0a82\u0aaa\u0abe\u0aa6\u0abf\u0aa4 \u0a95\u0ab0\u0acb",
+ "dialog": {
+ "title": "\u0a9f\u0abf\u0aaa\u0acd\u0aaa\u0aa3\u0ac0 \u0a89\u0aae\u0ac7\u0ab0\u0acb",
+ "submit": "\u0aaa\u0acd\u0ab0\u0aa4\u0abf\u0ab8\u0abe\u0aa6 \u0ab8\u0aac\u0aae\u0abf\u0a9f \u0a95\u0ab0\u0acb"
+ },
+ "status": {
+ "updating": "\u0a85\u0aaa\u0aa1\u0ac7\u0a9f \u0aa5\u0a88 \u0ab0\u0ab9\u0acd\u0aaf\u0ac1\u0a82 \u0a9b\u0ac7",
+ "updated": "\u0aaa\u0acd\u0ab0\u0aa4\u0abf\u0ab8\u0abe\u0aa6 \u0a85\u0aaa\u0aa1\u0ac7\u0a9f \u0aa5\u0aaf\u0acb"
+ }
+ }
+ },
+ "history": {
+ "title": "\u0a9b\u0ac7\u0ab2\u0acd\u0ab2\u0abe \u0a87\u0aa8\u0aaa\u0ac1\u0a9f\u0acd\u0ab8",
+ "empty": "\u0a96\u0abe\u0ab2\u0ac0 \u0a9b\u0ac7...",
+ "show": "\u0a87\u0aa4\u0abf\u0ab9\u0abe\u0ab8 \u0aac\u0aa4\u0abe\u0ab5\u0acb"
+ },
+ "settings": {
+ "title": "\u0ab8\u0ac7\u0a9f\u0abf\u0a82\u0a97\u0acd\u0ab8 \u0aaa\u0ac7\u0aa8\u0ab2"
+ },
+ "watermark": "\u0ab8\u0abe\u0aa5\u0ac7 \u0aac\u0aa8\u0abe\u0ab5\u0ac7\u0ab2"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u0aaa\u0abe\u0a9b\u0ab2\u0ac0 \u0a9a\u0ac7\u0a9f\u0acd\u0ab8",
+ "filters": {
+ "search": "\u0ab6\u0acb\u0aa7\u0acb",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u0a86\u0a9c\u0ac7",
+ "yesterday": "\u0a97\u0a88\u0a95\u0abe\u0ab2\u0ac7",
+ "previous7days": "\u0aaa\u0abe\u0a9b\u0ab2\u0abe 7 \u0aa6\u0abf\u0ab5\u0ab8",
+ "previous30days": "\u0aaa\u0abe\u0a9b\u0ab2\u0abe 30 \u0aa6\u0abf\u0ab5\u0ab8"
+ },
+ "empty": "\u0a95\u0acb\u0a88 \u0aa5\u0acd\u0ab0\u0ac7\u0aa1\u0acd\u0ab8 \u0aae\u0ab3\u0acd\u0aaf\u0abe \u0aa8\u0aa5\u0ac0",
+ "actions": {
+ "close": "\u0ab8\u0abe\u0a87\u0aa1\u0aac\u0abe\u0ab0 \u0aac\u0a82\u0aa7 \u0a95\u0ab0\u0acb",
+ "open": "\u0ab8\u0abe\u0a87\u0aa1\u0aac\u0abe\u0ab0 \u0a96\u0acb\u0ab2\u0acb"
+ }
+ },
+ "thread": {
+ "untitled": "\u0ab6\u0ac0\u0ab0\u0acd\u0ab7\u0a95 \u0ab5\u0a97\u0ab0\u0aa8\u0ac0 \u0ab5\u0abe\u0aa4\u0a9a\u0ac0\u0aa4",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u0a95\u0abe\u0aa2\u0ac0 \u0aa8\u0abe\u0a96\u0ab5\u0abe\u0aa8\u0ac0 \u0aaa\u0ac1\u0ab7\u0acd\u0a9f\u0abf \u0a95\u0ab0\u0acb",
+ "description": "\u0a86 \u0aa5\u0acd\u0ab0\u0ac7\u0aa1 \u0a85\u0aa8\u0ac7 \u0aa4\u0ac7\u0aa8\u0abe \u0ab8\u0a82\u0aa6\u0ac7\u0ab6\u0abe\u0a93 \u0a85\u0aa8\u0ac7 \u0aa4\u0aa4\u0acd\u0ab5\u0acb\u0aa8\u0ac7 \u0a95\u0abe\u0aa2\u0ac0 \u0aa8\u0abe\u0a96\u0ab6\u0ac7. \u0a86 \u0a95\u0acd\u0ab0\u0abf\u0aaf\u0abe \u0aaa\u0abe\u0a9b\u0ac0 \u0aab\u0ac7\u0ab0\u0ab5\u0ac0 \u0ab6\u0a95\u0abe\u0ab6\u0ac7 \u0aa8\u0ab9\u0ac0\u0a82",
+ "success": "\u0a9a\u0ac7\u0a9f \u0a95\u0abe\u0aa2\u0ac0 \u0aa8\u0abe\u0a96\u0ac0",
+ "inProgress": "\u0a9a\u0ac7\u0a9f \u0a95\u0abe\u0aa2\u0ac0 \u0aa8\u0abe\u0a96\u0ac0 \u0ab0\u0ab9\u0acd\u0aaf\u0abe \u0a9b\u0ac0\u0a8f"
+ },
+ "rename": {
+ "title": "\u0aa5\u0acd\u0ab0\u0ac7\u0aa1\u0aa8\u0ac1\u0a82 \u0aa8\u0abe\u0aae \u0aac\u0aa6\u0ab2\u0acb",
+ "description": "\u0a86 \u0aa5\u0acd\u0ab0\u0ac7\u0aa1 \u0aae\u0abe\u0a9f\u0ac7 \u0aa8\u0ab5\u0ac1\u0a82 \u0aa8\u0abe\u0aae \u0aa6\u0abe\u0a96\u0ab2 \u0a95\u0ab0\u0acb",
+ "form": {
+ "name": {
+ "label": "\u0aa8\u0abe\u0aae",
+ "placeholder": "\u0aa8\u0ab5\u0ac1\u0a82 \u0aa8\u0abe\u0aae \u0aa6\u0abe\u0a96\u0ab2 \u0a95\u0ab0\u0acb"
+ }
+ },
+ "success": "\u0aa5\u0acd\u0ab0\u0ac7\u0aa1\u0aa8\u0ac1\u0a82 \u0aa8\u0abe\u0aae \u0aac\u0aa6\u0ab2\u0abe\u0aaf\u0ac1\u0a82!",
+ "inProgress": "\u0aa5\u0acd\u0ab0\u0ac7\u0aa1\u0aa8\u0ac1\u0a82 \u0aa8\u0abe\u0aae \u0aac\u0aa6\u0ab2\u0ac0 \u0ab0\u0ab9\u0acd\u0aaf\u0abe \u0a9b\u0ac0\u0a8f"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u0a9a\u0ac7\u0a9f",
+ "readme": "\u0ab5\u0abe\u0a82\u0a9a\u0acb",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u0aa8\u0ab5\u0ac0 \u0a9a\u0ac7\u0a9f",
+ "dialog": {
+ "title": "\u0aa8\u0ab5\u0ac0 \u0a9a\u0ac7\u0a9f \u0aac\u0aa8\u0abe\u0ab5\u0acb",
+ "description": "\u0a86 \u0aa4\u0aae\u0abe\u0ab0\u0acb \u0ab5\u0ab0\u0acd\u0aa4\u0aae\u0abe\u0aa8 \u0a9a\u0ac7\u0a9f \u0a87\u0aa4\u0abf\u0ab9\u0abe\u0ab8 \u0ab8\u0abe\u0aab \u0a95\u0ab0\u0ab6\u0ac7. \u0ab6\u0ac1\u0a82 \u0aa4\u0aae\u0ac7 \u0a9a\u0abe\u0ab2\u0ac1 \u0ab0\u0abe\u0a96\u0ab5\u0abe \u0aae\u0abe\u0a82\u0a97\u0acb \u0a9b\u0acb?",
+ "tooltip": "\u0aa8\u0ab5\u0ac0 \u0a9a\u0ac7\u0a9f"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u0ab8\u0ac7\u0a9f\u0abf\u0a82\u0a97\u0acd\u0ab8",
+ "settingsKey": "S",
+ "apiKeys": "API \u0a95\u0ac0",
+ "logout": "\u0ab2\u0ac9\u0a97\u0a86\u0a89\u0a9f"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u0a9c\u0ab0\u0ac2\u0ab0\u0ac0 API \u0a95\u0ac0",
+ "description": "\u0a86 \u0a8f\u0aaa\u0acd\u0ab2\u0abf\u0a95\u0ac7\u0ab6\u0aa8 \u0ab5\u0abe\u0aaa\u0ab0\u0ab5\u0abe \u0aae\u0abe\u0a9f\u0ac7, \u0aa8\u0ac0\u0a9a\u0ac7\u0aa8\u0ac0 API \u0a95\u0ac0 \u0a9c\u0ab0\u0ac2\u0ab0\u0ac0 \u0a9b\u0ac7. \u0a95\u0ac0 \u0aa4\u0aae\u0abe\u0ab0\u0abe \u0aa1\u0abf\u0ab5\u0abe\u0a87\u0ab8\u0aa8\u0abe \u0ab2\u0acb\u0a95\u0ab2 \u0ab8\u0acd\u0a9f\u0acb\u0ab0\u0ac7\u0a9c\u0aae\u0abe\u0a82 \u0ab8\u0a82\u0a97\u0acd\u0ab0\u0ab9\u0abf\u0aa4 \u0aa5\u0ab6\u0ac7.",
+ "success": {
+ "saved": "\u0ab8\u0aab\u0ab3\u0aa4\u0abe\u0aaa\u0ac2\u0ab0\u0acd\u0ab5\u0a95 \u0ab8\u0abe\u0a9a\u0ab5\u0acd\u0aaf\u0ac1\u0a82"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/he-IL.json b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/he-IL.json
new file mode 100644
index 00000000..fc076784
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/he-IL.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u05d1\u05d9\u05d8\u05d5\u05dc",
+ "confirm": "\u05d0\u05d9\u05e9\u05d5\u05e8",
+ "continue": "\u05d4\u05de\u05e9\u05da",
+ "goBack": "\u05d7\u05d6\u05d5\u05e8",
+ "reset": "\u05d0\u05d9\u05e4\u05d5\u05e1",
+ "submit": "\u05e9\u05dc\u05d7"
+ },
+ "status": {
+ "loading": "\u05d8\u05d5\u05e2\u05df...",
+ "error": {
+ "default": "\u05d0\u05d9\u05e8\u05e2\u05d4 \u05e9\u05d2\u05d9\u05d0\u05d4",
+ "serverConnection": "\u05dc\u05d0 \u05e0\u05d9\u05ea\u05df \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8 \u05dc\u05e9\u05e8\u05ea"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u05d4\u05ea\u05d7\u05d1\u05e8 \u05db\u05d3\u05d9 \u05dc\u05d2\u05e9\u05ea \u05dc\u05d0\u05e4\u05dc\u05d9\u05e7\u05e6\u05d9\u05d4",
+ "form": {
+ "email": {
+ "label": "\u05db\u05ea\u05d5\u05d1\u05ea \u05d0\u05d9\u05de\u05d9\u05d9\u05dc",
+ "required": "\u05e9\u05d3\u05d4 \u05d4\u05d0\u05d9\u05de\u05d9\u05d9\u05dc \u05d4\u05d5\u05d0 \u05e9\u05d3\u05d4 \u05d7\u05d5\u05d1\u05d4"
+ },
+ "password": {
+ "label": "\u05e1\u05d9\u05e1\u05de\u05d4",
+ "required": "\u05e9\u05d3\u05d4 \u05d4\u05e1\u05d9\u05e1\u05de\u05d4 \u05d4\u05d5\u05d0 \u05e9\u05d3\u05d4 \u05d7\u05d5\u05d1\u05d4"
+ },
+ "actions": {
+ "signin": "\u05d4\u05ea\u05d7\u05d1\u05e8"
+ },
+ "alternativeText": {
+ "or": "\u05d0\u05d5"
+ }
+ },
+ "errors": {
+ "default": "\u05dc\u05d0 \u05e0\u05d9\u05ea\u05df \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8",
+ "signin": "\u05e0\u05e1\u05d4 \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8 \u05e2\u05dd \u05d7\u05e9\u05d1\u05d5\u05df \u05d0\u05d7\u05e8",
+ "oauthSignin": "\u05e0\u05e1\u05d4 \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8 \u05e2\u05dd \u05d7\u05e9\u05d1\u05d5\u05df \u05d0\u05d7\u05e8",
+ "redirectUriMismatch": "\u05db\u05ea\u05d5\u05d1\u05ea \u05d4\u05d4\u05e4\u05e0\u05d9\u05d4 \u05d0\u05d9\u05e0\u05d4 \u05ea\u05d5\u05d0\u05de\u05ea \u05d0\u05ea \u05ea\u05e6\u05d5\u05e8\u05ea \u05d0\u05e4\u05dc\u05d9\u05e7\u05e6\u05d9\u05d9\u05ea OAuth",
+ "oauthCallback": "\u05e0\u05e1\u05d4 \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8 \u05e2\u05dd \u05d7\u05e9\u05d1\u05d5\u05df \u05d0\u05d7\u05e8",
+ "oauthCreateAccount": "\u05e0\u05e1\u05d4 \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8 \u05e2\u05dd \u05d7\u05e9\u05d1\u05d5\u05df \u05d0\u05d7\u05e8",
+ "emailCreateAccount": "\u05e0\u05e1\u05d4 \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8 \u05e2\u05dd \u05d7\u05e9\u05d1\u05d5\u05df \u05d0\u05d7\u05e8",
+ "callback": "\u05e0\u05e1\u05d4 \u05dc\u05d4\u05ea\u05d7\u05d1\u05e8 \u05e2\u05dd \u05d7\u05e9\u05d1\u05d5\u05df \u05d0\u05d7\u05e8",
+ "oauthAccountNotLinked": "\u05db\u05d3\u05d9 \u05dc\u05d0\u05de\u05ea \u05d0\u05ea \u05d6\u05d4\u05d5\u05ea\u05da, \u05d4\u05ea\u05d7\u05d1\u05e8 \u05e2\u05dd \u05d0\u05d5\u05ea\u05d5 \u05d7\u05e9\u05d1\u05d5\u05df \u05d1\u05d5 \u05d4\u05e9\u05ea\u05de\u05e9\u05ea \u05d1\u05de\u05e7\u05d5\u05e8",
+ "emailSignin": "\u05dc\u05d0 \u05e0\u05d9\u05ea\u05df \u05d4\u05d9\u05d4 \u05dc\u05e9\u05dc\u05d5\u05d7 \u05d0\u05ea \u05d4\u05d0\u05d9\u05de\u05d9\u05d9\u05dc",
+ "emailVerify": "\u05d0\u05e0\u05d0 \u05d0\u05de\u05ea \u05d0\u05ea \u05d4\u05d0\u05d9\u05de\u05d9\u05d9\u05dc \u05e9\u05dc\u05da, \u05e0\u05e9\u05dc\u05d7 \u05d0\u05d9\u05de\u05d9\u05d9\u05dc \u05d7\u05d3\u05e9",
+ "credentialsSignin": "\u05d4\u05d4\u05ea\u05d7\u05d1\u05e8\u05d5\u05ea \u05e0\u05db\u05e9\u05dc\u05d4. \u05d1\u05d3\u05d5\u05e7 \u05e9\u05d4\u05e4\u05e8\u05d8\u05d9\u05dd \u05e9\u05d4\u05d6\u05e0\u05ea \u05e0\u05db\u05d5\u05e0\u05d9\u05dd",
+ "sessionRequired": "\u05d0\u05e0\u05d0 \u05d4\u05ea\u05d7\u05d1\u05e8 \u05db\u05d3\u05d9 \u05dc\u05d2\u05e9\u05ea \u05dc\u05d3\u05e3 \u05d6\u05d4"
+ }
+ },
+ "provider": {
+ "continue": "\u05d4\u05de\u05e9\u05da \u05e2\u05dd {{provider}}"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u05d4\u05e7\u05dc\u05d3 \u05d0\u05ea \u05d4\u05d4\u05d5\u05d3\u05e2\u05d4 \u05e9\u05dc\u05da \u05db\u05d0\u05df...",
+ "actions": {
+ "send": "\u05e9\u05dc\u05d7 \u05d4\u05d5\u05d3\u05e2\u05d4",
+ "stop": "\u05e2\u05e6\u05d5\u05e8 \u05de\u05e9\u05d9\u05de\u05d4",
+ "attachFiles": "\u05e6\u05e8\u05e3 \u05e7\u05d1\u05e6\u05d9\u05dd"
+ }
+ },
+ "speech": {
+ "start": "\u05d4\u05ea\u05d7\u05dc \u05d4\u05e7\u05dc\u05d8\u05d4",
+ "stop": "\u05e2\u05e6\u05d5\u05e8 \u05d4\u05e7\u05dc\u05d8\u05d4",
+ "connecting": "\u05de\u05ea\u05d7\u05d1\u05e8"
+ },
+ "fileUpload": {
+ "dragDrop": "\u05d2\u05e8\u05d5\u05e8 \u05d5\u05e9\u05d7\u05e8\u05e8 \u05e7\u05d1\u05e6\u05d9\u05dd \u05db\u05d0\u05df",
+ "browse": "\u05e2\u05d9\u05d9\u05df \u05d1\u05e7\u05d1\u05e6\u05d9\u05dd",
+ "sizeLimit": "\u05de\u05d2\u05d1\u05dc\u05d4:",
+ "errors": {
+ "failed": "\u05d4\u05e2\u05dc\u05d0\u05d4 \u05e0\u05db\u05e9\u05dc\u05d4",
+ "cancelled": "\u05d4\u05e2\u05dc\u05d0\u05d4 \u05d1\u05d5\u05d8\u05dc\u05d4 \u05e9\u05dc"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u05de\u05e9\u05ea\u05de\u05e9 \u05d1",
+ "used": "\u05d4\u05e9\u05ea\u05de\u05e9 \u05d1"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u05d4\u05e2\u05ea\u05e7 \u05dc\u05dc\u05d5\u05d7",
+ "success": "\u05d4\u05d5\u05e2\u05ea\u05e7!"
+ }
+ },
+ "feedback": {
+ "positive": "\u05de\u05d5\u05e2\u05d9\u05dc",
+ "negative": "\u05dc\u05d0 \u05de\u05d5\u05e2\u05d9\u05dc",
+ "edit": "\u05e2\u05e8\u05d5\u05da \u05de\u05e9\u05d5\u05d1",
+ "dialog": {
+ "title": "\u05d4\u05d5\u05e1\u05e3 \u05ea\u05d2\u05d5\u05d1\u05d4",
+ "submit": "\u05e9\u05dc\u05d7 \u05de\u05e9\u05d5\u05d1"
+ },
+ "status": {
+ "updating": "\u05de\u05e2\u05d3\u05db\u05df",
+ "updated": "\u05d4\u05de\u05e9\u05d5\u05d1 \u05e2\u05d5\u05d3\u05db\u05df"
+ }
+ }
+ },
+ "history": {
+ "title": "\u05e7\u05dc\u05d8\u05d9\u05dd \u05d0\u05d7\u05e8\u05d5\u05e0\u05d9\u05dd",
+ "empty": "\u05db\u05dc \u05db\u05da \u05e8\u05d9\u05e7...",
+ "show": "\u05d4\u05e6\u05d2 \u05d4\u05d9\u05e1\u05d8\u05d5\u05e8\u05d9\u05d4"
+ },
+ "settings": {
+ "title": "\u05e4\u05d0\u05e0\u05dc \u05d4\u05d2\u05d3\u05e8\u05d5\u05ea"
+ },
+ "watermark": "\u05e0\u05d1\u05e0\u05d4 \u05d1\u05d0\u05de\u05e6\u05e2\u05d5\u05ea"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u05e6'\u05d0\u05d8\u05d9\u05dd \u05e7\u05d5\u05d3\u05de\u05d9\u05dd",
+ "filters": {
+ "search": "\u05d7\u05d9\u05e4\u05d5\u05e9",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u05d4\u05d9\u05d5\u05dd",
+ "yesterday": "\u05d0\u05ea\u05de\u05d5\u05dc",
+ "previous7days": "7 \u05d9\u05de\u05d9\u05dd \u05d0\u05d7\u05e8\u05d5\u05e0\u05d9\u05dd",
+ "previous30days": "30 \u05d9\u05de\u05d9\u05dd \u05d0\u05d7\u05e8\u05d5\u05e0\u05d9\u05dd"
+ },
+ "empty": "\u05dc\u05d0 \u05e0\u05de\u05e6\u05d0\u05d5 \u05e9\u05d9\u05d7\u05d5\u05ea",
+ "actions": {
+ "close": "\u05e1\u05d2\u05d5\u05e8 \u05e1\u05e8\u05d2\u05dc \u05e6\u05d3",
+ "open": "\u05e4\u05ea\u05d7 \u05e1\u05e8\u05d2\u05dc \u05e6\u05d3"
+ }
+ },
+ "thread": {
+ "untitled": "\u05e9\u05d9\u05d7\u05d4 \u05dc\u05dc\u05d0 \u05db\u05d5\u05ea\u05e8\u05ea",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u05d0\u05e9\u05e8 \u05de\u05d7\u05d9\u05e7\u05d4",
+ "description": "\u05e4\u05e2\u05d5\u05dc\u05d4 \u05d6\u05d5 \u05ea\u05de\u05d7\u05e7 \u05d0\u05ea \u05d4\u05e9\u05d9\u05d7\u05d4 \u05d5\u05db\u05df \u05d0\u05ea \u05d4\u05d4\u05d5\u05d3\u05e2\u05d5\u05ea \u05d5\u05d4\u05d0\u05dc\u05de\u05e0\u05d8\u05d9\u05dd \u05e9\u05dc\u05d4. \u05dc\u05d0 \u05e0\u05d9\u05ea\u05df \u05dc\u05d1\u05d8\u05dc \u05e4\u05e2\u05d5\u05dc\u05d4 \u05d6\u05d5",
+ "success": "\u05d4\u05e6'\u05d0\u05d8 \u05e0\u05de\u05d7\u05e7",
+ "inProgress": "\u05de\u05d5\u05d7\u05e7 \u05e6'\u05d0\u05d8"
+ },
+ "rename": {
+ "title": "\u05e9\u05e0\u05d4 \u05e9\u05dd \u05e9\u05d9\u05d7\u05d4",
+ "description": "\u05d4\u05d6\u05df \u05e9\u05dd \u05d7\u05d3\u05e9 \u05dc\u05e9\u05d9\u05d7\u05d4 \u05d6\u05d5",
+ "form": {
+ "name": {
+ "label": "\u05e9\u05dd",
+ "placeholder": "\u05d4\u05d6\u05df \u05e9\u05dd \u05d7\u05d3\u05e9"
+ }
+ },
+ "success": "\u05e9\u05dd \u05d4\u05e9\u05d9\u05d7\u05d4 \u05e9\u05d5\u05e0\u05d4!",
+ "inProgress": "\u05de\u05e9\u05e0\u05d4 \u05e9\u05dd \u05e9\u05d9\u05d7\u05d4"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u05e6'\u05d0\u05d8",
+ "readme": "\u05e7\u05e8\u05d0 \u05d0\u05d5\u05ea\u05d9",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u05e6'\u05d0\u05d8 \u05d7\u05d3\u05e9",
+ "dialog": {
+ "title": "\u05e6\u05d5\u05e8 \u05e6'\u05d0\u05d8 \u05d7\u05d3\u05e9",
+ "description": "\u05e4\u05e2\u05d5\u05dc\u05d4 \u05d6\u05d5 \u05ea\u05e0\u05e7\u05d4 \u05d0\u05ea \u05d4\u05d9\u05e1\u05d8\u05d5\u05e8\u05d9\u05d9\u05ea \u05d4\u05e6'\u05d0\u05d8 \u05d4\u05e0\u05d5\u05db\u05d7\u05d9\u05ea \u05e9\u05dc\u05da. \u05d4\u05d0\u05dd \u05d0\u05ea\u05d4 \u05d1\u05d8\u05d5\u05d7 \u05e9\u05d1\u05e8\u05e6\u05d5\u05e0\u05da \u05dc\u05d4\u05de\u05e9\u05d9\u05da?",
+ "tooltip": "\u05e6'\u05d0\u05d8 \u05d7\u05d3\u05e9"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u05d4\u05d2\u05d3\u05e8\u05d5\u05ea",
+ "settingsKey": "\u05d4",
+ "apiKeys": "\u05de\u05e4\u05ea\u05d7\u05d5\u05ea API",
+ "logout": "\u05d4\u05ea\u05e0\u05ea\u05e7"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u05de\u05e4\u05ea\u05d7\u05d5\u05ea API \u05e0\u05d3\u05e8\u05e9\u05d9\u05dd",
+ "description": "\u05db\u05d3\u05d9 \u05dc\u05d4\u05e9\u05ea\u05de\u05e9 \u05d1\u05d0\u05e4\u05dc\u05d9\u05e7\u05e6\u05d9\u05d4 \u05d6\u05d5, \u05e0\u05d3\u05e8\u05e9\u05d9\u05dd \u05de\u05e4\u05ea\u05d7\u05d5\u05ea API \u05d4\u05d1\u05d0\u05d9\u05dd. \u05d4\u05de\u05e4\u05ea\u05d7\u05d5\u05ea \u05de\u05d0\u05d5\u05d7\u05e1\u05e0\u05d9\u05dd \u05d1\u05d0\u05d7\u05e1\u05d5\u05df \u05d4\u05de\u05e7\u05d5\u05de\u05d9 \u05e9\u05dc \u05d4\u05de\u05db\u05e9\u05d9\u05e8 \u05e9\u05dc\u05da.",
+ "success": {
+ "saved": "\u05e0\u05e9\u05de\u05e8 \u05d1\u05d4\u05e6\u05dc\u05d7\u05d4"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/hi.json b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/hi.json
new file mode 100644
index 00000000..d6acccb3
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/hi.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u0930\u0926\u094d\u0926 \u0915\u0930\u0947\u0902",
+ "confirm": "\u092a\u0941\u0937\u094d\u091f\u093f \u0915\u0930\u0947\u0902",
+ "continue": "\u091c\u093e\u0930\u0940 \u0930\u0916\u0947\u0902",
+ "goBack": "\u0935\u093e\u092a\u0938 \u091c\u093e\u090f\u0902",
+ "reset": "\u0930\u0940\u0938\u0947\u091f \u0915\u0930\u0947\u0902",
+ "submit": "\u091c\u092e\u093e \u0915\u0930\u0947\u0902"
+ },
+ "status": {
+ "loading": "\u0932\u094b\u0921 \u0939\u094b \u0930\u0939\u093e \u0939\u0948...",
+ "error": {
+ "default": "\u090f\u0915 \u0924\u094d\u0930\u0941\u091f\u093f \u0939\u0941\u0908",
+ "serverConnection": "\u0938\u0930\u094d\u0935\u0930 \u0938\u0947 \u0938\u0902\u092a\u0930\u094d\u0915 \u0928\u0939\u0940\u0902 \u0939\u094b \u092a\u093e \u0930\u0939\u093e"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u0910\u092a \u0915\u093e \u0909\u092a\u092f\u094b\u0917 \u0915\u0930\u0928\u0947 \u0915\u0947 \u0932\u093f\u090f \u0932\u0949\u0917\u093f\u0928 \u0915\u0930\u0947\u0902",
+ "form": {
+ "email": {
+ "label": "\u0908\u092e\u0947\u0932 \u092a\u0924\u093e",
+ "required": "\u0908\u092e\u0947\u0932 \u090f\u0915 \u0906\u0935\u0936\u094d\u092f\u0915 \u092b\u093c\u0940\u0932\u094d\u0921 \u0939\u0948"
+ },
+ "password": {
+ "label": "\u092a\u093e\u0938\u0935\u0930\u094d\u0921",
+ "required": "\u092a\u093e\u0938\u0935\u0930\u094d\u0921 \u090f\u0915 \u0906\u0935\u0936\u094d\u092f\u0915 \u092b\u093c\u0940\u0932\u094d\u0921 \u0939\u0948"
+ },
+ "actions": {
+ "signin": "\u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0947\u0902"
+ },
+ "alternativeText": {
+ "or": "\u092f\u093e"
+ }
+ },
+ "errors": {
+ "default": "\u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0928\u0947 \u092e\u0947\u0902 \u0905\u0938\u092e\u0930\u094d\u0925",
+ "signin": "\u0915\u093f\u0938\u0940 \u0926\u0942\u0938\u0930\u0947 \u0916\u093e\u0924\u0947 \u0938\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0928\u0947 \u0915\u093e \u092a\u094d\u0930\u092f\u093e\u0938 \u0915\u0930\u0947\u0902",
+ "oauthSignin": "\u0915\u093f\u0938\u0940 \u0926\u0942\u0938\u0930\u0947 \u0916\u093e\u0924\u0947 \u0938\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0928\u0947 \u0915\u093e \u092a\u094d\u0930\u092f\u093e\u0938 \u0915\u0930\u0947\u0902",
+ "redirectUriMismatch": "\u0930\u0940\u0921\u093e\u092f\u0930\u0947\u0915\u094d\u091f URI oauth \u0910\u092a \u0915\u0949\u0928\u094d\u092b\u093c\u093f\u0917\u0930\u0947\u0936\u0928 \u0938\u0947 \u092e\u0947\u0932 \u0928\u0939\u0940\u0902 \u0916\u093e \u0930\u0939\u093e",
+ "oauthCallback": "\u0915\u093f\u0938\u0940 \u0926\u0942\u0938\u0930\u0947 \u0916\u093e\u0924\u0947 \u0938\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0928\u0947 \u0915\u093e \u092a\u094d\u0930\u092f\u093e\u0938 \u0915\u0930\u0947\u0902",
+ "oauthCreateAccount": "\u0915\u093f\u0938\u0940 \u0926\u0942\u0938\u0930\u0947 \u0916\u093e\u0924\u0947 \u0938\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0928\u0947 \u0915\u093e \u092a\u094d\u0930\u092f\u093e\u0938 \u0915\u0930\u0947\u0902",
+ "emailCreateAccount": "\u0915\u093f\u0938\u0940 \u0926\u0942\u0938\u0930\u0947 \u0916\u093e\u0924\u0947 \u0938\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0928\u0947 \u0915\u093e \u092a\u094d\u0930\u092f\u093e\u0938 \u0915\u0930\u0947\u0902",
+ "callback": "\u0915\u093f\u0938\u0940 \u0926\u0942\u0938\u0930\u0947 \u0916\u093e\u0924\u0947 \u0938\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0928\u0947 \u0915\u093e \u092a\u094d\u0930\u092f\u093e\u0938 \u0915\u0930\u0947\u0902",
+ "oauthAccountNotLinked": "\u0905\u092a\u0928\u0940 \u092a\u0939\u091a\u093e\u0928 \u0915\u0940 \u092a\u0941\u0937\u094d\u091f\u093f \u0915\u0930\u0928\u0947 \u0915\u0947 \u0932\u093f\u090f, \u0909\u0938\u0940 \u0916\u093e\u0924\u0947 \u0938\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0947\u0902 \u091c\u093f\u0938\u0915\u093e \u0909\u092a\u092f\u094b\u0917 \u0906\u092a\u0928\u0947 \u092e\u0942\u0932 \u0930\u0942\u092a \u0938\u0947 \u0915\u093f\u092f\u093e \u0925\u093e",
+ "emailSignin": "\u0908\u092e\u0947\u0932 \u0928\u0939\u0940\u0902 \u092d\u0947\u091c\u093e \u091c\u093e \u0938\u0915\u093e",
+ "emailVerify": "\u0915\u0943\u092a\u092f\u093e \u0905\u092a\u0928\u093e \u0908\u092e\u0947\u0932 \u0938\u0924\u094d\u092f\u093e\u092a\u093f\u0924 \u0915\u0930\u0947\u0902, \u090f\u0915 \u0928\u092f\u093e \u0908\u092e\u0947\u0932 \u092d\u0947\u091c\u093e \u0917\u092f\u093e \u0939\u0948",
+ "credentialsSignin": "\u0938\u093e\u0907\u0928 \u0907\u0928 \u0935\u093f\u092b\u0932\u0964 \u0906\u092a\u0915\u0947 \u0926\u094d\u0935\u093e\u0930\u093e \u092a\u094d\u0930\u0926\u093e\u0928 \u0915\u093f\u090f \u0917\u090f \u0935\u093f\u0935\u0930\u0923 \u0915\u0940 \u091c\u093e\u0902\u091a \u0915\u0930\u0947\u0902",
+ "sessionRequired": "\u0907\u0938 \u092a\u0943\u0937\u094d\u0920 \u0924\u0915 \u092a\u0939\u0941\u0902\u091a\u0928\u0947 \u0915\u0947 \u0932\u093f\u090f \u0915\u0943\u092a\u092f\u093e \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0947\u0902"
+ }
+ },
+ "provider": {
+ "continue": "{{provider}} \u0915\u0947 \u0938\u093e\u0925 \u091c\u093e\u0930\u0940 \u0930\u0916\u0947\u0902"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u0905\u092a\u0928\u093e \u0938\u0902\u0926\u0947\u0936 \u092f\u0939\u093e\u0902 \u091f\u093e\u0907\u092a \u0915\u0930\u0947\u0902...",
+ "actions": {
+ "send": "\u0938\u0902\u0926\u0947\u0936 \u092d\u0947\u091c\u0947\u0902",
+ "stop": "\u0915\u093e\u0930\u094d\u092f \u0930\u094b\u0915\u0947\u0902",
+ "attachFiles": "\u092b\u093c\u093e\u0907\u0932\u0947\u0902 \u0938\u0902\u0932\u0917\u094d\u0928 \u0915\u0930\u0947\u0902"
+ }
+ },
+ "speech": {
+ "start": "\u0930\u093f\u0915\u0949\u0930\u094d\u0921\u093f\u0902\u0917 \u0936\u0941\u0930\u0942 \u0915\u0930\u0947\u0902",
+ "stop": "\u0930\u093f\u0915\u0949\u0930\u094d\u0921\u093f\u0902\u0917 \u0930\u094b\u0915\u0947\u0902",
+ "connecting": "\u0915\u0928\u0947\u0915\u094d\u091f \u0939\u094b \u0930\u0939\u093e \u0939\u0948"
+ },
+ "fileUpload": {
+ "dragDrop": "\u092b\u093c\u093e\u0907\u0932\u094b\u0902 \u0915\u094b \u092f\u0939\u093e\u0902 \u0916\u0940\u0902\u091a\u0947\u0902 \u0914\u0930 \u091b\u094b\u0921\u093c\u0947\u0902",
+ "browse": "\u092b\u093c\u093e\u0907\u0932\u0947\u0902 \u092c\u094d\u0930\u093e\u0909\u091c\u093c \u0915\u0930\u0947\u0902",
+ "sizeLimit": "\u0938\u0940\u092e\u093e:",
+ "errors": {
+ "failed": "\u0905\u092a\u0932\u094b\u0921 \u0915\u0930\u0928\u0947 \u092e\u0947\u0902 \u0935\u093f\u092b\u0932",
+ "cancelled": "\u0915\u093e \u0905\u092a\u0932\u094b\u0921 \u0930\u0926\u094d\u0926 \u0915\u093f\u092f\u093e \u0917\u092f\u093e"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u0909\u092a\u092f\u094b\u0917 \u0915\u0930 \u0930\u0939\u0947 \u0939\u0948\u0902",
+ "used": "\u0909\u092a\u092f\u094b\u0917 \u0915\u093f\u092f\u093e"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u0915\u094d\u0932\u093f\u092a\u092c\u094b\u0930\u094d\u0921 \u092a\u0930 \u0915\u0949\u092a\u0940 \u0915\u0930\u0947\u0902",
+ "success": "\u0915\u0949\u092a\u0940 \u0915\u093f\u092f\u093e \u0917\u092f\u093e!"
+ }
+ },
+ "feedback": {
+ "positive": "\u0938\u0939\u093e\u092f\u0915",
+ "negative": "\u0938\u0939\u093e\u092f\u0915 \u0928\u0939\u0940\u0902",
+ "edit": "\u092a\u094d\u0930\u0924\u093f\u0915\u094d\u0930\u093f\u092f\u093e \u0938\u0902\u092a\u093e\u0926\u093f\u0924 \u0915\u0930\u0947\u0902",
+ "dialog": {
+ "title": "\u091f\u093f\u092a\u094d\u092a\u0923\u0940 \u091c\u094b\u0921\u093c\u0947\u0902",
+ "submit": "\u092a\u094d\u0930\u0924\u093f\u0915\u094d\u0930\u093f\u092f\u093e \u091c\u092e\u093e \u0915\u0930\u0947\u0902"
+ },
+ "status": {
+ "updating": "\u0905\u092a\u0921\u0947\u091f \u0939\u094b \u0930\u0939\u093e \u0939\u0948",
+ "updated": "\u092a\u094d\u0930\u0924\u093f\u0915\u094d\u0930\u093f\u092f\u093e \u0905\u092a\u0921\u0947\u091f \u0915\u0940 \u0917\u0908"
+ }
+ }
+ },
+ "history": {
+ "title": "\u092a\u093f\u091b\u0932\u0947 \u0907\u0928\u092a\u0941\u091f",
+ "empty": "\u0915\u0941\u091b \u092d\u0940 \u0928\u0939\u0940\u0902 \u0939\u0948...",
+ "show": "\u0907\u0924\u093f\u0939\u093e\u0938 \u0926\u093f\u0916\u093e\u090f\u0902"
+ },
+ "settings": {
+ "title": "\u0938\u0947\u091f\u093f\u0902\u0917\u094d\u0938 \u092a\u0948\u0928\u0932"
+ },
+ "watermark": "\u0915\u0947 \u0938\u093e\u0925 \u092c\u0928\u093e\u092f\u093e \u0917\u092f\u093e"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u092a\u093f\u091b\u0932\u0940 \u091a\u0948\u091f",
+ "filters": {
+ "search": "\u0916\u094b\u091c\u0947\u0902",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u0906\u091c",
+ "yesterday": "\u0915\u0932",
+ "previous7days": "\u092a\u093f\u091b\u0932\u0947 7 \u0926\u093f\u0928",
+ "previous30days": "\u092a\u093f\u091b\u0932\u0947 30 \u0926\u093f\u0928"
+ },
+ "empty": "\u0915\u094b\u0908 \u0925\u094d\u0930\u0947\u0921 \u0928\u0939\u0940\u0902 \u092e\u093f\u0932\u093e",
+ "actions": {
+ "close": "\u0938\u093e\u0907\u0921\u092c\u093e\u0930 \u092c\u0902\u0926 \u0915\u0930\u0947\u0902",
+ "open": "\u0938\u093e\u0907\u0921\u092c\u093e\u0930 \u0916\u094b\u0932\u0947\u0902"
+ }
+ },
+ "thread": {
+ "untitled": "\u0936\u0940\u0930\u094d\u0937\u0915\u0939\u0940\u0928 \u0935\u093e\u0930\u094d\u0924\u093e\u0932\u093e\u092a",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u0939\u091f\u093e\u0928\u0947 \u0915\u0940 \u092a\u0941\u0937\u094d\u091f\u093f \u0915\u0930\u0947\u0902",
+ "description": "\u092f\u0939 \u0925\u094d\u0930\u0947\u0921 \u0914\u0930 \u0907\u0938\u0915\u0947 \u0938\u0902\u0926\u0947\u0936\u094b\u0902 \u0914\u0930 \u0924\u0924\u094d\u0935\u094b\u0902 \u0915\u094b \u0939\u091f\u093e \u0926\u0947\u0917\u093e\u0964 \u092f\u0939 \u0915\u094d\u0930\u093f\u092f\u093e \u0935\u093e\u092a\u0938 \u0928\u0939\u0940\u0902 \u0915\u0940 \u091c\u093e \u0938\u0915\u0924\u0940",
+ "success": "\u091a\u0948\u091f \u0939\u091f\u093e \u0926\u0940 \u0917\u0908",
+ "inProgress": "\u091a\u0948\u091f \u0939\u091f\u093e\u0908 \u091c\u093e \u0930\u0939\u0940 \u0939\u0948"
+ },
+ "rename": {
+ "title": "\u0925\u094d\u0930\u0947\u0921 \u0915\u093e \u0928\u093e\u092e \u092c\u0926\u0932\u0947\u0902",
+ "description": "\u0907\u0938 \u0925\u094d\u0930\u0947\u0921 \u0915\u0947 \u0932\u093f\u090f \u090f\u0915 \u0928\u092f\u093e \u0928\u093e\u092e \u0926\u0930\u094d\u091c \u0915\u0930\u0947\u0902",
+ "form": {
+ "name": {
+ "label": "\u0928\u093e\u092e",
+ "placeholder": "\u0928\u092f\u093e \u0928\u093e\u092e \u0926\u0930\u094d\u091c \u0915\u0930\u0947\u0902"
+ }
+ },
+ "success": "\u0925\u094d\u0930\u0947\u0921 \u0915\u093e \u0928\u093e\u092e \u092c\u0926\u0932 \u0926\u093f\u092f\u093e \u0917\u092f\u093e!",
+ "inProgress": "\u0925\u094d\u0930\u0947\u0921 \u0915\u093e \u0928\u093e\u092e \u092c\u0926\u0932\u093e \u091c\u093e \u0930\u0939\u093e \u0939\u0948"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u091a\u0948\u091f",
+ "readme": "\u0930\u0940\u0921\u092e\u0940",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u0928\u0908 \u091a\u0948\u091f",
+ "dialog": {
+ "title": "\u0928\u0908 \u091a\u0948\u091f \u092c\u0928\u093e\u090f\u0902",
+ "description": "\u092f\u0939 \u0906\u092a\u0915\u093e \u0935\u0930\u094d\u0924\u092e\u093e\u0928 \u091a\u0948\u091f \u0907\u0924\u093f\u0939\u093e\u0938 \u0938\u093e\u092b\u093c \u0915\u0930 \u0926\u0947\u0917\u093e\u0964 \u0915\u094d\u092f\u093e \u0906\u092a \u091c\u093e\u0930\u0940 \u0930\u0916\u0928\u093e \u091a\u093e\u0939\u0924\u0947 \u0939\u0948\u0902?",
+ "tooltip": "\u0928\u0908 \u091a\u0948\u091f"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u0938\u0947\u091f\u093f\u0902\u0917\u094d\u0938",
+ "settingsKey": "S",
+ "apiKeys": "API \u0915\u0941\u0902\u091c\u093f\u092f\u093e\u0902",
+ "logout": "\u0932\u0949\u0917\u0906\u0909\u091f"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u0906\u0935\u0936\u094d\u092f\u0915 API \u0915\u0941\u0902\u091c\u093f\u092f\u093e\u0902",
+ "description": "\u0907\u0938 \u0910\u092a \u0915\u093e \u0909\u092a\u092f\u094b\u0917 \u0915\u0930\u0928\u0947 \u0915\u0947 \u0932\u093f\u090f, \u0928\u093f\u092e\u094d\u0928\u0932\u093f\u0916\u093f\u0924 API \u0915\u0941\u0902\u091c\u093f\u092f\u093e\u0902 \u0906\u0935\u0936\u094d\u092f\u0915 \u0939\u0948\u0902\u0964 \u0915\u0941\u0902\u091c\u093f\u092f\u093e\u0902 \u0906\u092a\u0915\u0947 \u0921\u093f\u0935\u093e\u0907\u0938 \u0915\u0947 \u0938\u094d\u0925\u093e\u0928\u0940\u092f \u0938\u0902\u0917\u094d\u0930\u0939\u0923 \u092e\u0947\u0902 \u0938\u0902\u0917\u094d\u0930\u0939\u0940\u0924 \u0915\u0940 \u091c\u093e\u0924\u0940 \u0939\u0948\u0902\u0964",
+ "success": {
+ "saved": "\u0938\u092b\u0932\u0924\u093e\u092a\u0942\u0930\u094d\u0935\u0915 \u0938\u0939\u0947\u091c\u093e \u0917\u092f\u093e"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/ja.json b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/ja.json
new file mode 100644
index 00000000..343ee37e
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/ja.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u30ad\u30e3\u30f3\u30bb\u30eb",
+ "confirm": "\u78ba\u8a8d",
+ "continue": "\u7d9a\u3051\u308b",
+ "goBack": "\u623b\u308b",
+ "reset": "\u30ea\u30bb\u30c3\u30c8",
+ "submit": "\u9001\u4fe1"
+ },
+ "status": {
+ "loading": "\u8aad\u307f\u8fbc\u307f\u4e2d...",
+ "error": {
+ "default": "\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f",
+ "serverConnection": "\u30b5\u30fc\u30d0\u30fc\u306b\u63a5\u7d9a\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u30a2\u30d7\u30ea\u306b\u30ed\u30b0\u30a4\u30f3",
+ "form": {
+ "email": {
+ "label": "\u30e1\u30fc\u30eb\u30a2\u30c9\u30ec\u30b9",
+ "required": "\u30e1\u30fc\u30eb\u30a2\u30c9\u30ec\u30b9\u306f\u5fc5\u9808\u9805\u76ee\u3067\u3059"
+ },
+ "password": {
+ "label": "\u30d1\u30b9\u30ef\u30fc\u30c9",
+ "required": "\u30d1\u30b9\u30ef\u30fc\u30c9\u306f\u5fc5\u9808\u9805\u76ee\u3067\u3059"
+ },
+ "actions": {
+ "signin": "\u30b5\u30a4\u30f3\u30a4\u30f3"
+ },
+ "alternativeText": {
+ "or": "\u307e\u305f\u306f"
+ }
+ },
+ "errors": {
+ "default": "\u30b5\u30a4\u30f3\u30a4\u30f3\u3067\u304d\u307e\u305b\u3093",
+ "signin": "\u5225\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u3067\u30b5\u30a4\u30f3\u30a4\u30f3\u3057\u3066\u304f\u3060\u3055\u3044",
+ "oauthSignin": "\u5225\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u3067\u30b5\u30a4\u30f3\u30a4\u30f3\u3057\u3066\u304f\u3060\u3055\u3044",
+ "redirectUriMismatch": "\u30ea\u30c0\u30a4\u30ec\u30af\u30c8URI\u304cOAuth\u30a2\u30d7\u30ea\u306e\u8a2d\u5b9a\u3068\u4e00\u81f4\u3057\u307e\u305b\u3093",
+ "oauthCallback": "\u5225\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u3067\u30b5\u30a4\u30f3\u30a4\u30f3\u3057\u3066\u304f\u3060\u3055\u3044",
+ "oauthCreateAccount": "\u5225\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u3067\u30b5\u30a4\u30f3\u30a4\u30f3\u3057\u3066\u304f\u3060\u3055\u3044",
+ "emailCreateAccount": "\u5225\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u3067\u30b5\u30a4\u30f3\u30a4\u30f3\u3057\u3066\u304f\u3060\u3055\u3044",
+ "callback": "\u5225\u306e\u30a2\u30ab\u30a6\u30f3\u30c8\u3067\u30b5\u30a4\u30f3\u30a4\u30f3\u3057\u3066\u304f\u3060\u3055\u3044",
+ "oauthAccountNotLinked": "\u672c\u4eba\u78ba\u8a8d\u306e\u305f\u3081\u3001\u6700\u521d\u306b\u4f7f\u7528\u3057\u305f\u306e\u3068\u540c\u3058\u30a2\u30ab\u30a6\u30f3\u30c8\u3067\u30b5\u30a4\u30f3\u30a4\u30f3\u3057\u3066\u304f\u3060\u3055\u3044",
+ "emailSignin": "\u30e1\u30fc\u30eb\u3092\u9001\u4fe1\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f",
+ "emailVerify": "\u30e1\u30fc\u30eb\u30a2\u30c9\u30ec\u30b9\u3092\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044\u3002\u65b0\u3057\u3044\u30e1\u30fc\u30eb\u304c\u9001\u4fe1\u3055\u308c\u307e\u3057\u305f",
+ "credentialsSignin": "\u30b5\u30a4\u30f3\u30a4\u30f3\u306b\u5931\u6557\u3057\u307e\u3057\u305f\u3002\u5165\u529b\u3057\u305f\u60c5\u5831\u304c\u6b63\u3057\u3044\u304b\u78ba\u8a8d\u3057\u3066\u304f\u3060\u3055\u3044",
+ "sessionRequired": "\u3053\u306e\u30da\u30fc\u30b8\u306b\u30a2\u30af\u30bb\u30b9\u3059\u308b\u306b\u306f\u30b5\u30a4\u30f3\u30a4\u30f3\u3057\u3066\u304f\u3060\u3055\u3044"
+ }
+ },
+ "provider": {
+ "continue": "{{provider}}\u3067\u7d9a\u3051\u308b"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044...",
+ "actions": {
+ "send": "\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u9001\u4fe1",
+ "stop": "\u30bf\u30b9\u30af\u3092\u505c\u6b62",
+ "attachFiles": "\u30d5\u30a1\u30a4\u30eb\u3092\u6dfb\u4ed8"
+ }
+ },
+ "speech": {
+ "start": "\u9332\u97f3\u958b\u59cb",
+ "stop": "\u9332\u97f3\u505c\u6b62",
+ "connecting": "\u63a5\u7d9a\u4e2d"
+ },
+ "fileUpload": {
+ "dragDrop": "\u3053\u3053\u306b\u30d5\u30a1\u30a4\u30eb\u3092\u30c9\u30e9\u30c3\u30b0\uff06\u30c9\u30ed\u30c3\u30d7",
+ "browse": "\u30d5\u30a1\u30a4\u30eb\u3092\u53c2\u7167",
+ "sizeLimit": "\u5236\u9650\uff1a",
+ "errors": {
+ "failed": "\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f",
+ "cancelled": "\u30a2\u30c3\u30d7\u30ed\u30fc\u30c9\u3092\u30ad\u30e3\u30f3\u30bb\u30eb\u3057\u307e\u3057\u305f\uff1a"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u4f7f\u7528\u4e2d",
+ "used": "\u4f7f\u7528\u6e08\u307f"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u30af\u30ea\u30c3\u30d7\u30dc\u30fc\u30c9\u306b\u30b3\u30d4\u30fc",
+ "success": "\u30b3\u30d4\u30fc\u3057\u307e\u3057\u305f\uff01"
+ }
+ },
+ "feedback": {
+ "positive": "\u5f79\u306b\u7acb\u3063\u305f",
+ "negative": "\u5f79\u306b\u7acb\u305f\u306a\u304b\u3063\u305f",
+ "edit": "\u30d5\u30a3\u30fc\u30c9\u30d0\u30c3\u30af\u3092\u7de8\u96c6",
+ "dialog": {
+ "title": "\u30b3\u30e1\u30f3\u30c8\u3092\u8ffd\u52a0",
+ "submit": "\u30d5\u30a3\u30fc\u30c9\u30d0\u30c3\u30af\u3092\u9001\u4fe1"
+ },
+ "status": {
+ "updating": "\u66f4\u65b0\u4e2d",
+ "updated": "\u30d5\u30a3\u30fc\u30c9\u30d0\u30c3\u30af\u3092\u66f4\u65b0\u3057\u307e\u3057\u305f"
+ }
+ }
+ },
+ "history": {
+ "title": "\u6700\u8fd1\u306e\u5165\u529b",
+ "empty": "\u4f55\u3082\u3042\u308a\u307e\u305b\u3093...",
+ "show": "\u5c65\u6b74\u3092\u8868\u793a"
+ },
+ "settings": {
+ "title": "\u8a2d\u5b9a\u30d1\u30cd\u30eb"
+ },
+ "watermark": "\u958b\u767a\u5143\uff1a"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u904e\u53bb\u306e\u30c1\u30e3\u30c3\u30c8",
+ "filters": {
+ "search": "\u691c\u7d22",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u4eca\u65e5",
+ "yesterday": "\u6628\u65e5",
+ "previous7days": "\u904e\u53bb7\u65e5\u9593",
+ "previous30days": "\u904e\u53bb30\u65e5\u9593"
+ },
+ "empty": "\u30b9\u30ec\u30c3\u30c9\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093",
+ "actions": {
+ "close": "\u30b5\u30a4\u30c9\u30d0\u30fc\u3092\u9589\u3058\u308b",
+ "open": "\u30b5\u30a4\u30c9\u30d0\u30fc\u3092\u958b\u304f"
+ }
+ },
+ "thread": {
+ "untitled": "\u7121\u984c\u306e\u4f1a\u8a71",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u524a\u9664\u306e\u78ba\u8a8d",
+ "description": "\u3053\u306e\u30b9\u30ec\u30c3\u30c9\u3068\u305d\u306e\u30e1\u30c3\u30bb\u30fc\u30b8\u3001\u8981\u7d20\u304c\u524a\u9664\u3055\u308c\u307e\u3059\u3002\u3053\u306e\u64cd\u4f5c\u306f\u53d6\u308a\u6d88\u305b\u307e\u305b\u3093",
+ "success": "\u30c1\u30e3\u30c3\u30c8\u3092\u524a\u9664\u3057\u307e\u3057\u305f",
+ "inProgress": "\u30c1\u30e3\u30c3\u30c8\u3092\u524a\u9664\u4e2d"
+ },
+ "rename": {
+ "title": "\u30b9\u30ec\u30c3\u30c9\u306e\u540d\u524d\u3092\u5909\u66f4",
+ "description": "\u3053\u306e\u30b9\u30ec\u30c3\u30c9\u306e\u65b0\u3057\u3044\u540d\u524d\u3092\u5165\u529b\u3057\u3066\u304f\u3060\u3055\u3044",
+ "form": {
+ "name": {
+ "label": "\u540d\u524d",
+ "placeholder": "\u65b0\u3057\u3044\u540d\u524d\u3092\u5165\u529b"
+ }
+ },
+ "success": "\u30b9\u30ec\u30c3\u30c9\u540d\u3092\u5909\u66f4\u3057\u307e\u3057\u305f\uff01",
+ "inProgress": "\u30b9\u30ec\u30c3\u30c9\u540d\u3092\u5909\u66f4\u4e2d"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u30c1\u30e3\u30c3\u30c8",
+ "readme": "\u8aac\u660e\u66f8",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u65b0\u898f\u30c1\u30e3\u30c3\u30c8",
+ "dialog": {
+ "title": "\u65b0\u898f\u30c1\u30e3\u30c3\u30c8\u306e\u4f5c\u6210",
+ "description": "\u73fe\u5728\u306e\u30c1\u30e3\u30c3\u30c8\u5c65\u6b74\u304c\u30af\u30ea\u30a2\u3055\u308c\u307e\u3059\u3002\u7d9a\u884c\u3057\u307e\u3059\u304b\uff1f",
+ "tooltip": "\u65b0\u898f\u30c1\u30e3\u30c3\u30c8"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u8a2d\u5b9a",
+ "settingsKey": "S",
+ "apiKeys": "API\u30ad\u30fc",
+ "logout": "\u30ed\u30b0\u30a2\u30a6\u30c8"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u5fc5\u8981\u306aAPI\u30ad\u30fc",
+ "description": "\u3053\u306e\u30a2\u30d7\u30ea\u3092\u4f7f\u7528\u3059\u308b\u306b\u306f\u3001\u4ee5\u4e0b\u306eAPI\u30ad\u30fc\u304c\u5fc5\u8981\u3067\u3059\u3002\u30ad\u30fc\u306f\u304a\u4f7f\u3044\u306e\u30c7\u30d0\u30a4\u30b9\u306e\u30ed\u30fc\u30ab\u30eb\u30b9\u30c8\u30ec\u30fc\u30b8\u306b\u4fdd\u5b58\u3055\u308c\u307e\u3059\u3002",
+ "success": {
+ "saved": "\u4fdd\u5b58\u304c\u5b8c\u4e86\u3057\u307e\u3057\u305f"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/kn.json b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/kn.json
new file mode 100644
index 00000000..c8ffabc0
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/kn.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u0cb0\u0ca6\u0ccd\u0ca6\u0cc1\u0cae\u0cbe\u0ca1\u0cbf",
+ "confirm": "\u0ca6\u0cc3\u0ca2\u0cc0\u0c95\u0cb0\u0cbf\u0cb8\u0cbf",
+ "continue": "\u0cae\u0cc1\u0c82\u0ca6\u0cc1\u0cb5\u0cb0\u0cbf\u0cb8\u0cbf",
+ "goBack": "\u0cb9\u0cbf\u0c82\u0ca6\u0cc6 \u0cb9\u0ccb\u0c97\u0cbf",
+ "reset": "\u0cae\u0cb0\u0cc1\u0cb9\u0cca\u0c82\u0ca6\u0cbf\u0cb8\u0cbf",
+ "submit": "\u0cb8\u0cb2\u0ccd\u0cb2\u0cbf\u0cb8\u0cbf"
+ },
+ "status": {
+ "loading": "\u0cb2\u0ccb\u0ca1\u0ccd \u0c86\u0c97\u0cc1\u0ca4\u0ccd\u0ca4\u0cbf\u0ca6\u0cc6...",
+ "error": {
+ "default": "\u0ca6\u0ccb\u0cb7 \u0cb8\u0c82\u0cad\u0cb5\u0cbf\u0cb8\u0cbf\u0ca6\u0cc6",
+ "serverConnection": "\u0cb8\u0cb0\u0ccd\u0cb5\u0cb0\u0ccd\u200c \u0c85\u0ca8\u0ccd\u0ca8\u0cc1 \u0ca4\u0cb2\u0cc1\u0caa\u0cb2\u0cc1 \u0cb8\u0cbe\u0ca7\u0ccd\u0caf\u0cb5\u0cbe\u0c97\u0cb2\u0cbf\u0cb2\u0ccd\u0cb2"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u0c85\u0caa\u0ccd\u0cb2\u0cbf\u0c95\u0cc7\u0cb6\u0ca8\u0ccd\u200c\u0c97\u0cc6 \u0caa\u0ccd\u0cb0\u0cb5\u0cc7\u0cb6\u0cbf\u0cb8\u0cb2\u0cc1 \u0cb2\u0cbe\u0c97\u0cbf\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cbf",
+ "form": {
+ "email": {
+ "label": "\u0c87\u0cae\u0cc7\u0cb2\u0ccd \u0cb5\u0cbf\u0cb3\u0cbe\u0cb8",
+ "required": "\u0c87\u0cae\u0cc7\u0cb2\u0ccd \u0c85\u0c97\u0ca4\u0ccd\u0caf\u0cb5\u0cbf\u0cb0\u0cc1\u0cb5 \u0c95\u0ccd\u0cb7\u0cc7\u0ca4\u0ccd\u0cb0"
+ },
+ "password": {
+ "label": "\u0caa\u0cbe\u0cb8\u0ccd\u200c\u0cb5\u0cb0\u0ccd\u0ca1\u0ccd",
+ "required": "\u0caa\u0cbe\u0cb8\u0ccd\u200c\u0cb5\u0cb0\u0ccd\u0ca1\u0ccd \u0c85\u0c97\u0ca4\u0ccd\u0caf\u0cb5\u0cbf\u0cb0\u0cc1\u0cb5 \u0c95\u0ccd\u0cb7\u0cc7\u0ca4\u0ccd\u0cb0"
+ },
+ "actions": {
+ "signin": "\u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cbf"
+ },
+ "alternativeText": {
+ "or": "\u0c85\u0ca5\u0cb5\u0cbe"
+ }
+ },
+ "errors": {
+ "default": "\u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cb2\u0cc1 \u0cb8\u0cbe\u0ca7\u0ccd\u0caf\u0cb5\u0cbe\u0c97\u0cb2\u0cbf\u0cb2\u0ccd\u0cb2",
+ "signin": "\u0cac\u0cc7\u0cb0\u0cc6 \u0c96\u0cbe\u0ca4\u0cc6\u0caf\u0cca\u0c82\u0ca6\u0cbf\u0c97\u0cc6 \u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cb2\u0cc1 \u0caa\u0ccd\u0cb0\u0caf\u0ca4\u0ccd\u0ca8\u0cbf\u0cb8\u0cbf",
+ "oauthSignin": "\u0cac\u0cc7\u0cb0\u0cc6 \u0c96\u0cbe\u0ca4\u0cc6\u0caf\u0cca\u0c82\u0ca6\u0cbf\u0c97\u0cc6 \u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cb2\u0cc1 \u0caa\u0ccd\u0cb0\u0caf\u0ca4\u0ccd\u0ca8\u0cbf\u0cb8\u0cbf",
+ "redirectUriMismatch": "\u0cb0\u0cc0\u0ca1\u0cc8\u0cb0\u0cc6\u0c95\u0ccd\u0c9f\u0ccd URI \u0c93\u0ca5\u0ccd \u0c85\u0caa\u0ccd\u0cb2\u0cbf\u0c95\u0cc7\u0cb6\u0ca8\u0ccd \u0c95\u0cbe\u0ca8\u0ccd\u0cab\u0cbf\u0c97\u0cb0\u0cc7\u0cb6\u0ca8\u0ccd\u200c\u0c97\u0cc6 \u0cb9\u0cca\u0c82\u0ca6\u0cbf\u0c95\u0cc6\u0caf\u0cbe\u0c97\u0cc1\u0ca4\u0ccd\u0ca4\u0cbf\u0cb2\u0ccd\u0cb2",
+ "oauthCallback": "\u0cac\u0cc7\u0cb0\u0cc6 \u0c96\u0cbe\u0ca4\u0cc6\u0caf\u0cca\u0c82\u0ca6\u0cbf\u0c97\u0cc6 \u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cb2\u0cc1 \u0caa\u0ccd\u0cb0\u0caf\u0ca4\u0ccd\u0ca8\u0cbf\u0cb8\u0cbf",
+ "oauthCreateAccount": "\u0cac\u0cc7\u0cb0\u0cc6 \u0c96\u0cbe\u0ca4\u0cc6\u0caf\u0cca\u0c82\u0ca6\u0cbf\u0c97\u0cc6 \u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cb2\u0cc1 \u0caa\u0ccd\u0cb0\u0caf\u0ca4\u0ccd\u0ca8\u0cbf\u0cb8\u0cbf",
+ "emailCreateAccount": "\u0cac\u0cc7\u0cb0\u0cc6 \u0c96\u0cbe\u0ca4\u0cc6\u0caf\u0cca\u0c82\u0ca6\u0cbf\u0c97\u0cc6 \u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cb2\u0cc1 \u0caa\u0ccd\u0cb0\u0caf\u0ca4\u0ccd\u0ca8\u0cbf\u0cb8\u0cbf",
+ "callback": "\u0cac\u0cc7\u0cb0\u0cc6 \u0c96\u0cbe\u0ca4\u0cc6\u0caf\u0cca\u0c82\u0ca6\u0cbf\u0c97\u0cc6 \u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cb2\u0cc1 \u0caa\u0ccd\u0cb0\u0caf\u0ca4\u0ccd\u0ca8\u0cbf\u0cb8\u0cbf",
+ "oauthAccountNotLinked": "\u0ca8\u0cbf\u0cae\u0ccd\u0cae \u0c97\u0cc1\u0cb0\u0cc1\u0ca4\u0ca8\u0ccd\u0ca8\u0cc1 \u0ca6\u0cc3\u0ca2\u0cc0\u0c95\u0cb0\u0cbf\u0cb8\u0cb2\u0cc1, \u0ca8\u0cc0\u0cb5\u0cc1 \u0cae\u0cca\u0ca6\u0cb2\u0cc1 \u0cac\u0cb3\u0cb8\u0cbf\u0ca6 \u0c85\u0ca6\u0cc7 \u0c96\u0cbe\u0ca4\u0cc6\u0caf\u0cca\u0c82\u0ca6\u0cbf\u0c97\u0cc6 \u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cbf",
+ "emailSignin": "\u0c87\u0cae\u0cc7\u0cb2\u0ccd \u0c95\u0cb3\u0cc1\u0cb9\u0cbf\u0cb8\u0cb2\u0cc1 \u0cb8\u0cbe\u0ca7\u0ccd\u0caf\u0cb5\u0cbe\u0c97\u0cb2\u0cbf\u0cb2\u0ccd\u0cb2",
+ "emailVerify": "\u0ca6\u0caf\u0cb5\u0cbf\u0c9f\u0ccd\u0c9f\u0cc1 \u0ca8\u0cbf\u0cae\u0ccd\u0cae \u0c87\u0cae\u0cc7\u0cb2\u0ccd \u0caa\u0cb0\u0cbf\u0cb6\u0cc0\u0cb2\u0cbf\u0cb8\u0cbf, \u0cb9\u0cca\u0cb8 \u0c87\u0cae\u0cc7\u0cb2\u0ccd \u0c95\u0cb3\u0cc1\u0cb9\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6",
+ "credentialsSignin": "\u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cb5\u0cbf\u0cab\u0cb2\u0cb5\u0cbe\u0c97\u0cbf\u0ca6\u0cc6. \u0ca8\u0cc0\u0cb5\u0cc1 \u0c92\u0ca6\u0c97\u0cbf\u0cb8\u0cbf\u0ca6 \u0cb5\u0cbf\u0cb5\u0cb0\u0c97\u0cb3\u0cc1 \u0cb8\u0cb0\u0cbf\u0caf\u0cbe\u0c97\u0cbf\u0cb5\u0cc6\u0caf\u0cc7 \u0c8e\u0c82\u0ca6\u0cc1 \u0caa\u0cb0\u0cbf\u0cb6\u0cc0\u0cb2\u0cbf\u0cb8\u0cbf",
+ "sessionRequired": "\u0c88 \u0caa\u0cc1\u0c9f\u0cb5\u0ca8\u0ccd\u0ca8\u0cc1 \u0caa\u0ccd\u0cb0\u0cb5\u0cc7\u0cb6\u0cbf\u0cb8\u0cb2\u0cc1 \u0ca6\u0caf\u0cb5\u0cbf\u0c9f\u0ccd\u0c9f\u0cc1 \u0cb8\u0cc8\u0ca8\u0ccd \u0c87\u0ca8\u0ccd \u0cae\u0cbe\u0ca1\u0cbf"
+ }
+ },
+ "provider": {
+ "continue": "{{provider}} \u0ca8\u0cca\u0c82\u0ca6\u0cbf\u0c97\u0cc6 \u0cae\u0cc1\u0c82\u0ca6\u0cc1\u0cb5\u0cb0\u0cbf\u0cb8\u0cbf"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u0ca8\u0cbf\u0cae\u0ccd\u0cae \u0cb8\u0c82\u0ca6\u0cc7\u0cb6\u0cb5\u0ca8\u0ccd\u0ca8\u0cc1 \u0c87\u0cb2\u0ccd\u0cb2\u0cbf \u0c9f\u0cc8\u0caa\u0ccd \u0cae\u0cbe\u0ca1\u0cbf...",
+ "actions": {
+ "send": "\u0cb8\u0c82\u0ca6\u0cc7\u0cb6 \u0c95\u0cb3\u0cc1\u0cb9\u0cbf\u0cb8\u0cbf",
+ "stop": "\u0c95\u0cbe\u0cb0\u0ccd\u0caf \u0ca8\u0cbf\u0cb2\u0ccd\u0cb2\u0cbf\u0cb8\u0cbf",
+ "attachFiles": "\u0cab\u0cc8\u0cb2\u0ccd\u200c\u0c97\u0cb3\u0ca8\u0ccd\u0ca8\u0cc1 \u0cb2\u0c97\u0ca4\u0ccd\u0ca4\u0cbf\u0cb8\u0cbf"
+ }
+ },
+ "speech": {
+ "start": "\u0cb0\u0cc6\u0c95\u0cbe\u0cb0\u0ccd\u0ca1\u0cbf\u0c82\u0c97\u0ccd \u0caa\u0ccd\u0cb0\u0cbe\u0cb0\u0c82\u0cad\u0cbf\u0cb8\u0cbf",
+ "stop": "\u0cb0\u0cc6\u0c95\u0cbe\u0cb0\u0ccd\u0ca1\u0cbf\u0c82\u0c97\u0ccd \u0ca8\u0cbf\u0cb2\u0ccd\u0cb2\u0cbf\u0cb8\u0cbf",
+ "connecting": "\u0cb8\u0c82\u0caa\u0cb0\u0ccd\u0c95\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cc1\u0ca4\u0ccd\u0ca4\u0cbf\u0ca6\u0cc6"
+ },
+ "fileUpload": {
+ "dragDrop": "\u0cab\u0cc8\u0cb2\u0ccd\u200c\u0c97\u0cb3\u0ca8\u0ccd\u0ca8\u0cc1 \u0c87\u0cb2\u0ccd\u0cb2\u0cbf \u0c8e\u0cb3\u0cc6\u0ca6\u0cc1 \u0cac\u0cbf\u0ca1\u0cbf",
+ "browse": "\u0cab\u0cc8\u0cb2\u0ccd\u200c\u0c97\u0cb3\u0ca8\u0ccd\u0ca8\u0cc1 \u0cac\u0ccd\u0cb0\u0ccc\u0cb8\u0ccd \u0cae\u0cbe\u0ca1\u0cbf",
+ "sizeLimit": "\u0cae\u0cbf\u0ca4\u0cbf:",
+ "errors": {
+ "failed": "\u0c85\u0caa\u0ccd\u200c\u0cb2\u0ccb\u0ca1\u0ccd \u0cb5\u0cbf\u0cab\u0cb2\u0cb5\u0cbe\u0c97\u0cbf\u0ca6\u0cc6",
+ "cancelled": "\u0c85\u0caa\u0ccd\u200c\u0cb2\u0ccb\u0ca1\u0ccd \u0cb0\u0ca6\u0ccd\u0ca6\u0cc1\u0c97\u0cca\u0cb3\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u0cac\u0cb3\u0cb8\u0cc1\u0ca4\u0ccd\u0ca4\u0cbf\u0cb0\u0cc1\u0cb5\u0cc1\u0ca6\u0cc1",
+ "used": "\u0cac\u0cb3\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u0c95\u0ccd\u0cb2\u0cbf\u0caa\u0ccd\u200c\u0cac\u0ccb\u0cb0\u0ccd\u0ca1\u0ccd\u200c\u0c97\u0cc6 \u0ca8\u0c95\u0cb2\u0cbf\u0cb8\u0cbf",
+ "success": "\u0ca8\u0c95\u0cb2\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6!"
+ }
+ },
+ "feedback": {
+ "positive": "\u0cb8\u0cb9\u0cbe\u0caf\u0c95\u0cb5\u0cbe\u0c97\u0cbf\u0ca6\u0cc6",
+ "negative": "\u0cb8\u0cb9\u0cbe\u0caf\u0c95\u0cb5\u0cbe\u0c97\u0cbf\u0cb2\u0ccd\u0cb2",
+ "edit": "\u0caa\u0ccd\u0cb0\u0ca4\u0cbf\u0c95\u0ccd\u0cb0\u0cbf\u0caf\u0cc6 \u0cb8\u0c82\u0caa\u0cbe\u0ca6\u0cbf\u0cb8\u0cbf",
+ "dialog": {
+ "title": "\u0c95\u0cbe\u0cae\u0cc6\u0c82\u0c9f\u0ccd \u0cb8\u0cc7\u0cb0\u0cbf\u0cb8\u0cbf",
+ "submit": "\u0caa\u0ccd\u0cb0\u0ca4\u0cbf\u0c95\u0ccd\u0cb0\u0cbf\u0caf\u0cc6 \u0cb8\u0cb2\u0ccd\u0cb2\u0cbf\u0cb8\u0cbf"
+ },
+ "status": {
+ "updating": "\u0ca8\u0cb5\u0cc0\u0c95\u0cb0\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cc1\u0ca4\u0ccd\u0ca4\u0cbf\u0ca6\u0cc6",
+ "updated": "\u0caa\u0ccd\u0cb0\u0ca4\u0cbf\u0c95\u0ccd\u0cb0\u0cbf\u0caf\u0cc6 \u0ca8\u0cb5\u0cc0\u0c95\u0cb0\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6"
+ }
+ }
+ },
+ "history": {
+ "title": "\u0c95\u0cca\u0ca8\u0cc6\u0caf \u0c87\u0ca8\u0ccd\u200c\u0caa\u0cc1\u0c9f\u0ccd\u200c\u0c97\u0cb3\u0cc1",
+ "empty": "\u0c96\u0cbe\u0cb2\u0cbf\u0caf\u0cbe\u0c97\u0cbf\u0ca6\u0cc6...",
+ "show": "\u0c87\u0ca4\u0cbf\u0cb9\u0cbe\u0cb8 \u0ca4\u0ccb\u0cb0\u0cbf\u0cb8\u0cbf"
+ },
+ "settings": {
+ "title": "\u0cb8\u0cc6\u0c9f\u0ccd\u0c9f\u0cbf\u0c82\u0c97\u0ccd\u200c\u0c97\u0cb3 \u0caa\u0ccd\u0caf\u0cbe\u0ca8\u0cc6\u0cb2\u0ccd"
+ },
+ "watermark": "\u0c87\u0ca6\u0cb0\u0cca\u0c82\u0ca6\u0cbf\u0c97\u0cc6 \u0ca8\u0cbf\u0cb0\u0ccd\u0cae\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u0cb9\u0cbf\u0c82\u0ca6\u0cbf\u0ca8 \u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6\u0c97\u0cb3\u0cc1",
+ "filters": {
+ "search": "\u0cb9\u0cc1\u0ca1\u0cc1\u0c95\u0cbf",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u0c87\u0c82\u0ca6\u0cc1",
+ "yesterday": "\u0ca8\u0cbf\u0ca8\u0ccd\u0ca8\u0cc6",
+ "previous7days": "\u0cb9\u0cbf\u0c82\u0ca6\u0cbf\u0ca8 7 \u0ca6\u0cbf\u0ca8\u0c97\u0cb3\u0cc1",
+ "previous30days": "\u0cb9\u0cbf\u0c82\u0ca6\u0cbf\u0ca8 30 \u0ca6\u0cbf\u0ca8\u0c97\u0cb3\u0cc1"
+ },
+ "empty": "\u0caf\u0cbe\u0cb5\u0cc1\u0ca6\u0cc7 \u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6\u0c97\u0cb3\u0cc1 \u0c95\u0c82\u0ca1\u0cc1\u0cac\u0c82\u0ca6\u0cbf\u0cb2\u0ccd\u0cb2",
+ "actions": {
+ "close": "\u0caa\u0c95\u0ccd\u0c95\u0ca6 \u0caa\u0c9f\u0ccd\u0c9f\u0cbf \u0cae\u0cc1\u0c9a\u0ccd\u0c9a\u0cbf",
+ "open": "\u0caa\u0c95\u0ccd\u0c95\u0ca6 \u0caa\u0c9f\u0ccd\u0c9f\u0cbf \u0ca4\u0cc6\u0cb0\u0cc6\u0caf\u0cbf\u0cb0\u0cbf"
+ }
+ },
+ "thread": {
+ "untitled": "\u0cb6\u0cc0\u0cb0\u0ccd\u0cb7\u0cbf\u0c95\u0cc6\u0cb0\u0cb9\u0cbf\u0ca4 \u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u0c85\u0cb3\u0cbf\u0cb8\u0cc1\u0cb5\u0cbf\u0c95\u0cc6\u0caf\u0ca8\u0ccd\u0ca8\u0cc1 \u0ca6\u0cc3\u0ca2\u0cc0\u0c95\u0cb0\u0cbf\u0cb8\u0cbf",
+ "description": "\u0c87\u0ca6\u0cc1 \u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6\u0caf\u0ca8\u0ccd\u0ca8\u0cc1 \u0cb9\u0cbe\u0c97\u0cc2 \u0c85\u0ca6\u0cb0 \u0cb8\u0c82\u0ca6\u0cc7\u0cb6\u0c97\u0cb3\u0cc1 \u0cae\u0ca4\u0ccd\u0ca4\u0cc1 \u0c85\u0c82\u0cb6\u0c97\u0cb3\u0ca8\u0ccd\u0ca8\u0cc1 \u0c85\u0cb3\u0cbf\u0cb8\u0cc1\u0ca4\u0ccd\u0ca4\u0ca6\u0cc6. \u0c88 \u0c95\u0ccd\u0cb0\u0cbf\u0caf\u0cc6\u0caf\u0ca8\u0ccd\u0ca8\u0cc1 \u0cb0\u0ca6\u0ccd\u0ca6\u0cc1\u0c97\u0cca\u0cb3\u0cbf\u0cb8\u0cb2\u0cc1 \u0cb8\u0cbe\u0ca7\u0ccd\u0caf\u0cb5\u0cbf\u0cb2\u0ccd\u0cb2",
+ "success": "\u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6 \u0c85\u0cb3\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6",
+ "inProgress": "\u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6 \u0c85\u0cb3\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cc1\u0ca4\u0ccd\u0ca4\u0cbf\u0ca6\u0cc6"
+ },
+ "rename": {
+ "title": "\u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6\u0caf \u0cb9\u0cc6\u0cb8\u0cb0\u0cc1 \u0cac\u0ca6\u0cb2\u0cbe\u0caf\u0cbf\u0cb8\u0cbf",
+ "description": "\u0c88 \u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6\u0c97\u0cc6 \u0cb9\u0cca\u0cb8 \u0cb9\u0cc6\u0cb8\u0cb0\u0ca8\u0ccd\u0ca8\u0cc1 \u0ca8\u0cae\u0cc2\u0ca6\u0cbf\u0cb8\u0cbf",
+ "form": {
+ "name": {
+ "label": "\u0cb9\u0cc6\u0cb8\u0cb0\u0cc1",
+ "placeholder": "\u0cb9\u0cca\u0cb8 \u0cb9\u0cc6\u0cb8\u0cb0\u0ca8\u0ccd\u0ca8\u0cc1 \u0ca8\u0cae\u0cc2\u0ca6\u0cbf\u0cb8\u0cbf"
+ }
+ },
+ "success": "\u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6\u0caf \u0cb9\u0cc6\u0cb8\u0cb0\u0cc1 \u0cac\u0ca6\u0cb2\u0cbe\u0caf\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6!",
+ "inProgress": "\u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6\u0caf \u0cb9\u0cc6\u0cb8\u0cb0\u0cc1 \u0cac\u0ca6\u0cb2\u0cbe\u0caf\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cc1\u0ca4\u0ccd\u0ca4\u0cbf\u0ca6\u0cc6"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6",
+ "readme": "\u0c93\u0ca6\u0cbf",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u0cb9\u0cca\u0cb8 \u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6",
+ "dialog": {
+ "title": "\u0cb9\u0cca\u0cb8 \u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6 \u0cb0\u0c9a\u0cbf\u0cb8\u0cbf",
+ "description": "\u0c87\u0ca6\u0cc1 \u0ca8\u0cbf\u0cae\u0ccd\u0cae \u0caa\u0ccd\u0cb0\u0cb8\u0ccd\u0ca4\u0cc1\u0ca4 \u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6\u0caf \u0c87\u0ca4\u0cbf\u0cb9\u0cbe\u0cb8\u0cb5\u0ca8\u0ccd\u0ca8\u0cc1 \u0c85\u0cb3\u0cbf\u0cb8\u0cc1\u0ca4\u0ccd\u0ca4\u0ca6\u0cc6. \u0ca8\u0cc0\u0cb5\u0cc1 \u0cae\u0cc1\u0c82\u0ca6\u0cc1\u0cb5\u0cb0\u0cc6\u0caf\u0cb2\u0cc1 \u0cac\u0caf\u0cb8\u0cc1\u0cb5\u0cbf\u0cb0\u0cbe?",
+ "tooltip": "\u0cb9\u0cca\u0cb8 \u0cb8\u0c82\u0cad\u0cbe\u0cb7\u0ca3\u0cc6"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u0cb8\u0cc6\u0c9f\u0ccd\u0c9f\u0cbf\u0c82\u0c97\u0ccd\u200c\u0c97\u0cb3\u0cc1",
+ "settingsKey": "S",
+ "apiKeys": "API \u0c95\u0cc0\u0c97\u0cb3\u0cc1",
+ "logout": "\u0cb2\u0cbe\u0c97\u0ccd \u0c94\u0c9f\u0ccd"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u0c85\u0c97\u0ca4\u0ccd\u0caf\u0cb5\u0cbf\u0cb0\u0cc1\u0cb5 API \u0c95\u0cc0\u0c97\u0cb3\u0cc1",
+ "description": "\u0c88 \u0c85\u0caa\u0ccd\u0cb2\u0cbf\u0c95\u0cc7\u0cb6\u0ca8\u0ccd \u0cac\u0cb3\u0cb8\u0cb2\u0cc1, \u0c88 \u0c95\u0cc6\u0cb3\u0c97\u0cbf\u0ca8 API \u0c95\u0cc0\u0c97\u0cb3\u0cc1 \u0c85\u0c97\u0ca4\u0ccd\u0caf\u0cb5\u0cbf\u0cb0\u0cc1\u0ca4\u0ccd\u0ca4\u0cb5\u0cc6. \u0c95\u0cc0\u0c97\u0cb3\u0ca8\u0ccd\u0ca8\u0cc1 \u0ca8\u0cbf\u0cae\u0ccd\u0cae \u0cb8\u0cbe\u0ca7\u0ca8\u0ca6 \u0cb8\u0ccd\u0ca5\u0cb3\u0cc0\u0caf \u0cb8\u0c82\u0c97\u0ccd\u0cb0\u0cb9\u0ca3\u0cc6\u0caf\u0cb2\u0ccd\u0cb2\u0cbf \u0cb8\u0c82\u0c97\u0ccd\u0cb0\u0cb9\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cc1\u0ca4\u0ccd\u0ca4\u0ca6\u0cc6.",
+ "success": {
+ "saved": "\u0caf\u0cb6\u0cb8\u0ccd\u0cb5\u0cbf\u0caf\u0cbe\u0c97\u0cbf \u0c89\u0cb3\u0cbf\u0cb8\u0cb2\u0cbe\u0c97\u0cbf\u0ca6\u0cc6"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/ml.json b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/ml.json
new file mode 100644
index 00000000..f932bd3d
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/ml.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u0d31\u0d26\u0d4d\u0d26\u0d3e\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "confirm": "\u0d38\u0d4d\u0d25\u0d3f\u0d30\u0d40\u0d15\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "continue": "\u0d24\u0d41\u0d1f\u0d30\u0d41\u0d15",
+ "goBack": "\u0d24\u0d3f\u0d30\u0d3f\u0d15\u0d46 \u0d2a\u0d4b\u0d15\u0d41\u0d15",
+ "reset": "\u0d2a\u0d41\u0d28\u0d03\u0d38\u0d1c\u0d4d\u0d1c\u0d2e\u0d3e\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "submit": "\u0d38\u0d2e\u0d7c\u0d2a\u0d4d\u0d2a\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15"
+ },
+ "status": {
+ "loading": "\u0d32\u0d4b\u0d21\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d28\u0d4d\u0d28\u0d41...",
+ "error": {
+ "default": "\u0d12\u0d30\u0d41 \u0d2a\u0d3f\u0d36\u0d15\u0d4d \u0d38\u0d02\u0d2d\u0d35\u0d3f\u0d1a\u0d4d\u0d1a\u0d41",
+ "serverConnection": "\u0d38\u0d46\u0d7c\u0d35\u0d31\u0d41\u0d2e\u0d3e\u0d2f\u0d3f \u0d2c\u0d28\u0d4d\u0d27\u0d2a\u0d4d\u0d2a\u0d46\u0d1f\u0d3e\u0d7b \u0d15\u0d34\u0d3f\u0d1e\u0d4d\u0d1e\u0d3f\u0d32\u0d4d\u0d32"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u0d06\u0d2a\u0d4d\u0d2a\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d15\u0d4d\u0d15\u0d3e\u0d7b \u0d32\u0d4b\u0d17\u0d3f\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15",
+ "form": {
+ "email": {
+ "label": "\u0d07\u0d2e\u0d46\u0d2f\u0d3f\u0d7d \u0d35\u0d3f\u0d32\u0d3e\u0d38\u0d02",
+ "required": "\u0d07\u0d2e\u0d46\u0d2f\u0d3f\u0d7d \u0d12\u0d30\u0d41 \u0d06\u0d35\u0d36\u0d4d\u0d2f\u0d2e\u0d3e\u0d2f \u0d2b\u0d40\u0d7d\u0d21\u0d4d \u0d06\u0d23\u0d4d"
+ },
+ "password": {
+ "label": "\u0d2a\u0d3e\u0d38\u0d4d\u200c\u0d35\u0d47\u0d21\u0d4d",
+ "required": "\u0d2a\u0d3e\u0d38\u0d4d\u200c\u0d35\u0d47\u0d21\u0d4d \u0d12\u0d30\u0d41 \u0d06\u0d35\u0d36\u0d4d\u0d2f\u0d2e\u0d3e\u0d2f \u0d2b\u0d40\u0d7d\u0d21\u0d4d \u0d06\u0d23\u0d4d"
+ },
+ "actions": {
+ "signin": "\u0d38\u0d48\u0d7b \u0d07\u0d7b"
+ },
+ "alternativeText": {
+ "or": "\u0d05\u0d32\u0d4d\u0d32\u0d46\u0d19\u0d4d\u0d15\u0d3f\u0d7d"
+ }
+ },
+ "errors": {
+ "default": "\u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d3e\u0d7b \u0d15\u0d34\u0d3f\u0d2f\u0d41\u0d28\u0d4d\u0d28\u0d3f\u0d32\u0d4d\u0d32",
+ "signin": "\u0d2e\u0d31\u0d4d\u0d31\u0d4a\u0d30\u0d41 \u0d05\u0d15\u0d4d\u0d15\u0d57\u0d23\u0d4d\u0d1f\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d4d \u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d3e\u0d7b \u0d36\u0d4d\u0d30\u0d2e\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "oauthSignin": "\u0d2e\u0d31\u0d4d\u0d31\u0d4a\u0d30\u0d41 \u0d05\u0d15\u0d4d\u0d15\u0d57\u0d23\u0d4d\u0d1f\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d4d \u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d3e\u0d7b \u0d36\u0d4d\u0d30\u0d2e\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "redirectUriMismatch": "\u0d31\u0d40\u0d21\u0d2f\u0d31\u0d15\u0d4d\u0d1f\u0d4d URI oauth \u0d06\u0d2a\u0d4d\u0d2a\u0d4d \u0d15\u0d4b\u0d7a\u0d2b\u0d3f\u0d17\u0d31\u0d47\u0d37\u0d28\u0d41\u0d2e\u0d3e\u0d2f\u0d3f \u0d2a\u0d4a\u0d30\u0d41\u0d24\u0d4d\u0d24\u0d2a\u0d4d\u0d2a\u0d46\u0d1f\u0d41\u0d28\u0d4d\u0d28\u0d3f\u0d32\u0d4d\u0d32",
+ "oauthCallback": "\u0d2e\u0d31\u0d4d\u0d31\u0d4a\u0d30\u0d41 \u0d05\u0d15\u0d4d\u0d15\u0d57\u0d23\u0d4d\u0d1f\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d4d \u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d3e\u0d7b \u0d36\u0d4d\u0d30\u0d2e\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "oauthCreateAccount": "\u0d2e\u0d31\u0d4d\u0d31\u0d4a\u0d30\u0d41 \u0d05\u0d15\u0d4d\u0d15\u0d57\u0d23\u0d4d\u0d1f\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d4d \u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d3e\u0d7b \u0d36\u0d4d\u0d30\u0d2e\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "emailCreateAccount": "\u0d2e\u0d31\u0d4d\u0d31\u0d4a\u0d30\u0d41 \u0d05\u0d15\u0d4d\u0d15\u0d57\u0d23\u0d4d\u0d1f\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d4d \u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d3e\u0d7b \u0d36\u0d4d\u0d30\u0d2e\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "callback": "\u0d2e\u0d31\u0d4d\u0d31\u0d4a\u0d30\u0d41 \u0d05\u0d15\u0d4d\u0d15\u0d57\u0d23\u0d4d\u0d1f\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d4d \u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d3e\u0d7b \u0d36\u0d4d\u0d30\u0d2e\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "oauthAccountNotLinked": "\u0d28\u0d3f\u0d19\u0d4d\u0d19\u0d33\u0d41\u0d1f\u0d46 \u0d35\u0d4d\u0d2f\u0d15\u0d4d\u0d24\u0d3f\u0d24\u0d4d\u0d35\u0d02 \u0d38\u0d4d\u0d25\u0d3f\u0d30\u0d40\u0d15\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d3e\u0d7b, \u0d06\u0d26\u0d4d\u0d2f\u0d02 \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a \u0d05\u0d24\u0d47 \u0d05\u0d15\u0d4d\u0d15\u0d57\u0d23\u0d4d\u0d1f\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d4d \u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15",
+ "emailSignin": "\u0d07\u0d2e\u0d46\u0d2f\u0d3f\u0d7d \u0d05\u0d2f\u0d2f\u0d4d\u0d15\u0d4d\u0d15\u0d3e\u0d7b \u0d15\u0d34\u0d3f\u0d1e\u0d4d\u0d1e\u0d3f\u0d32\u0d4d\u0d32",
+ "emailVerify": "\u0d28\u0d3f\u0d19\u0d4d\u0d19\u0d33\u0d41\u0d1f\u0d46 \u0d07\u0d2e\u0d46\u0d2f\u0d3f\u0d7d \u0d2a\u0d30\u0d3f\u0d36\u0d4b\u0d27\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15, \u0d12\u0d30\u0d41 \u0d2a\u0d41\u0d24\u0d3f\u0d2f \u0d07\u0d2e\u0d46\u0d2f\u0d3f\u0d7d \u0d05\u0d2f\u0d1a\u0d4d\u0d1a\u0d3f\u0d1f\u0d4d\u0d1f\u0d41\u0d23\u0d4d\u0d1f\u0d4d",
+ "credentialsSignin": "\u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d2a\u0d30\u0d3e\u0d1c\u0d2f\u0d2a\u0d4d\u0d2a\u0d46\u0d1f\u0d4d\u0d1f\u0d41. \u0d28\u0d3f\u0d19\u0d4d\u0d19\u0d7e \u0d28\u0d7d\u0d15\u0d3f\u0d2f \u0d35\u0d3f\u0d35\u0d30\u0d19\u0d4d\u0d19\u0d7e \u0d36\u0d30\u0d3f\u0d2f\u0d3e\u0d23\u0d46\u0d28\u0d4d\u0d28\u0d4d \u0d2a\u0d30\u0d3f\u0d36\u0d4b\u0d27\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "sessionRequired": "\u0d08 \u0d2a\u0d47\u0d1c\u0d4d \u0d06\u0d15\u0d4d\u0d38\u0d38\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d3e\u0d7b \u0d26\u0d2f\u0d35\u0d3e\u0d2f\u0d3f \u0d38\u0d48\u0d7b \u0d07\u0d7b \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15"
+ }
+ },
+ "provider": {
+ "continue": "{{provider}} \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d4d \u0d24\u0d41\u0d1f\u0d30\u0d41\u0d15"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u0d28\u0d3f\u0d19\u0d4d\u0d19\u0d33\u0d41\u0d1f\u0d46 \u0d38\u0d28\u0d4d\u0d26\u0d47\u0d36\u0d02 \u0d07\u0d35\u0d3f\u0d1f\u0d46 \u0d1f\u0d48\u0d2a\u0d4d\u0d2a\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15...",
+ "actions": {
+ "send": "\u0d38\u0d28\u0d4d\u0d26\u0d47\u0d36\u0d02 \u0d05\u0d2f\u0d2f\u0d4d\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "stop": "\u0d1f\u0d3e\u0d38\u0d4d\u0d15\u0d4d \u0d28\u0d3f\u0d7c\u0d24\u0d4d\u0d24\u0d41\u0d15",
+ "attachFiles": "\u0d2b\u0d2f\u0d32\u0d41\u0d15\u0d7e \u0d05\u0d31\u0d4d\u0d31\u0d3e\u0d1a\u0d4d\u0d1a\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15"
+ }
+ },
+ "speech": {
+ "start": "\u0d31\u0d46\u0d15\u0d4d\u0d15\u0d4b\u0d7c\u0d21\u0d3f\u0d02\u0d17\u0d4d \u0d06\u0d30\u0d02\u0d2d\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "stop": "\u0d31\u0d46\u0d15\u0d4d\u0d15\u0d4b\u0d7c\u0d21\u0d3f\u0d02\u0d17\u0d4d \u0d28\u0d3f\u0d7c\u0d24\u0d4d\u0d24\u0d41\u0d15",
+ "connecting": "\u0d2c\u0d28\u0d4d\u0d27\u0d3f\u0d2a\u0d4d\u0d2a\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d28\u0d4d\u0d28\u0d41"
+ },
+ "fileUpload": {
+ "dragDrop": "\u0d2b\u0d2f\u0d32\u0d41\u0d15\u0d7e \u0d07\u0d35\u0d3f\u0d1f\u0d46 \u0d35\u0d32\u0d3f\u0d1a\u0d4d\u0d1a\u0d3f\u0d1f\u0d41\u0d15",
+ "browse": "\u0d2b\u0d2f\u0d32\u0d41\u0d15\u0d7e \u0d24\u0d3f\u0d30\u0d2f\u0d41\u0d15",
+ "sizeLimit": "\u0d2a\u0d30\u0d3f\u0d27\u0d3f:",
+ "errors": {
+ "failed": "\u0d05\u0d2a\u0d4d\u200c\u0d32\u0d4b\u0d21\u0d4d \u0d2a\u0d30\u0d3e\u0d1c\u0d2f\u0d2a\u0d4d\u0d2a\u0d46\u0d1f\u0d4d\u0d1f\u0d41",
+ "cancelled": "\u0d05\u0d2a\u0d4d\u200c\u0d32\u0d4b\u0d21\u0d4d \u0d31\u0d26\u0d4d\u0d26\u0d3e\u0d15\u0d4d\u0d15\u0d3f"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d28\u0d4d\u0d28\u0d41",
+ "used": "\u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d41"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u0d15\u0d4d\u0d32\u0d3f\u0d2a\u0d4d\u0d2a\u0d4d\u0d2c\u0d4b\u0d7c\u0d21\u0d3f\u0d32\u0d47\u0d15\u0d4d\u0d15\u0d4d \u0d2a\u0d15\u0d7c\u0d24\u0d4d\u0d24\u0d41\u0d15",
+ "success": "\u0d2a\u0d15\u0d7c\u0d24\u0d4d\u0d24\u0d3f!"
+ }
+ },
+ "feedback": {
+ "positive": "\u0d38\u0d39\u0d3e\u0d2f\u0d15\u0d30\u0d02",
+ "negative": "\u0d38\u0d39\u0d3e\u0d2f\u0d15\u0d30\u0d2e\u0d32\u0d4d\u0d32",
+ "edit": "\u0d2b\u0d40\u0d21\u0d4d\u0d2c\u0d3e\u0d15\u0d4d\u0d15\u0d4d \u0d0e\u0d21\u0d3f\u0d31\u0d4d\u0d31\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15",
+ "dialog": {
+ "title": "\u0d12\u0d30\u0d41 \u0d15\u0d2e\u0d28\u0d4d\u0d31\u0d4d \u0d1a\u0d47\u0d7c\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "submit": "\u0d2b\u0d40\u0d21\u0d4d\u0d2c\u0d3e\u0d15\u0d4d\u0d15\u0d4d \u0d38\u0d2e\u0d7c\u0d2a\u0d4d\u0d2a\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15"
+ },
+ "status": {
+ "updating": "\u0d05\u0d2a\u0d4d\u0d21\u0d47\u0d31\u0d4d\u0d31\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d28\u0d4d\u0d28\u0d41",
+ "updated": "\u0d2b\u0d40\u0d21\u0d4d\u0d2c\u0d3e\u0d15\u0d4d\u0d15\u0d4d \u0d05\u0d2a\u0d4d\u0d21\u0d47\u0d31\u0d4d\u0d31\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d24\u0d41"
+ }
+ }
+ },
+ "history": {
+ "title": "\u0d05\u0d35\u0d38\u0d3e\u0d28 \u0d07\u0d7b\u0d2a\u0d41\u0d1f\u0d4d\u0d1f\u0d41\u0d15\u0d7e",
+ "empty": "\u0d12\u0d28\u0d4d\u0d28\u0d41\u0d2e\u0d3f\u0d32\u0d4d\u0d32...",
+ "show": "\u0d39\u0d3f\u0d38\u0d4d\u0d31\u0d4d\u0d31\u0d31\u0d3f \u0d15\u0d3e\u0d23\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15"
+ },
+ "settings": {
+ "title": "\u0d15\u0d4d\u0d30\u0d2e\u0d40\u0d15\u0d30\u0d23\u0d19\u0d4d\u0d19\u0d7e \u0d2a\u0d3e\u0d28\u0d7d"
+ },
+ "watermark": "\u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d1a\u0d4d\u0d1a\u0d4d \u0d28\u0d3f\u0d7c\u0d2e\u0d4d\u0d2e\u0d3f\u0d1a\u0d4d\u0d1a\u0d24\u0d4d"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u0d2e\u0d41\u0d7b \u0d1a\u0d3e\u0d31\u0d4d\u0d31\u0d41\u0d15\u0d7e",
+ "filters": {
+ "search": "\u0d24\u0d3f\u0d30\u0d2f\u0d41\u0d15",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u0d07\u0d28\u0d4d\u0d28\u0d4d",
+ "yesterday": "\u0d07\u0d28\u0d4d\u0d28\u0d32\u0d46",
+ "previous7days": "\u0d15\u0d34\u0d3f\u0d1e\u0d4d\u0d1e 7 \u0d26\u0d3f\u0d35\u0d38\u0d02",
+ "previous30days": "\u0d15\u0d34\u0d3f\u0d1e\u0d4d\u0d1e 30 \u0d26\u0d3f\u0d35\u0d38\u0d02"
+ },
+ "empty": "\u0d24\u0d4d\u0d30\u0d46\u0d21\u0d41\u0d15\u0d7e \u0d15\u0d23\u0d4d\u0d1f\u0d46\u0d24\u0d4d\u0d24\u0d3f\u0d2f\u0d3f\u0d32\u0d4d\u0d32",
+ "actions": {
+ "close": "\u0d38\u0d48\u0d21\u0d4d\u0d2c\u0d3e\u0d7c \u0d05\u0d1f\u0d2f\u0d4d\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "open": "\u0d38\u0d48\u0d21\u0d4d\u0d2c\u0d3e\u0d7c \u0d24\u0d41\u0d31\u0d15\u0d4d\u0d15\u0d41\u0d15"
+ }
+ },
+ "thread": {
+ "untitled": "\u0d2a\u0d47\u0d30\u0d3f\u0d32\u0d4d\u0d32\u0d3e\u0d24\u0d4d\u0d24 \u0d38\u0d02\u0d2d\u0d3e\u0d37\u0d23\u0d02",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u0d21\u0d3f\u0d32\u0d40\u0d31\u0d4d\u0d31\u0d4d \u0d38\u0d4d\u0d25\u0d3f\u0d30\u0d40\u0d15\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "description": "\u0d07\u0d24\u0d4d \u0d24\u0d4d\u0d30\u0d46\u0d21\u0d41\u0d02 \u0d05\u0d24\u0d3f\u0d28\u0d4d\u0d31\u0d46 \u0d38\u0d28\u0d4d\u0d26\u0d47\u0d36\u0d19\u0d4d\u0d19\u0d33\u0d41\u0d02 \u0d18\u0d1f\u0d15\u0d19\u0d4d\u0d19\u0d33\u0d41\u0d02 \u0d21\u0d3f\u0d32\u0d40\u0d31\u0d4d\u0d31\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d02. \u0d08 \u0d2a\u0d4d\u0d30\u0d35\u0d7c\u0d24\u0d4d\u0d24\u0d3f \u0d2a\u0d34\u0d2f\u0d2a\u0d1f\u0d3f\u0d2f\u0d3e\u0d15\u0d4d\u0d15\u0d3e\u0d7b \u0d15\u0d34\u0d3f\u0d2f\u0d3f\u0d32\u0d4d\u0d32",
+ "success": "\u0d1a\u0d3e\u0d31\u0d4d\u0d31\u0d4d \u0d21\u0d3f\u0d32\u0d40\u0d31\u0d4d\u0d31\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d24\u0d41",
+ "inProgress": "\u0d1a\u0d3e\u0d31\u0d4d\u0d31\u0d4d \u0d21\u0d3f\u0d32\u0d40\u0d31\u0d4d\u0d31\u0d4d \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d28\u0d4d\u0d28\u0d41"
+ },
+ "rename": {
+ "title": "\u0d24\u0d4d\u0d30\u0d46\u0d21\u0d4d \u0d2a\u0d41\u0d28\u0d7c\u0d28\u0d3e\u0d2e\u0d15\u0d30\u0d23\u0d02 \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d15",
+ "description": "\u0d08 \u0d24\u0d4d\u0d30\u0d46\u0d21\u0d3f\u0d28\u0d4d \u0d12\u0d30\u0d41 \u0d2a\u0d41\u0d24\u0d3f\u0d2f \u0d2a\u0d47\u0d30\u0d4d \u0d28\u0d7d\u0d15\u0d41\u0d15",
+ "form": {
+ "name": {
+ "label": "\u0d2a\u0d47\u0d30\u0d4d",
+ "placeholder": "\u0d2a\u0d41\u0d24\u0d3f\u0d2f \u0d2a\u0d47\u0d30\u0d4d \u0d28\u0d7d\u0d15\u0d41\u0d15"
+ }
+ },
+ "success": "\u0d24\u0d4d\u0d30\u0d46\u0d21\u0d4d \u0d2a\u0d41\u0d28\u0d7c\u0d28\u0d3e\u0d2e\u0d15\u0d30\u0d23\u0d02 \u0d1a\u0d46\u0d2f\u0d4d\u0d24\u0d41!",
+ "inProgress": "\u0d24\u0d4d\u0d30\u0d46\u0d21\u0d4d \u0d2a\u0d41\u0d28\u0d7c\u0d28\u0d3e\u0d2e\u0d15\u0d30\u0d23\u0d02 \u0d1a\u0d46\u0d2f\u0d4d\u0d2f\u0d41\u0d28\u0d4d\u0d28\u0d41"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u0d1a\u0d3e\u0d31\u0d4d\u0d31\u0d4d",
+ "readme": "\u0d35\u0d3e\u0d2f\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u0d2a\u0d41\u0d24\u0d3f\u0d2f \u0d1a\u0d3e\u0d31\u0d4d\u0d31\u0d4d",
+ "dialog": {
+ "title": "\u0d2a\u0d41\u0d24\u0d3f\u0d2f \u0d1a\u0d3e\u0d31\u0d4d\u0d31\u0d4d \u0d38\u0d43\u0d37\u0d4d\u0d1f\u0d3f\u0d15\u0d4d\u0d15\u0d41\u0d15",
+ "description": "\u0d07\u0d24\u0d4d \u0d28\u0d3f\u0d19\u0d4d\u0d19\u0d33\u0d41\u0d1f\u0d46 \u0d28\u0d3f\u0d32\u0d35\u0d3f\u0d32\u0d46 \u0d1a\u0d3e\u0d31\u0d4d\u0d31\u0d4d \u0d39\u0d3f\u0d38\u0d4d\u0d31\u0d4d\u0d31\u0d31\u0d3f \u0d2e\u0d3e\u0d2f\u0d4d\u0d15\u0d4d\u0d15\u0d41\u0d02. \u0d24\u0d41\u0d1f\u0d30\u0d3e\u0d7b \u0d24\u0d3e\u0d7d\u0d2a\u0d4d\u0d2a\u0d30\u0d4d\u0d2f\u0d2e\u0d41\u0d23\u0d4d\u0d1f\u0d4b?",
+ "tooltip": "\u0d2a\u0d41\u0d24\u0d3f\u0d2f \u0d1a\u0d3e\u0d31\u0d4d\u0d31\u0d4d"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u0d15\u0d4d\u0d30\u0d2e\u0d40\u0d15\u0d30\u0d23\u0d19\u0d4d\u0d19\u0d7e",
+ "settingsKey": "S",
+ "apiKeys": "API \u0d15\u0d40\u0d15\u0d7e",
+ "logout": "\u0d32\u0d4b\u0d17\u0d4d\u0d14\u0d1f\u0d4d\u0d1f\u0d4d"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u0d06\u0d35\u0d36\u0d4d\u0d2f\u0d2e\u0d3e\u0d2f API \u0d15\u0d40\u0d15\u0d7e",
+ "description": "\u0d08 \u0d06\u0d2a\u0d4d\u0d2a\u0d4d \u0d09\u0d2a\u0d2f\u0d4b\u0d17\u0d3f\u0d15\u0d4d\u0d15\u0d3e\u0d7b, \u0d24\u0d3e\u0d34\u0d46\u0d2a\u0d4d\u0d2a\u0d31\u0d2f\u0d41\u0d28\u0d4d\u0d28 API \u0d15\u0d40\u0d15\u0d7e \u0d06\u0d35\u0d36\u0d4d\u0d2f\u0d2e\u0d3e\u0d23\u0d4d. \u0d15\u0d40\u0d15\u0d7e \u0d28\u0d3f\u0d19\u0d4d\u0d19\u0d33\u0d41\u0d1f\u0d46 \u0d09\u0d2a\u0d15\u0d30\u0d23\u0d24\u0d4d\u0d24\u0d3f\u0d28\u0d4d\u0d31\u0d46 \u0d32\u0d4b\u0d15\u0d4d\u0d15\u0d7d \u0d38\u0d4d\u0d31\u0d4d\u0d31\u0d4b\u0d31\u0d47\u0d1c\u0d3f\u0d7d \u0d38\u0d02\u0d2d\u0d30\u0d3f\u0d15\u0d4d\u0d15\u0d2a\u0d4d\u0d2a\u0d46\u0d1f\u0d41\u0d28\u0d4d\u0d28\u0d41.",
+ "success": {
+ "saved": "\u0d35\u0d3f\u0d1c\u0d2f\u0d15\u0d30\u0d2e\u0d3e\u0d2f\u0d3f \u0d38\u0d02\u0d30\u0d15\u0d4d\u0d37\u0d3f\u0d1a\u0d4d\u0d1a\u0d41"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/mr.json b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/mr.json
new file mode 100644
index 00000000..04a990b8
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/mr.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u0930\u0926\u094d\u0926 \u0915\u0930\u093e",
+ "confirm": "\u092a\u0941\u0937\u094d\u091f\u0940 \u0915\u0930\u093e",
+ "continue": "\u092a\u0941\u0922\u0947 \u091c\u093e",
+ "goBack": "\u092e\u093e\u0917\u0947 \u091c\u093e",
+ "reset": "\u0930\u0940\u0938\u0947\u091f \u0915\u0930\u093e",
+ "submit": "\u0938\u092c\u092e\u093f\u091f \u0915\u0930\u093e"
+ },
+ "status": {
+ "loading": "\u0932\u094b\u0921 \u0915\u0930\u0924 \u0906\u0939\u0947...",
+ "error": {
+ "default": "\u090f\u0915 \u0924\u094d\u0930\u0941\u091f\u0940 \u0906\u0932\u0940",
+ "serverConnection": "\u0938\u0930\u094d\u0935\u094d\u0939\u0930\u0936\u0940 \u0915\u0928\u0947\u0915\u094d\u091f \u0939\u094b\u090a \u0936\u0915\u0932\u0947 \u0928\u093e\u0939\u0940"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u0905\u0945\u092a \u0935\u093e\u092a\u0930\u0923\u094d\u092f\u093e\u0938\u093e\u0920\u0940 \u0932\u0949\u0917\u093f\u0928 \u0915\u0930\u093e",
+ "form": {
+ "email": {
+ "label": "\u0908\u092e\u0947\u0932 \u092a\u0924\u094d\u0924\u093e",
+ "required": "\u0908\u092e\u0947\u0932 \u0906\u0935\u0936\u094d\u092f\u0915 \u0906\u0939\u0947"
+ },
+ "password": {
+ "label": "\u092a\u093e\u0938\u0935\u0930\u094d\u0921",
+ "required": "\u092a\u093e\u0938\u0935\u0930\u094d\u0921 \u0906\u0935\u0936\u094d\u092f\u0915 \u0906\u0939\u0947"
+ },
+ "actions": {
+ "signin": "\u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u093e"
+ },
+ "alternativeText": {
+ "or": "\u0915\u093f\u0902\u0935\u093e"
+ }
+ },
+ "errors": {
+ "default": "\u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0942 \u0936\u0915\u0924 \u0928\u093e\u0939\u0940",
+ "signin": "\u0935\u0947\u0917\u0933\u094d\u092f\u093e \u0916\u093e\u0924\u094d\u092f\u093e\u0928\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0923\u094d\u092f\u093e\u091a\u093e \u092a\u094d\u0930\u092f\u0924\u094d\u0928 \u0915\u0930\u093e",
+ "oauthSignin": "\u0935\u0947\u0917\u0933\u094d\u092f\u093e \u0916\u093e\u0924\u094d\u092f\u093e\u0928\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0923\u094d\u092f\u093e\u091a\u093e \u092a\u094d\u0930\u092f\u0924\u094d\u0928 \u0915\u0930\u093e",
+ "redirectUriMismatch": "\u0930\u0940\u0921\u093e\u092f\u0930\u0947\u0915\u094d\u091f URI \u0913\u0925 \u0905\u0945\u092a \u0915\u0949\u0928\u094d\u092b\u093f\u0917\u0930\u0947\u0936\u0928\u0936\u0940 \u091c\u0941\u0933\u0924 \u0928\u093e\u0939\u0940",
+ "oauthCallback": "\u0935\u0947\u0917\u0933\u094d\u092f\u093e \u0916\u093e\u0924\u094d\u092f\u093e\u0928\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0923\u094d\u092f\u093e\u091a\u093e \u092a\u094d\u0930\u092f\u0924\u094d\u0928 \u0915\u0930\u093e",
+ "oauthCreateAccount": "\u0935\u0947\u0917\u0933\u094d\u092f\u093e \u0916\u093e\u0924\u094d\u092f\u093e\u0928\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0923\u094d\u092f\u093e\u091a\u093e \u092a\u094d\u0930\u092f\u0924\u094d\u0928 \u0915\u0930\u093e",
+ "emailCreateAccount": "\u0935\u0947\u0917\u0933\u094d\u092f\u093e \u0916\u093e\u0924\u094d\u092f\u093e\u0928\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0923\u094d\u092f\u093e\u091a\u093e \u092a\u094d\u0930\u092f\u0924\u094d\u0928 \u0915\u0930\u093e",
+ "callback": "\u0935\u0947\u0917\u0933\u094d\u092f\u093e \u0916\u093e\u0924\u094d\u092f\u093e\u0928\u0947 \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u0923\u094d\u092f\u093e\u091a\u093e \u092a\u094d\u0930\u092f\u0924\u094d\u0928 \u0915\u0930\u093e",
+ "oauthAccountNotLinked": "\u0924\u0941\u092e\u091a\u0940 \u0913\u0933\u0916 \u092a\u091f\u0935\u0923\u094d\u092f\u093e\u0938\u093e\u0920\u0940, \u092e\u0942\u0933 \u0935\u093e\u092a\u0930\u0932\u0947\u0932\u094d\u092f\u093e \u0916\u093e\u0924\u094d\u092f\u093e\u0928\u0947\u091a \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u093e",
+ "emailSignin": "\u0908\u092e\u0947\u0932 \u092a\u093e\u0920\u0935\u0942 \u0936\u0915\u0932\u0947 \u0928\u093e\u0939\u0940",
+ "emailVerify": "\u0915\u0943\u092a\u092f\u093e \u0924\u0941\u092e\u091a\u093e \u0908\u092e\u0947\u0932 \u0924\u092a\u093e\u0938\u093e, \u0928\u0935\u0940\u0928 \u0908\u092e\u0947\u0932 \u092a\u093e\u0920\u0935\u0932\u093e \u0917\u0947\u0932\u093e \u0906\u0939\u0947",
+ "credentialsSignin": "\u0938\u093e\u0907\u0928 \u0907\u0928 \u0905\u092f\u0936\u0938\u094d\u0935\u0940. \u0924\u0941\u092e\u094d\u0939\u0940 \u0926\u093f\u0932\u0947\u0932\u0940 \u092e\u093e\u0939\u093f\u0924\u0940 \u092f\u094b\u0917\u094d\u092f \u0906\u0939\u0947 \u0915\u093e \u0924\u0947 \u0924\u092a\u093e\u0938\u093e",
+ "sessionRequired": "\u092f\u093e \u092a\u0943\u0937\u094d\u0920\u093e\u0935\u0930 \u092a\u094d\u0930\u0935\u0947\u0936 \u0915\u0930\u0923\u094d\u092f\u093e\u0938\u093e\u0920\u0940 \u0915\u0943\u092a\u092f\u093e \u0938\u093e\u0907\u0928 \u0907\u0928 \u0915\u0930\u093e"
+ }
+ },
+ "provider": {
+ "continue": "{{provider}} \u0938\u0939 \u092a\u0941\u0922\u0947 \u091c\u093e"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u0924\u0941\u092e\u091a\u093e \u0938\u0902\u0926\u0947\u0936 \u092f\u0947\u0925\u0947 \u091f\u093e\u0907\u092a \u0915\u0930\u093e...",
+ "actions": {
+ "send": "\u0938\u0902\u0926\u0947\u0936 \u092a\u093e\u0920\u0935\u093e",
+ "stop": "\u0915\u093e\u0930\u094d\u092f \u0925\u093e\u0902\u092c\u0935\u093e",
+ "attachFiles": "\u092b\u093e\u0907\u0932\u094d\u0938 \u091c\u094b\u0921\u093e"
+ }
+ },
+ "speech": {
+ "start": "\u0930\u0947\u0915\u0949\u0930\u094d\u0921\u093f\u0902\u0917 \u0938\u0941\u0930\u0942 \u0915\u0930\u093e",
+ "stop": "\u0930\u0947\u0915\u0949\u0930\u094d\u0921\u093f\u0902\u0917 \u0925\u093e\u0902\u092c\u0935\u093e",
+ "connecting": "\u0915\u0928\u0947\u0915\u094d\u091f \u0915\u0930\u0924 \u0906\u0939\u0947"
+ },
+ "fileUpload": {
+ "dragDrop": "\u092b\u093e\u0907\u0932\u094d\u0938 \u092f\u0947\u0925\u0947 \u0921\u094d\u0930\u0945\u0917 \u0906\u0923\u093f \u0921\u094d\u0930\u0949\u092a \u0915\u0930\u093e",
+ "browse": "\u092b\u093e\u0907\u0932\u094d\u0938 \u092c\u094d\u0930\u093e\u0909\u091d \u0915\u0930\u093e",
+ "sizeLimit": "\u092e\u0930\u094d\u092f\u093e\u0926\u093e:",
+ "errors": {
+ "failed": "\u0905\u092a\u0932\u094b\u0921 \u0905\u092f\u0936\u0938\u094d\u0935\u0940",
+ "cancelled": "\u092f\u093e\u0902\u091a\u0947 \u0905\u092a\u0932\u094b\u0921 \u0930\u0926\u094d\u0926 \u0915\u0947\u0932\u0947"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u0935\u093e\u092a\u0930\u0924 \u0906\u0939\u0947",
+ "used": "\u0935\u093e\u092a\u0930\u0932\u0947"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u0915\u094d\u0932\u093f\u092a\u092c\u094b\u0930\u094d\u0921\u0935\u0930 \u0915\u0949\u092a\u0940 \u0915\u0930\u093e",
+ "success": "\u0915\u0949\u092a\u0940 \u0915\u0947\u0932\u0947!"
+ }
+ },
+ "feedback": {
+ "positive": "\u0909\u092a\u092f\u0941\u0915\u094d\u0924",
+ "negative": "\u0909\u092a\u092f\u0941\u0915\u094d\u0924 \u0928\u093e\u0939\u0940",
+ "edit": "\u092b\u0940\u0921\u092c\u0945\u0915 \u0938\u0902\u092a\u093e\u0926\u093f\u0924 \u0915\u0930\u093e",
+ "dialog": {
+ "title": "\u091f\u093f\u092a\u094d\u092a\u0923\u0940 \u091c\u094b\u0921\u093e",
+ "submit": "\u092b\u0940\u0921\u092c\u0945\u0915 \u0938\u092c\u092e\u093f\u091f \u0915\u0930\u093e"
+ },
+ "status": {
+ "updating": "\u0905\u092a\u0921\u0947\u091f \u0915\u0930\u0924 \u0906\u0939\u0947",
+ "updated": "\u092b\u0940\u0921\u092c\u0945\u0915 \u0905\u092a\u0921\u0947\u091f \u0915\u0947\u0932\u0947"
+ }
+ }
+ },
+ "history": {
+ "title": "\u0936\u0947\u0935\u091f\u091a\u0947 \u0907\u0928\u092a\u0941\u091f",
+ "empty": "\u0930\u093f\u0915\u093e\u092e\u0947 \u0906\u0939\u0947...",
+ "show": "\u0907\u0924\u093f\u0939\u093e\u0938 \u0926\u093e\u0916\u0935\u093e"
+ },
+ "settings": {
+ "title": "\u0938\u0947\u091f\u093f\u0902\u0917\u094d\u091c \u092a\u0945\u0928\u0932"
+ },
+ "watermark": "\u0938\u0939 \u092c\u0928\u0935\u0932\u0947"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u092e\u093e\u0917\u0940\u0932 \u091a\u0945\u091f\u094d\u0938",
+ "filters": {
+ "search": "\u0936\u094b\u0927\u093e",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u0906\u091c",
+ "yesterday": "\u0915\u093e\u0932",
+ "previous7days": "\u092e\u093e\u0917\u0940\u0932 7 \u0926\u093f\u0935\u0938",
+ "previous30days": "\u092e\u093e\u0917\u0940\u0932 30 \u0926\u093f\u0935\u0938"
+ },
+ "empty": "\u0915\u094b\u0923\u0924\u0947\u0939\u0940 \u0925\u094d\u0930\u0947\u0921 \u0938\u093e\u092a\u0921\u0932\u0947 \u0928\u093e\u0939\u0940\u0924",
+ "actions": {
+ "close": "\u0938\u093e\u0907\u0921\u092c\u093e\u0930 \u092c\u0902\u0926 \u0915\u0930\u093e",
+ "open": "\u0938\u093e\u0907\u0921\u092c\u093e\u0930 \u0909\u0918\u0921\u093e"
+ }
+ },
+ "thread": {
+ "untitled": "\u0936\u0940\u0930\u094d\u0937\u0915\u0935\u093f\u0930\u0939\u093f\u0924 \u0938\u0902\u092d\u093e\u0937\u0923",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u0939\u091f\u0935\u093f\u0923\u094d\u092f\u093e\u091a\u0940 \u092a\u0941\u0937\u094d\u091f\u0940 \u0915\u0930\u093e",
+ "description": "\u0939\u0947 \u0925\u094d\u0930\u0947\u0921 \u0906\u0923\u093f \u0924\u094d\u092f\u093e\u091a\u0947 \u0938\u0902\u0926\u0947\u0936 \u0935 \u0918\u091f\u0915 \u0939\u091f\u0935\u0947\u0932. \u0939\u0940 \u0915\u094d\u0930\u093f\u092f\u093e \u092a\u0942\u0930\u094d\u0935\u0935\u0924 \u0915\u0947\u0932\u0940 \u091c\u093e\u090a \u0936\u0915\u0924 \u0928\u093e\u0939\u0940",
+ "success": "\u091a\u0945\u091f \u0939\u091f\u0935\u0932\u093e",
+ "inProgress": "\u091a\u0945\u091f \u0939\u091f\u0935\u0924 \u0906\u0939\u0947"
+ },
+ "rename": {
+ "title": "\u0925\u094d\u0930\u0947\u0921\u091a\u0947 \u0928\u093e\u0935 \u092c\u0926\u0932\u093e",
+ "description": "\u092f\u093e \u0925\u094d\u0930\u0947\u0921\u0938\u093e\u0920\u0940 \u0928\u0935\u0940\u0928 \u0928\u093e\u0935 \u092a\u094d\u0930\u0935\u093f\u0937\u094d\u091f \u0915\u0930\u093e",
+ "form": {
+ "name": {
+ "label": "\u0928\u093e\u0935",
+ "placeholder": "\u0928\u0935\u0940\u0928 \u0928\u093e\u0935 \u092a\u094d\u0930\u0935\u093f\u0937\u094d\u091f \u0915\u0930\u093e"
+ }
+ },
+ "success": "\u0925\u094d\u0930\u0947\u0921\u091a\u0947 \u0928\u093e\u0935 \u092c\u0926\u0932\u0932\u0947!",
+ "inProgress": "\u0925\u094d\u0930\u0947\u0921\u091a\u0947 \u0928\u093e\u0935 \u092c\u0926\u0932\u0924 \u0906\u0939\u0947"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u091a\u0945\u091f",
+ "readme": "\u0935\u093e\u091a\u093e",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u0928\u0935\u0940\u0928 \u091a\u0945\u091f",
+ "dialog": {
+ "title": "\u0928\u0935\u0940\u0928 \u091a\u0945\u091f \u0924\u092f\u093e\u0930 \u0915\u0930\u093e",
+ "description": "\u0939\u0947 \u0924\u0941\u092e\u091a\u093e \u0938\u0927\u094d\u092f\u093e\u091a\u093e \u091a\u0945\u091f \u0907\u0924\u093f\u0939\u093e\u0938 \u0938\u093e\u092b \u0915\u0930\u0947\u0932. \u0924\u0941\u092e\u094d\u0939\u093e\u0932\u093e \u0916\u093e\u0924\u094d\u0930\u0940 \u0906\u0939\u0947 \u0915\u0940 \u0924\u0941\u092e\u094d\u0939\u0940 \u092a\u0941\u0922\u0947 \u091c\u093e\u090a \u0907\u091a\u094d\u091b\u093f\u0924\u093e?",
+ "tooltip": "\u0928\u0935\u0940\u0928 \u091a\u0945\u091f"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u0938\u0947\u091f\u093f\u0902\u0917\u094d\u091c",
+ "settingsKey": "S",
+ "apiKeys": "API \u0915\u0940\u091c",
+ "logout": "\u0932\u0949\u0917\u0906\u0909\u091f"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u0906\u0935\u0936\u094d\u092f\u0915 API \u0915\u0940\u091c",
+ "description": "\u0939\u0947 \u0905\u0945\u092a \u0935\u093e\u092a\u0930\u0923\u094d\u092f\u093e\u0938\u093e\u0920\u0940 \u0916\u093e\u0932\u0940\u0932 API \u0915\u0940\u091c \u0906\u0935\u0936\u094d\u092f\u0915 \u0906\u0939\u0947\u0924. \u0915\u0940\u091c \u0924\u0941\u092e\u091a\u094d\u092f\u093e \u0921\u093f\u0935\u094d\u0939\u093e\u0907\u0938\u091a\u094d\u092f\u093e \u0932\u094b\u0915\u0932 \u0938\u094d\u091f\u094b\u0930\u0947\u091c\u092e\u0927\u094d\u092f\u0947 \u0938\u093e\u0920\u0935\u0932\u094d\u092f\u093e \u091c\u093e\u0924\u093e\u0924.",
+ "success": {
+ "saved": "\u092f\u0936\u0938\u094d\u0935\u0940\u0930\u093f\u0924\u094d\u092f\u093e \u091c\u0924\u0928 \u0915\u0947\u0932\u0947"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/nl.json b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/nl.json
new file mode 100644
index 00000000..ed331152
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/nl.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "Annuleren",
+ "confirm": "Bevestigen",
+ "continue": "Doorgaan",
+ "goBack": "Terug",
+ "reset": "Herstellen",
+ "submit": "Versturen"
+ },
+ "status": {
+ "loading": "Laden...",
+ "error": {
+ "default": "Er is een fout opgetreden",
+ "serverConnection": "Kon geen verbinding maken met de server"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "Inloggen om toegang te krijgen tot de app",
+ "form": {
+ "email": {
+ "label": "E-mailadres",
+ "required": "e-mail is een verplicht veld"
+ },
+ "password": {
+ "label": "Wachtwoord",
+ "required": "wachtwoord is een verplicht veld"
+ },
+ "actions": {
+ "signin": "Inloggen"
+ },
+ "alternativeText": {
+ "or": "OF"
+ }
+ },
+ "errors": {
+ "default": "Kan niet inloggen",
+ "signin": "Probeer in te loggen met een ander account",
+ "oauthSignin": "Probeer in te loggen met een ander account",
+ "redirectUriMismatch": "De redirect URI komt niet overeen met de oauth app configuratie",
+ "oauthCallback": "Probeer in te loggen met een ander account",
+ "oauthCreateAccount": "Probeer in te loggen met een ander account",
+ "emailCreateAccount": "Probeer in te loggen met een ander account",
+ "callback": "Probeer in te loggen met een ander account",
+ "oauthAccountNotLinked": "Om je identiteit te bevestigen, log in met hetzelfde account dat je oorspronkelijk hebt gebruikt",
+ "emailSignin": "De e-mail kon niet worden verzonden",
+ "emailVerify": "Verifieer je e-mail, er is een nieuwe e-mail verzonden",
+ "credentialsSignin": "Inloggen mislukt. Controleer of de ingevoerde gegevens correct zijn",
+ "sessionRequired": "Log in om toegang te krijgen tot deze pagina"
+ }
+ },
+ "provider": {
+ "continue": "Doorgaan met {{provider}}"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "Typ hier je bericht...",
+ "actions": {
+ "send": "Bericht versturen",
+ "stop": "Taak stoppen",
+ "attachFiles": "Bestanden bijvoegen"
+ }
+ },
+ "speech": {
+ "start": "Start opname",
+ "stop": "Stop opname",
+ "connecting": "Verbinden"
+ },
+ "fileUpload": {
+ "dragDrop": "Sleep bestanden hierheen",
+ "browse": "Bestanden zoeken",
+ "sizeLimit": "Limiet:",
+ "errors": {
+ "failed": "Uploaden mislukt",
+ "cancelled": "Upload geannuleerd van"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "In gebruik",
+ "used": "Gebruikt"
+ },
+ "actions": {
+ "copy": {
+ "button": "Kopi\u00ebren naar klembord",
+ "success": "Gekopieerd!"
+ }
+ },
+ "feedback": {
+ "positive": "Nuttig",
+ "negative": "Niet nuttig",
+ "edit": "Feedback bewerken",
+ "dialog": {
+ "title": "Voeg een opmerking toe",
+ "submit": "Feedback versturen"
+ },
+ "status": {
+ "updating": "Bijwerken",
+ "updated": "Feedback bijgewerkt"
+ }
+ }
+ },
+ "history": {
+ "title": "Laatste invoer",
+ "empty": "Zo leeg...",
+ "show": "Toon geschiedenis"
+ },
+ "settings": {
+ "title": "Instellingenpaneel"
+ },
+ "watermark": "Gebouwd met"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "Eerdere chats",
+ "filters": {
+ "search": "Zoeken",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "Vandaag",
+ "yesterday": "Gisteren",
+ "previous7days": "Afgelopen 7 dagen",
+ "previous30days": "Afgelopen 30 dagen"
+ },
+ "empty": "Geen gesprekken gevonden",
+ "actions": {
+ "close": "Zijbalk sluiten",
+ "open": "Zijbalk openen"
+ }
+ },
+ "thread": {
+ "untitled": "Naamloos gesprek",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "Verwijdering bevestigen",
+ "description": "Dit zal het gesprek en bijbehorende berichten en elementen verwijderen. Deze actie kan niet ongedaan worden gemaakt",
+ "success": "Chat verwijderd",
+ "inProgress": "Chat verwijderen"
+ },
+ "rename": {
+ "title": "Gesprek hernoemen",
+ "description": "Voer een nieuwe naam in voor dit gesprek",
+ "form": {
+ "name": {
+ "label": "Naam",
+ "placeholder": "Voer nieuwe naam in"
+ }
+ },
+ "success": "Gesprek hernoemd!",
+ "inProgress": "Gesprek hernoemen"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "Chat",
+ "readme": "Leesmij",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "Nieuwe chat",
+ "dialog": {
+ "title": "Nieuwe chat aanmaken",
+ "description": "Dit zal je huidige chatgeschiedenis wissen. Weet je zeker dat je door wilt gaan?",
+ "tooltip": "Nieuwe chat"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "Instellingen",
+ "settingsKey": "I",
+ "apiKeys": "API-sleutels",
+ "logout": "Uitloggen"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "Vereiste API-sleutels",
+ "description": "Om deze app te gebruiken zijn de volgende API-sleutels vereist. De sleutels worden opgeslagen in de lokale opslag van je apparaat.",
+ "success": {
+ "saved": "Succesvol opgeslagen"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/ta.json b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/ta.json
new file mode 100644
index 00000000..69900727
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/ta.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u0bb0\u0ba4\u0bcd\u0ba4\u0bc1 \u0b9a\u0bc6\u0baf\u0bcd",
+ "confirm": "\u0b89\u0bb1\u0bc1\u0ba4\u0bbf\u0baa\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1",
+ "continue": "\u0ba4\u0bca\u0b9f\u0bb0\u0bcd\u0b95",
+ "goBack": "\u0ba4\u0bbf\u0bb0\u0bc1\u0bae\u0bcd\u0baa\u0bbf\u0b9a\u0bcd \u0b9a\u0bc6\u0bb2\u0bcd",
+ "reset": "\u0bae\u0bc0\u0b9f\u0bcd\u0b9f\u0bae\u0bc8",
+ "submit": "\u0b9a\u0bae\u0bb0\u0bcd\u0baa\u0bcd\u0baa\u0bbf"
+ },
+ "status": {
+ "loading": "\u0b8f\u0bb1\u0bcd\u0bb1\u0bc1\u0b95\u0bbf\u0bb1\u0ba4\u0bc1...",
+ "error": {
+ "default": "\u0baa\u0bbf\u0bb4\u0bc8 \u0b8f\u0bb1\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1",
+ "serverConnection": "\u0b9a\u0bc7\u0bb5\u0bc8\u0baf\u0b95\u0ba4\u0bcd\u0ba4\u0bc8 \u0b85\u0b9f\u0bc8\u0baf \u0bae\u0bc1\u0b9f\u0bbf\u0baf\u0bb5\u0bbf\u0bb2\u0bcd\u0bb2\u0bc8"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u0baa\u0baf\u0ba9\u0bcd\u0baa\u0bbe\u0b9f\u0bcd\u0b9f\u0bc8 \u0b85\u0ba3\u0bc1\u0b95 \u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf\u0bb5\u0bc1\u0bae\u0bcd",
+ "form": {
+ "email": {
+ "label": "\u0bae\u0bbf\u0ba9\u0bcd\u0ba9\u0b9e\u0bcd\u0b9a\u0bb2\u0bcd \u0bae\u0bc1\u0b95\u0bb5\u0bb0\u0bbf",
+ "required": "\u0bae\u0bbf\u0ba9\u0bcd\u0ba9\u0b9e\u0bcd\u0b9a\u0bb2\u0bcd \u0ba4\u0bc7\u0bb5\u0bc8\u0baf\u0bbe\u0ba9 \u0baa\u0bc1\u0bb2\u0bae\u0bcd"
+ },
+ "password": {
+ "label": "\u0b95\u0b9f\u0bb5\u0bc1\u0b9a\u0bcd\u0b9a\u0bca\u0bb2\u0bcd",
+ "required": "\u0b95\u0b9f\u0bb5\u0bc1\u0b9a\u0bcd\u0b9a\u0bca\u0bb2\u0bcd \u0ba4\u0bc7\u0bb5\u0bc8\u0baf\u0bbe\u0ba9 \u0baa\u0bc1\u0bb2\u0bae\u0bcd"
+ },
+ "actions": {
+ "signin": "\u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0b95"
+ },
+ "alternativeText": {
+ "or": "\u0b85\u0bb2\u0bcd\u0bb2\u0ba4\u0bc1"
+ }
+ },
+ "errors": {
+ "default": "\u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf \u0bae\u0bc1\u0b9f\u0bbf\u0baf\u0bb5\u0bbf\u0bb2\u0bcd\u0bb2\u0bc8",
+ "signin": "\u0bb5\u0bc7\u0bb1\u0bc1 \u0b95\u0ba3\u0b95\u0bcd\u0b95\u0bc1\u0b9f\u0ba9\u0bcd \u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf \u0bae\u0bc1\u0baf\u0bb1\u0bcd\u0b9a\u0bbf\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd",
+ "oauthSignin": "\u0bb5\u0bc7\u0bb1\u0bc1 \u0b95\u0ba3\u0b95\u0bcd\u0b95\u0bc1\u0b9f\u0ba9\u0bcd \u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf \u0bae\u0bc1\u0baf\u0bb1\u0bcd\u0b9a\u0bbf\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd",
+ "redirectUriMismatch": "\u0ba4\u0bbf\u0b9a\u0bc8\u0ba4\u0bbf\u0bb0\u0bc1\u0baa\u0bcd\u0baa\u0bb2\u0bcd URI \u0b93\u0b86\u0ba4\u0bcd \u0baa\u0baf\u0ba9\u0bcd\u0baa\u0bbe\u0b9f\u0bcd\u0b9f\u0bc1 \u0b95\u0b9f\u0bcd\u0b9f\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc1\u0b9f\u0ba9\u0bcd \u0baa\u0bca\u0bb0\u0bc1\u0ba8\u0bcd\u0ba4\u0bb5\u0bbf\u0bb2\u0bcd\u0bb2\u0bc8",
+ "oauthCallback": "\u0bb5\u0bc7\u0bb1\u0bc1 \u0b95\u0ba3\u0b95\u0bcd\u0b95\u0bc1\u0b9f\u0ba9\u0bcd \u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf \u0bae\u0bc1\u0baf\u0bb1\u0bcd\u0b9a\u0bbf\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd",
+ "oauthCreateAccount": "\u0bb5\u0bc7\u0bb1\u0bc1 \u0b95\u0ba3\u0b95\u0bcd\u0b95\u0bc1\u0b9f\u0ba9\u0bcd \u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf \u0bae\u0bc1\u0baf\u0bb1\u0bcd\u0b9a\u0bbf\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd",
+ "emailCreateAccount": "\u0bb5\u0bc7\u0bb1\u0bc1 \u0b95\u0ba3\u0b95\u0bcd\u0b95\u0bc1\u0b9f\u0ba9\u0bcd \u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf \u0bae\u0bc1\u0baf\u0bb1\u0bcd\u0b9a\u0bbf\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd",
+ "callback": "\u0bb5\u0bc7\u0bb1\u0bc1 \u0b95\u0ba3\u0b95\u0bcd\u0b95\u0bc1\u0b9f\u0ba9\u0bcd \u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf \u0bae\u0bc1\u0baf\u0bb1\u0bcd\u0b9a\u0bbf\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd",
+ "oauthAccountNotLinked": "\u0b89\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b85\u0b9f\u0bc8\u0baf\u0bbe\u0bb3\u0ba4\u0bcd\u0ba4\u0bc8 \u0b89\u0bb1\u0bc1\u0ba4\u0bbf\u0baa\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4, \u0bae\u0bc1\u0ba4\u0bb2\u0bbf\u0bb2\u0bcd \u0baa\u0baf\u0ba9\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4\u0bbf\u0baf \u0b85\u0ba4\u0bc7 \u0b95\u0ba3\u0b95\u0bcd\u0b95\u0bc1\u0b9f\u0ba9\u0bcd \u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf\u0bb5\u0bc1\u0bae\u0bcd",
+ "emailSignin": "\u0bae\u0bbf\u0ba9\u0bcd\u0ba9\u0b9e\u0bcd\u0b9a\u0bb2\u0bc8 \u0b85\u0ba9\u0bc1\u0baa\u0bcd\u0baa \u0bae\u0bc1\u0b9f\u0bbf\u0baf\u0bb5\u0bbf\u0bb2\u0bcd\u0bb2\u0bc8",
+ "emailVerify": "\u0b89\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0bae\u0bbf\u0ba9\u0bcd\u0ba9\u0b9e\u0bcd\u0b9a\u0bb2\u0bc8 \u0b9a\u0bb0\u0bbf\u0baa\u0bbe\u0bb0\u0bcd\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd, \u0baa\u0bc1\u0ba4\u0bbf\u0baf \u0bae\u0bbf\u0ba9\u0bcd\u0ba9\u0b9e\u0bcd\u0b9a\u0bb2\u0bcd \u0b85\u0ba9\u0bc1\u0baa\u0bcd\u0baa\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0bc1\u0bb3\u0bcd\u0bb3\u0ba4\u0bc1",
+ "credentialsSignin": "\u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0bb5\u0bc1 \u0ba4\u0bcb\u0bb2\u0bcd\u0bb5\u0bbf\u0baf\u0b9f\u0bc8\u0ba8\u0bcd\u0ba4\u0ba4\u0bc1. \u0ba8\u0bc0\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0bb5\u0bb4\u0b99\u0bcd\u0b95\u0bbf\u0baf \u0bb5\u0bbf\u0bb5\u0bb0\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b9a\u0bb0\u0bbf\u0baf\u0bbe\u0ba9\u0bb5\u0bc8 \u0b8e\u0ba9 \u0b9a\u0bb0\u0bbf\u0baa\u0bbe\u0bb0\u0bcd\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd",
+ "sessionRequired": "\u0b87\u0ba8\u0bcd\u0ba4\u0baa\u0bcd \u0baa\u0b95\u0bcd\u0b95\u0ba4\u0bcd\u0ba4\u0bc8 \u0b85\u0ba3\u0bc1\u0b95 \u0b89\u0bb3\u0bcd\u0ba8\u0bc1\u0bb4\u0bc8\u0baf\u0bb5\u0bc1\u0bae\u0bcd"
+ }
+ },
+ "provider": {
+ "continue": "{{provider}} \u0bae\u0bc2\u0bb2\u0bae\u0bcd \u0ba4\u0bca\u0b9f\u0bb0\u0bb5\u0bc1\u0bae\u0bcd"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u0b89\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b9a\u0bc6\u0baf\u0bcd\u0ba4\u0bbf\u0baf\u0bc8 \u0b87\u0b99\u0bcd\u0b95\u0bc7 \u0ba4\u0b9f\u0bcd\u0b9f\u0b9a\u0bcd\u0b9a\u0bc1 \u0b9a\u0bc6\u0baf\u0bcd\u0baf\u0bb5\u0bc1\u0bae\u0bcd...",
+ "actions": {
+ "send": "\u0b9a\u0bc6\u0baf\u0bcd\u0ba4\u0bbf \u0b85\u0ba9\u0bc1\u0baa\u0bcd\u0baa\u0bc1",
+ "stop": "\u0baa\u0ba3\u0bbf\u0baf\u0bc8 \u0ba8\u0bbf\u0bb1\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1",
+ "attachFiles": "\u0b95\u0bcb\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bc8 \u0b87\u0ba3\u0bc8"
+ }
+ },
+ "speech": {
+ "start": "\u0baa\u0ba4\u0bbf\u0bb5\u0bc1 \u0ba4\u0bca\u0b9f\u0b99\u0bcd\u0b95\u0bc1",
+ "stop": "\u0baa\u0ba4\u0bbf\u0bb5\u0bc8 \u0ba8\u0bbf\u0bb1\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1",
+ "connecting": "\u0b87\u0ba3\u0bc8\u0b95\u0bcd\u0b95\u0bbf\u0bb1\u0ba4\u0bc1"
+ },
+ "fileUpload": {
+ "dragDrop": "\u0b95\u0bcb\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bc8 \u0b87\u0b99\u0bcd\u0b95\u0bc7 \u0b87\u0bb4\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1 \u0bb5\u0bbf\u0b9f\u0bb5\u0bc1\u0bae\u0bcd",
+ "browse": "\u0b95\u0bcb\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bc8 \u0b89\u0bb2\u0bbe\u0bb5\u0bc1",
+ "sizeLimit": "\u0bb5\u0bb0\u0bae\u0bcd\u0baa\u0bc1:",
+ "errors": {
+ "failed": "\u0baa\u0ba4\u0bbf\u0bb5\u0bc7\u0bb1\u0bcd\u0bb1\u0bae\u0bcd \u0ba4\u0bcb\u0bb2\u0bcd\u0bb5\u0bbf\u0baf\u0b9f\u0bc8\u0ba8\u0bcd\u0ba4\u0ba4\u0bc1",
+ "cancelled": "\u0baa\u0ba4\u0bbf\u0bb5\u0bc7\u0bb1\u0bcd\u0bb1\u0bae\u0bcd \u0bb0\u0ba4\u0bcd\u0ba4\u0bc1 \u0b9a\u0bc6\u0baf\u0bcd\u0baf\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u0baa\u0baf\u0ba9\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1\u0b95\u0bbf\u0bb1\u0ba4\u0bc1",
+ "used": "\u0baa\u0baf\u0ba9\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u0b95\u0bbf\u0bb3\u0bbf\u0baa\u0bcd\u0baa\u0bcb\u0bb0\u0bcd\u0b9f\u0bc1\u0b95\u0bcd\u0b95\u0bc1 \u0ba8\u0b95\u0bb2\u0bc6\u0b9f\u0bc1",
+ "success": "\u0ba8\u0b95\u0bb2\u0bc6\u0b9f\u0bc1\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1!"
+ }
+ },
+ "feedback": {
+ "positive": "\u0baa\u0baf\u0ba9\u0bc1\u0bb3\u0bcd\u0bb3\u0ba4\u0bbe\u0b95 \u0b87\u0bb0\u0bc1\u0ba8\u0bcd\u0ba4\u0ba4\u0bc1",
+ "negative": "\u0baa\u0baf\u0ba9\u0bc1\u0bb3\u0bcd\u0bb3\u0ba4\u0bbe\u0b95 \u0b87\u0bb2\u0bcd\u0bb2\u0bc8",
+ "edit": "\u0b95\u0bb0\u0bc1\u0ba4\u0bcd\u0ba4\u0bc8 \u0ba4\u0bbf\u0bb0\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1",
+ "dialog": {
+ "title": "\u0b95\u0bb0\u0bc1\u0ba4\u0bcd\u0ba4\u0bc8\u0b9a\u0bcd \u0b9a\u0bc7\u0bb0\u0bcd",
+ "submit": "\u0b95\u0bb0\u0bc1\u0ba4\u0bcd\u0ba4\u0bc8 \u0b9a\u0bae\u0bb0\u0bcd\u0baa\u0bcd\u0baa\u0bbf"
+ },
+ "status": {
+ "updating": "\u0baa\u0bc1\u0ba4\u0bc1\u0baa\u0bcd\u0baa\u0bbf\u0b95\u0bcd\u0b95\u0bbf\u0bb1\u0ba4\u0bc1",
+ "updated": "\u0b95\u0bb0\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1 \u0baa\u0bc1\u0ba4\u0bc1\u0baa\u0bcd\u0baa\u0bbf\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1"
+ }
+ }
+ },
+ "history": {
+ "title": "\u0b95\u0b9f\u0bc8\u0b9a\u0bbf \u0b89\u0bb3\u0bcd\u0bb3\u0bc0\u0b9f\u0bc1\u0b95\u0bb3\u0bcd",
+ "empty": "\u0b95\u0bbe\u0bb2\u0bbf\u0baf\u0bbe\u0b95 \u0b89\u0bb3\u0bcd\u0bb3\u0ba4\u0bc1...",
+ "show": "\u0bb5\u0bb0\u0bb2\u0bbe\u0bb1\u0bcd\u0bb1\u0bc8\u0b95\u0bcd \u0b95\u0bbe\u0b9f\u0bcd\u0b9f\u0bc1"
+ },
+ "settings": {
+ "title": "\u0b85\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd \u0baa\u0bb2\u0b95\u0bae\u0bcd"
+ },
+ "watermark": "\u0b89\u0b9f\u0ba9\u0bcd \u0b89\u0bb0\u0bc1\u0bb5\u0bbe\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u0b95\u0b9f\u0ba8\u0bcd\u0ba4 \u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd\u0b95\u0bb3\u0bcd",
+ "filters": {
+ "search": "\u0ba4\u0bc7\u0b9f\u0bc1",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u0b87\u0ba9\u0bcd\u0bb1\u0bc1",
+ "yesterday": "\u0ba8\u0bc7\u0bb1\u0bcd\u0bb1\u0bc1",
+ "previous7days": "\u0b95\u0b9f\u0ba8\u0bcd\u0ba4 7 \u0ba8\u0bbe\u0b9f\u0bcd\u0b95\u0bb3\u0bcd",
+ "previous30days": "\u0b95\u0b9f\u0ba8\u0bcd\u0ba4 30 \u0ba8\u0bbe\u0b9f\u0bcd\u0b95\u0bb3\u0bcd"
+ },
+ "empty": "\u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd\u0b95\u0bb3\u0bcd \u0b8e\u0ba4\u0bc1\u0bb5\u0bc1\u0bae\u0bcd \u0b87\u0bb2\u0bcd\u0bb2\u0bc8",
+ "actions": {
+ "close": "\u0baa\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0bbf\u0baf\u0bc8 \u0bae\u0bc2\u0b9f\u0bc1",
+ "open": "\u0baa\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0bbf\u0baf\u0bc8 \u0ba4\u0bbf\u0bb1"
+ }
+ },
+ "thread": {
+ "untitled": "\u0ba4\u0bb2\u0bc8\u0baa\u0bcd\u0baa\u0bbf\u0b9f\u0bbe\u0ba4 \u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u0ba8\u0bc0\u0b95\u0bcd\u0b95\u0bc1\u0bb5\u0ba4\u0bc8 \u0b89\u0bb1\u0bc1\u0ba4\u0bbf\u0baa\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4\u0bc1",
+ "description": "\u0b87\u0ba4\u0bc1 \u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd \u0bae\u0bb1\u0bcd\u0bb1\u0bc1\u0bae\u0bcd \u0b85\u0ba4\u0ba9\u0bcd \u0b9a\u0bc6\u0baf\u0bcd\u0ba4\u0bbf\u0b95\u0bb3\u0bcd, \u0b89\u0bb1\u0bc1\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bc8 \u0ba8\u0bc0\u0b95\u0bcd\u0b95\u0bc1\u0bae\u0bcd. \u0b87\u0ba8\u0bcd\u0ba4 \u0b9a\u0bc6\u0baf\u0bb2\u0bc8 \u0bae\u0bc0\u0b9f\u0bcd\u0b9f\u0bc6\u0b9f\u0bc1\u0b95\u0bcd\u0b95 \u0bae\u0bc1\u0b9f\u0bbf\u0baf\u0bbe\u0ba4\u0bc1",
+ "success": "\u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd \u0ba8\u0bc0\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1",
+ "inProgress": "\u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bc8 \u0ba8\u0bc0\u0b95\u0bcd\u0b95\u0bc1\u0b95\u0bbf\u0bb1\u0ba4\u0bc1"
+ },
+ "rename": {
+ "title": "\u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bc8 \u0bae\u0bb1\u0bc1\u0baa\u0bc6\u0baf\u0bb0\u0bbf\u0b9f\u0bc1",
+ "description": "\u0b87\u0ba8\u0bcd\u0ba4 \u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bc1\u0b95\u0bcd\u0b95\u0bc1 \u0baa\u0bc1\u0ba4\u0bbf\u0baf \u0baa\u0bc6\u0baf\u0bb0\u0bc8 \u0b89\u0bb3\u0bcd\u0bb3\u0bbf\u0b9f\u0bb5\u0bc1\u0bae\u0bcd",
+ "form": {
+ "name": {
+ "label": "\u0baa\u0bc6\u0baf\u0bb0\u0bcd",
+ "placeholder": "\u0baa\u0bc1\u0ba4\u0bbf\u0baf \u0baa\u0bc6\u0baf\u0bb0\u0bc8 \u0b89\u0bb3\u0bcd\u0bb3\u0bbf\u0b9f\u0bb5\u0bc1\u0bae\u0bcd"
+ }
+ },
+ "success": "\u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd \u0bae\u0bb1\u0bc1\u0baa\u0bc6\u0baf\u0bb0\u0bbf\u0b9f\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1!",
+ "inProgress": "\u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bc8 \u0bae\u0bb1\u0bc1\u0baa\u0bc6\u0baf\u0bb0\u0bbf\u0b9f\u0bc1\u0b95\u0bbf\u0bb1\u0ba4\u0bc1"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd",
+ "readme": "\u0baa\u0b9f\u0bbf\u0b95\u0bcd\u0b95\u0bb5\u0bc1\u0bae\u0bcd",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u0baa\u0bc1\u0ba4\u0bbf\u0baf \u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd",
+ "dialog": {
+ "title": "\u0baa\u0bc1\u0ba4\u0bbf\u0baf \u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bc8 \u0b89\u0bb0\u0bc1\u0bb5\u0bbe\u0b95\u0bcd\u0b95\u0bc1",
+ "description": "\u0b87\u0ba4\u0bc1 \u0b89\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0ba4\u0bb1\u0bcd\u0baa\u0bcb\u0ba4\u0bc8\u0baf \u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd \u0bb5\u0bb0\u0bb2\u0bbe\u0bb1\u0bcd\u0bb1\u0bc8 \u0b85\u0bb4\u0bbf\u0b95\u0bcd\u0b95\u0bc1\u0bae\u0bcd. \u0ba4\u0bca\u0b9f\u0bb0 \u0bb5\u0bbf\u0bb0\u0bc1\u0bae\u0bcd\u0baa\u0bc1\u0b95\u0bbf\u0bb1\u0bc0\u0bb0\u0bcd\u0b95\u0bb3\u0bbe?",
+ "tooltip": "\u0baa\u0bc1\u0ba4\u0bbf\u0baf \u0b89\u0bb0\u0bc8\u0baf\u0bbe\u0b9f\u0bb2\u0bcd"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u0b85\u0bae\u0bc8\u0baa\u0bcd\u0baa\u0bc1\u0b95\u0bb3\u0bcd",
+ "settingsKey": "S",
+ "apiKeys": "API \u0bb5\u0bbf\u0b9a\u0bc8\u0b95\u0bb3\u0bcd",
+ "logout": "\u0bb5\u0bc6\u0bb3\u0bbf\u0baf\u0bc7\u0bb1\u0bc1"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u0ba4\u0bc7\u0bb5\u0bc8\u0baf\u0bbe\u0ba9 API \u0bb5\u0bbf\u0b9a\u0bc8\u0b95\u0bb3\u0bcd",
+ "description": "\u0b87\u0ba8\u0bcd\u0ba4 \u0baa\u0baf\u0ba9\u0bcd\u0baa\u0bbe\u0b9f\u0bcd\u0b9f\u0bc8\u0baa\u0bcd \u0baa\u0baf\u0ba9\u0bcd\u0baa\u0b9f\u0bc1\u0ba4\u0bcd\u0ba4, \u0baa\u0bbf\u0ba9\u0bcd\u0bb5\u0bb0\u0bc1\u0bae\u0bcd API \u0bb5\u0bbf\u0b9a\u0bc8\u0b95\u0bb3\u0bcd \u0ba4\u0bc7\u0bb5\u0bc8. \u0bb5\u0bbf\u0b9a\u0bc8\u0b95\u0bb3\u0bcd \u0b89\u0b99\u0bcd\u0b95\u0bb3\u0bcd \u0b9a\u0bbe\u0ba4\u0ba9\u0ba4\u0bcd\u0ba4\u0bbf\u0ba9\u0bcd \u0b89\u0bb3\u0bcd\u0bb3\u0bc2\u0bb0\u0bcd \u0b9a\u0bc7\u0bae\u0bbf\u0baa\u0bcd\u0baa\u0b95\u0ba4\u0bcd\u0ba4\u0bbf\u0bb2\u0bcd \u0b9a\u0bc7\u0bae\u0bbf\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bc1\u0bae\u0bcd.",
+ "success": {
+ "saved": "\u0bb5\u0bc6\u0bb1\u0bcd\u0bb1\u0bbf\u0b95\u0bb0\u0bae\u0bbe\u0b95 \u0b9a\u0bc7\u0bae\u0bbf\u0b95\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0b9f\u0bcd\u0b9f\u0ba4\u0bc1"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/te.json b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/te.json
new file mode 100644
index 00000000..ac92371c
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/te.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u0c30\u0c26\u0c4d\u0c26\u0c41 \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "confirm": "\u0c28\u0c3f\u0c30\u0c4d\u0c27\u0c3e\u0c30\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "continue": "\u0c15\u0c4a\u0c28\u0c38\u0c3e\u0c17\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "goBack": "\u0c35\u0c46\u0c28\u0c15\u0c4d\u0c15\u0c3f \u0c35\u0c46\u0c33\u0c4d\u0c33\u0c02\u0c21\u0c3f",
+ "reset": "\u0c30\u0c40\u0c38\u0c46\u0c1f\u0c4d \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "submit": "\u0c38\u0c2e\u0c30\u0c4d\u0c2a\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f"
+ },
+ "status": {
+ "loading": "\u0c32\u0c4b\u0c21\u0c4d \u0c05\u0c35\u0c41\u0c24\u0c4b\u0c02\u0c26\u0c3f...",
+ "error": {
+ "default": "\u0c32\u0c4b\u0c2a\u0c02 \u0c38\u0c02\u0c2d\u0c35\u0c3f\u0c02\u0c1a\u0c3f\u0c02\u0c26\u0c3f",
+ "serverConnection": "\u0c38\u0c30\u0c4d\u0c35\u0c30\u0c4d\u200c\u0c28\u0c3f \u0c1a\u0c47\u0c30\u0c41\u0c15\u0c4b\u0c32\u0c47\u0c15\u0c2a\u0c4b\u0c2f\u0c3e\u0c2e\u0c41"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u0c2f\u0c3e\u0c2a\u0c4d\u200c\u0c28\u0c3f \u0c09\u0c2a\u0c2f\u0c4b\u0c17\u0c3f\u0c02\u0c1a\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f \u0c32\u0c3e\u0c17\u0c3f\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "form": {
+ "email": {
+ "label": "\u0c07\u0c2e\u0c46\u0c2f\u0c3f\u0c32\u0c4d \u0c1a\u0c3f\u0c30\u0c41\u0c28\u0c3e\u0c2e\u0c3e",
+ "required": "\u0c07\u0c2e\u0c46\u0c2f\u0c3f\u0c32\u0c4d \u0c24\u0c2a\u0c4d\u0c2a\u0c28\u0c3f\u0c38\u0c30\u0c3f"
+ },
+ "password": {
+ "label": "\u0c2a\u0c3e\u0c38\u0c4d\u200c\u0c35\u0c30\u0c4d\u0c21\u0c4d",
+ "required": "\u0c2a\u0c3e\u0c38\u0c4d\u200c\u0c35\u0c30\u0c4d\u0c21\u0c4d \u0c24\u0c2a\u0c4d\u0c2a\u0c28\u0c3f\u0c38\u0c30\u0c3f"
+ },
+ "actions": {
+ "signin": "\u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f"
+ },
+ "alternativeText": {
+ "or": "\u0c32\u0c47\u0c26\u0c3e"
+ }
+ },
+ "errors": {
+ "default": "\u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c32\u0c47\u0c15\u0c2a\u0c4b\u0c2f\u0c3e\u0c2e\u0c41",
+ "signin": "\u0c35\u0c47\u0c30\u0c47 \u0c16\u0c3e\u0c24\u0c3e\u0c24\u0c4b \u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f \u0c2a\u0c4d\u0c30\u0c2f\u0c24\u0c4d\u0c28\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "oauthSignin": "\u0c35\u0c47\u0c30\u0c47 \u0c16\u0c3e\u0c24\u0c3e\u0c24\u0c4b \u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f \u0c2a\u0c4d\u0c30\u0c2f\u0c24\u0c4d\u0c28\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "redirectUriMismatch": "\u0c30\u0c40\u0c21\u0c48\u0c30\u0c46\u0c15\u0c4d\u0c1f\u0c4d URI oauth \u0c2f\u0c3e\u0c2a\u0c4d \u0c15\u0c3e\u0c28\u0c4d\u0c2b\u0c3f\u0c17\u0c30\u0c47\u0c37\u0c28\u0c4d\u200c\u0c24\u0c4b \u0c38\u0c30\u0c3f\u0c2a\u0c4b\u0c32\u0c21\u0c02 \u0c32\u0c47\u0c26\u0c41",
+ "oauthCallback": "\u0c35\u0c47\u0c30\u0c47 \u0c16\u0c3e\u0c24\u0c3e\u0c24\u0c4b \u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f \u0c2a\u0c4d\u0c30\u0c2f\u0c24\u0c4d\u0c28\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "oauthCreateAccount": "\u0c35\u0c47\u0c30\u0c47 \u0c16\u0c3e\u0c24\u0c3e\u0c24\u0c4b \u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f \u0c2a\u0c4d\u0c30\u0c2f\u0c24\u0c4d\u0c28\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "emailCreateAccount": "\u0c35\u0c47\u0c30\u0c47 \u0c16\u0c3e\u0c24\u0c3e\u0c24\u0c4b \u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f \u0c2a\u0c4d\u0c30\u0c2f\u0c24\u0c4d\u0c28\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "callback": "\u0c35\u0c47\u0c30\u0c47 \u0c16\u0c3e\u0c24\u0c3e\u0c24\u0c4b \u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f \u0c2a\u0c4d\u0c30\u0c2f\u0c24\u0c4d\u0c28\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "oauthAccountNotLinked": "\u0c2e\u0c40 \u0c17\u0c41\u0c30\u0c4d\u0c24\u0c3f\u0c02\u0c2a\u0c41\u0c28\u0c41 \u0c28\u0c3f\u0c30\u0c4d\u0c27\u0c3e\u0c30\u0c3f\u0c02\u0c1a\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f, \u0c2e\u0c40\u0c30\u0c41 \u0c2e\u0c4a\u0c26\u0c1f \u0c09\u0c2a\u0c2f\u0c4b\u0c17\u0c3f\u0c02\u0c1a\u0c3f\u0c28 \u0c05\u0c26\u0c47 \u0c16\u0c3e\u0c24\u0c3e\u0c24\u0c4b \u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "emailSignin": "\u0c07\u0c2e\u0c46\u0c2f\u0c3f\u0c32\u0c4d \u0c2a\u0c02\u0c2a\u0c21\u0c02 \u0c38\u0c3e\u0c27\u0c4d\u0c2f\u0c02 \u0c15\u0c3e\u0c32\u0c47\u0c26\u0c41",
+ "emailVerify": "\u0c26\u0c2f\u0c1a\u0c47\u0c38\u0c3f \u0c2e\u0c40 \u0c07\u0c2e\u0c46\u0c2f\u0c3f\u0c32\u0c4d\u200c\u0c28\u0c3f \u0c27\u0c43\u0c35\u0c40\u0c15\u0c30\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f, \u0c15\u0c4a\u0c24\u0c4d\u0c24 \u0c07\u0c2e\u0c46\u0c2f\u0c3f\u0c32\u0c4d \u0c2a\u0c02\u0c2a\u0c2c\u0c21\u0c3f\u0c02\u0c26\u0c3f",
+ "credentialsSignin": "\u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c35\u0c3f\u0c2b\u0c32\u0c2e\u0c48\u0c02\u0c26\u0c3f. \u0c2e\u0c40\u0c30\u0c41 \u0c05\u0c02\u0c26\u0c3f\u0c02\u0c1a\u0c3f\u0c28 \u0c35\u0c3f\u0c35\u0c30\u0c3e\u0c32\u0c41 \u0c38\u0c30\u0c48\u0c28\u0c35\u0c47\u0c28\u0c3e \u0c05\u0c28\u0c3f \u0c24\u0c28\u0c3f\u0c16\u0c40 \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "sessionRequired": "\u0c08 \u0c2a\u0c47\u0c1c\u0c40\u0c28\u0c3f \u0c2f\u0c3e\u0c15\u0c4d\u0c38\u0c46\u0c38\u0c4d \u0c1a\u0c47\u0c2f\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f \u0c26\u0c2f\u0c1a\u0c47\u0c38\u0c3f \u0c38\u0c48\u0c28\u0c4d \u0c07\u0c28\u0c4d \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f"
+ }
+ },
+ "provider": {
+ "continue": "{{provider}}\u0c24\u0c4b \u0c15\u0c4a\u0c28\u0c38\u0c3e\u0c17\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u0c2e\u0c40 \u0c38\u0c02\u0c26\u0c47\u0c36\u0c3e\u0c28\u0c4d\u0c28\u0c3f \u0c07\u0c15\u0c4d\u0c15\u0c21 \u0c1f\u0c48\u0c2a\u0c4d \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f...",
+ "actions": {
+ "send": "\u0c38\u0c02\u0c26\u0c47\u0c36\u0c02 \u0c2a\u0c02\u0c2a\u0c02\u0c21\u0c3f",
+ "stop": "\u0c2a\u0c28\u0c3f \u0c06\u0c2a\u0c02\u0c21\u0c3f",
+ "attachFiles": "\u0c2b\u0c48\u0c32\u0c4d\u0c38\u0c4d \u0c1c\u0c4b\u0c21\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f"
+ }
+ },
+ "speech": {
+ "start": "\u0c30\u0c3f\u0c15\u0c3e\u0c30\u0c4d\u0c21\u0c3f\u0c02\u0c17\u0c4d \u0c2a\u0c4d\u0c30\u0c3e\u0c30\u0c02\u0c2d\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "stop": "\u0c30\u0c3f\u0c15\u0c3e\u0c30\u0c4d\u0c21\u0c3f\u0c02\u0c17\u0c4d \u0c06\u0c2a\u0c02\u0c21\u0c3f",
+ "connecting": "\u0c05\u0c28\u0c41\u0c38\u0c02\u0c27\u0c3e\u0c28\u0c3f\u0c38\u0c4d\u0c24\u0c4b\u0c02\u0c26\u0c3f"
+ },
+ "fileUpload": {
+ "dragDrop": "\u0c2b\u0c48\u0c32\u0c4d\u0c38\u0c4d\u200c\u0c28\u0c3f \u0c07\u0c15\u0c4d\u0c15\u0c21 \u0c21\u0c4d\u0c30\u0c3e\u0c17\u0c4d \u0c1a\u0c47\u0c38\u0c3f \u0c21\u0c4d\u0c30\u0c3e\u0c2a\u0c4d \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "browse": "\u0c2b\u0c48\u0c32\u0c4d\u0c38\u0c4d \u0c2c\u0c4d\u0c30\u0c4c\u0c1c\u0c4d \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "sizeLimit": "\u0c2a\u0c30\u0c3f\u0c2e\u0c3f\u0c24\u0c3f:",
+ "errors": {
+ "failed": "\u0c05\u0c2a\u0c4d\u200c\u0c32\u0c4b\u0c21\u0c4d \u0c35\u0c3f\u0c2b\u0c32\u0c2e\u0c48\u0c02\u0c26\u0c3f",
+ "cancelled": "\u0c05\u0c2a\u0c4d\u200c\u0c32\u0c4b\u0c21\u0c4d \u0c30\u0c26\u0c4d\u0c26\u0c41 \u0c1a\u0c47\u0c2f\u0c2c\u0c21\u0c3f\u0c02\u0c26\u0c3f"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u0c09\u0c2a\u0c2f\u0c4b\u0c17\u0c3f\u0c38\u0c4d\u0c24\u0c4b\u0c02\u0c26\u0c3f",
+ "used": "\u0c09\u0c2a\u0c2f\u0c4b\u0c17\u0c3f\u0c02\u0c1a\u0c2c\u0c21\u0c3f\u0c02\u0c26\u0c3f"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u0c15\u0c4d\u0c32\u0c3f\u0c2a\u0c4d\u200c\u0c2c\u0c4b\u0c30\u0c4d\u0c21\u0c4d\u200c\u0c15\u0c3f \u0c15\u0c3e\u0c2a\u0c40 \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "success": "\u0c15\u0c3e\u0c2a\u0c40 \u0c1a\u0c47\u0c2f\u0c2c\u0c21\u0c3f\u0c02\u0c26\u0c3f!"
+ }
+ },
+ "feedback": {
+ "positive": "\u0c38\u0c39\u0c3e\u0c2f\u0c15\u0c30\u0c02",
+ "negative": "\u0c38\u0c39\u0c3e\u0c2f\u0c15\u0c30\u0c02 \u0c15\u0c3e\u0c26\u0c41",
+ "edit": "\u0c05\u0c2d\u0c3f\u0c2a\u0c4d\u0c30\u0c3e\u0c2f\u0c3e\u0c28\u0c4d\u0c28\u0c3f \u0c38\u0c35\u0c30\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "dialog": {
+ "title": "\u0c35\u0c4d\u0c2f\u0c3e\u0c16\u0c4d\u0c2f \u0c1c\u0c4b\u0c21\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "submit": "\u0c05\u0c2d\u0c3f\u0c2a\u0c4d\u0c30\u0c3e\u0c2f\u0c3e\u0c28\u0c4d\u0c28\u0c3f \u0c38\u0c2e\u0c30\u0c4d\u0c2a\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f"
+ },
+ "status": {
+ "updating": "\u0c28\u0c35\u0c40\u0c15\u0c30\u0c3f\u0c38\u0c4d\u0c24\u0c4b\u0c02\u0c26\u0c3f",
+ "updated": "\u0c05\u0c2d\u0c3f\u0c2a\u0c4d\u0c30\u0c3e\u0c2f\u0c02 \u0c28\u0c35\u0c40\u0c15\u0c30\u0c3f\u0c02\u0c1a\u0c2c\u0c21\u0c3f\u0c02\u0c26\u0c3f"
+ }
+ }
+ },
+ "history": {
+ "title": "\u0c1a\u0c3f\u0c35\u0c30\u0c3f \u0c07\u0c28\u0c4d\u200c\u0c2a\u0c41\u0c1f\u0c4d\u200c\u0c32\u0c41",
+ "empty": "\u0c16\u0c3e\u0c33\u0c40\u0c17\u0c3e \u0c09\u0c02\u0c26\u0c3f...",
+ "show": "\u0c1a\u0c30\u0c3f\u0c24\u0c4d\u0c30\u0c28\u0c41 \u0c1a\u0c42\u0c2a\u0c3f\u0c02\u0c1a\u0c41"
+ },
+ "settings": {
+ "title": "\u0c38\u0c46\u0c1f\u0c4d\u0c1f\u0c3f\u0c02\u0c17\u0c4d\u200c\u0c32 \u0c2a\u0c4d\u0c2f\u0c3e\u0c28\u0c46\u0c32\u0c4d"
+ },
+ "watermark": "\u0c24\u0c4b \u0c28\u0c3f\u0c30\u0c4d\u0c2e\u0c3f\u0c02\u0c1a\u0c2c\u0c21\u0c3f\u0c02\u0c26\u0c3f"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u0c17\u0c24 \u0c1a\u0c3e\u0c1f\u0c4d\u200c\u0c32\u0c41",
+ "filters": {
+ "search": "\u0c35\u0c46\u0c24\u0c15\u0c02\u0c21\u0c3f",
+ "placeholder": "Search conversations..."
+ },
+ "timeframes": {
+ "today": "\u0c08\u0c30\u0c4b\u0c1c\u0c41",
+ "yesterday": "\u0c28\u0c3f\u0c28\u0c4d\u0c28",
+ "previous7days": "\u0c17\u0c24 7 \u0c30\u0c4b\u0c1c\u0c41\u0c32\u0c41",
+ "previous30days": "\u0c17\u0c24 30 \u0c30\u0c4b\u0c1c\u0c41\u0c32\u0c41"
+ },
+ "empty": "\u0c25\u0c4d\u0c30\u0c46\u0c21\u0c4d\u200c\u0c32\u0c41 \u0c15\u0c28\u0c41\u0c17\u0c4a\u0c28\u0c2c\u0c21\u0c32\u0c47\u0c26\u0c41",
+ "actions": {
+ "close": "\u0c38\u0c48\u0c21\u0c4d\u200c\u0c2c\u0c3e\u0c30\u0c4d \u0c2e\u0c42\u0c38\u0c3f\u0c35\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "open": "\u0c38\u0c48\u0c21\u0c4d\u200c\u0c2c\u0c3e\u0c30\u0c4d \u0c24\u0c46\u0c30\u0c35\u0c02\u0c21\u0c3f"
+ }
+ },
+ "thread": {
+ "untitled": "\u0c2a\u0c47\u0c30\u0c41 \u0c32\u0c47\u0c28\u0c3f \u0c38\u0c02\u0c2d\u0c3e\u0c37\u0c23",
+ "menu": {
+ "rename": "Rename",
+ "delete": "Delete"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u0c24\u0c4a\u0c32\u0c17\u0c3f\u0c02\u0c2a\u0c41\u0c28\u0c41 \u0c28\u0c3f\u0c30\u0c4d\u0c27\u0c3e\u0c30\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "description": "\u0c07\u0c26\u0c3f \u0c25\u0c4d\u0c30\u0c46\u0c21\u0c4d\u200c\u0c24\u0c4b \u0c2a\u0c3e\u0c1f\u0c41 \u0c26\u0c3e\u0c28\u0c3f \u0c38\u0c02\u0c26\u0c47\u0c36\u0c3e\u0c32\u0c28\u0c41 \u0c2e\u0c30\u0c3f\u0c2f\u0c41 \u0c05\u0c02\u0c36\u0c3e\u0c32\u0c28\u0c41 \u0c24\u0c4a\u0c32\u0c17\u0c3f\u0c38\u0c4d\u0c24\u0c41\u0c02\u0c26\u0c3f. \u0c08 \u0c1a\u0c30\u0c4d\u0c2f\u0c28\u0c41 \u0c30\u0c26\u0c4d\u0c26\u0c41 \u0c1a\u0c47\u0c2f\u0c32\u0c47\u0c30\u0c41",
+ "success": "\u0c1a\u0c3e\u0c1f\u0c4d \u0c24\u0c4a\u0c32\u0c17\u0c3f\u0c02\u0c1a\u0c2c\u0c21\u0c3f\u0c02\u0c26\u0c3f",
+ "inProgress": "\u0c1a\u0c3e\u0c1f\u0c4d\u200c\u0c28\u0c3f \u0c24\u0c4a\u0c32\u0c17\u0c3f\u0c38\u0c4d\u0c24\u0c4b\u0c02\u0c26\u0c3f"
+ },
+ "rename": {
+ "title": "\u0c25\u0c4d\u0c30\u0c46\u0c21\u0c4d \u0c2a\u0c47\u0c30\u0c41 \u0c2e\u0c3e\u0c30\u0c4d\u0c1a\u0c02\u0c21\u0c3f",
+ "description": "\u0c08 \u0c25\u0c4d\u0c30\u0c46\u0c21\u0c4d \u0c15\u0c4b\u0c38\u0c02 \u0c15\u0c4a\u0c24\u0c4d\u0c24 \u0c2a\u0c47\u0c30\u0c41\u0c28\u0c41 \u0c28\u0c2e\u0c4b\u0c26\u0c41 \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f",
+ "form": {
+ "name": {
+ "label": "\u0c2a\u0c47\u0c30\u0c41",
+ "placeholder": "\u0c15\u0c4a\u0c24\u0c4d\u0c24 \u0c2a\u0c47\u0c30\u0c41\u0c28\u0c41 \u0c28\u0c2e\u0c4b\u0c26\u0c41 \u0c1a\u0c47\u0c2f\u0c02\u0c21\u0c3f"
+ }
+ },
+ "success": "\u0c25\u0c4d\u0c30\u0c46\u0c21\u0c4d \u0c2a\u0c47\u0c30\u0c41 \u0c2e\u0c3e\u0c30\u0c4d\u0c1a\u0c2c\u0c21\u0c3f\u0c02\u0c26\u0c3f!",
+ "inProgress": "\u0c25\u0c4d\u0c30\u0c46\u0c21\u0c4d \u0c2a\u0c47\u0c30\u0c41 \u0c2e\u0c3e\u0c30\u0c41\u0c38\u0c4d\u0c24\u0c4b\u0c02\u0c26\u0c3f"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u0c1a\u0c3e\u0c1f\u0c4d",
+ "readme": "\u0c1a\u0c26\u0c35\u0c02\u0c21\u0c3f",
+ "theme": {
+ "light": "Light Theme",
+ "dark": "Dark Theme",
+ "system": "Follow System"
+ }
+ },
+ "newChat": {
+ "button": "\u0c15\u0c4a\u0c24\u0c4d\u0c24 \u0c1a\u0c3e\u0c1f\u0c4d",
+ "dialog": {
+ "title": "\u0c15\u0c4a\u0c24\u0c4d\u0c24 \u0c1a\u0c3e\u0c1f\u0c4d \u0c38\u0c43\u0c37\u0c4d\u0c1f\u0c3f\u0c02\u0c1a\u0c02\u0c21\u0c3f",
+ "description": "\u0c07\u0c26\u0c3f \u0c2e\u0c40 \u0c2a\u0c4d\u0c30\u0c38\u0c4d\u0c24\u0c41\u0c24 \u0c1a\u0c3e\u0c1f\u0c4d \u0c1a\u0c30\u0c3f\u0c24\u0c4d\u0c30\u0c28\u0c41 \u0c24\u0c41\u0c21\u0c3f\u0c1a\u0c3f\u0c35\u0c47\u0c38\u0c4d\u0c24\u0c41\u0c02\u0c26\u0c3f. \u0c2e\u0c40\u0c30\u0c41 \u0c15\u0c4a\u0c28\u0c38\u0c3e\u0c17\u0c3f\u0c02\u0c1a\u0c3e\u0c32\u0c28\u0c41\u0c15\u0c41\u0c02\u0c1f\u0c41\u0c28\u0c4d\u0c28\u0c3e\u0c30\u0c3e?",
+ "tooltip": "\u0c15\u0c4a\u0c24\u0c4d\u0c24 \u0c1a\u0c3e\u0c1f\u0c4d"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u0c38\u0c46\u0c1f\u0c4d\u0c1f\u0c3f\u0c02\u0c17\u0c4d\u200c\u0c32\u0c41",
+ "settingsKey": "S",
+ "apiKeys": "API \u0c15\u0c40\u0c32\u0c41",
+ "logout": "\u0c32\u0c3e\u0c17\u0c4d \u0c05\u0c35\u0c41\u0c1f\u0c4d"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u0c05\u0c35\u0c38\u0c30\u0c2e\u0c48\u0c28 API \u0c15\u0c40\u0c32\u0c41",
+ "description": "\u0c08 \u0c2f\u0c3e\u0c2a\u0c4d\u200c\u0c28\u0c3f \u0c09\u0c2a\u0c2f\u0c4b\u0c17\u0c3f\u0c02\u0c1a\u0c21\u0c3e\u0c28\u0c3f\u0c15\u0c3f, \u0c15\u0c3f\u0c02\u0c26\u0c3f API \u0c15\u0c40\u0c32\u0c41 \u0c05\u0c35\u0c38\u0c30\u0c02. \u0c15\u0c40\u0c32\u0c41 \u0c2e\u0c40 \u0c2a\u0c30\u0c3f\u0c15\u0c30\u0c02 \u0c2f\u0c4a\u0c15\u0c4d\u0c15 \u0c38\u0c4d\u0c25\u0c3e\u0c28\u0c3f\u0c15 \u0c28\u0c3f\u0c32\u0c4d\u0c35\u0c32\u0c4b \u0c28\u0c3f\u0c32\u0c4d\u0c35 \u0c1a\u0c47\u0c2f\u0c2c\u0c21\u0c24\u0c3e\u0c2f\u0c3f.",
+ "success": {
+ "saved": "\u0c35\u0c3f\u0c1c\u0c2f\u0c35\u0c02\u0c24\u0c02\u0c17\u0c3e \u0c38\u0c47\u0c35\u0c4d \u0c1a\u0c47\u0c2f\u0c2c\u0c21\u0c3f\u0c02\u0c26\u0c3f"
+ }
+ },
+ "alerts": {
+ "info": "Info",
+ "note": "Note",
+ "tip": "Tip",
+ "important": "Important",
+ "warning": "Warning",
+ "caution": "Caution",
+ "debug": "Debug",
+ "example": "Example",
+ "success": "Success",
+ "help": "Help",
+ "idea": "Idea",
+ "pending": "Pending",
+ "security": "Security",
+ "beta": "Beta",
+ "best-practice": "Best Practice"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/zh-CN.json b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/zh-CN.json
new file mode 100644
index 00000000..ae336fc3
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/.chainlit/translations/zh-CN.json
@@ -0,0 +1,214 @@
+{
+ "common": {
+ "actions": {
+ "cancel": "\u53d6\u6d88",
+ "confirm": "\u786e\u8ba4",
+ "continue": "\u7ee7\u7eed",
+ "goBack": "\u8fd4\u56de",
+ "reset": "\u91cd\u7f6e",
+ "submit": "\u63d0\u4ea4"
+ },
+ "status": {
+ "loading": "\u52a0\u8f7d\u4e2d...",
+ "error": {
+ "default": "\u53d1\u751f\u9519\u8bef",
+ "serverConnection": "\u65e0\u6cd5\u8fde\u63a5\u5230\u670d\u52a1\u5668"
+ }
+ }
+ },
+ "auth": {
+ "login": {
+ "title": "\u767b\u5f55\u4ee5\u8bbf\u95ee\u5e94\u7528",
+ "form": {
+ "email": {
+ "label": "\u7535\u5b50\u90ae\u7bb1",
+ "required": "\u90ae\u7bb1\u662f\u5fc5\u586b\u9879"
+ },
+ "password": {
+ "label": "\u5bc6\u7801",
+ "required": "\u5bc6\u7801\u662f\u5fc5\u586b\u9879"
+ },
+ "actions": {
+ "signin": "\u767b\u5f55"
+ },
+ "alternativeText": {
+ "or": "\u6216"
+ }
+ },
+ "errors": {
+ "default": "\u65e0\u6cd5\u767b\u5f55",
+ "signin": "\u8bf7\u5c1d\u8bd5\u4f7f\u7528\u5176\u4ed6\u8d26\u53f7\u767b\u5f55",
+ "oauthSignin": "\u8bf7\u5c1d\u8bd5\u4f7f\u7528\u5176\u4ed6\u8d26\u53f7\u767b\u5f55",
+ "redirectUriMismatch": "\u91cd\u5b9a\u5411URI\u4e0eOAuth\u5e94\u7528\u914d\u7f6e\u4e0d\u5339\u914d",
+ "oauthCallback": "\u8bf7\u5c1d\u8bd5\u4f7f\u7528\u5176\u4ed6\u8d26\u53f7\u767b\u5f55",
+ "oauthCreateAccount": "\u8bf7\u5c1d\u8bd5\u4f7f\u7528\u5176\u4ed6\u8d26\u53f7\u767b\u5f55",
+ "emailCreateAccount": "\u8bf7\u5c1d\u8bd5\u4f7f\u7528\u5176\u4ed6\u8d26\u53f7\u767b\u5f55",
+ "callback": "\u8bf7\u5c1d\u8bd5\u4f7f\u7528\u5176\u4ed6\u8d26\u53f7\u767b\u5f55",
+ "oauthAccountNotLinked": "\u4e3a\u786e\u8ba4\u60a8\u7684\u8eab\u4efd\uff0c\u8bf7\u4f7f\u7528\u539f\u59cb\u8d26\u53f7\u767b\u5f55",
+ "emailSignin": "\u90ae\u4ef6\u53d1\u9001\u5931\u8d25",
+ "emailVerify": "\u8bf7\u9a8c\u8bc1\u60a8\u7684\u90ae\u7bb1\uff0c\u65b0\u7684\u9a8c\u8bc1\u90ae\u4ef6\u5df2\u53d1\u9001",
+ "credentialsSignin": "\u767b\u5f55\u5931\u8d25\u3002\u8bf7\u68c0\u67e5\u60a8\u63d0\u4f9b\u7684\u4fe1\u606f\u662f\u5426\u6b63\u786e",
+ "sessionRequired": "\u8bf7\u767b\u5f55\u4ee5\u8bbf\u95ee\u6b64\u9875\u9762"
+ }
+ },
+ "provider": {
+ "continue": "\u7ee7\u7eed\u4f7f\u7528{{provider}}"
+ }
+ },
+ "chat": {
+ "input": {
+ "placeholder": "\u5728\u6b64\u8f93\u5165\u60a8\u7684\u6d88\u606f...",
+ "actions": {
+ "send": "\u53d1\u9001\u6d88\u606f",
+ "stop": "\u505c\u6b62\u4efb\u52a1",
+ "attachFiles": "\u9644\u52a0\u6587\u4ef6"
+ }
+ },
+ "speech": {
+ "start": "\u5f00\u59cb\u5f55\u97f3",
+ "stop": "\u505c\u6b62\u5f55\u97f3",
+ "connecting": "\u8fde\u63a5\u4e2d"
+ },
+ "fileUpload": {
+ "dragDrop": "\u5c06\u6587\u4ef6\u62d6\u653e\u5230\u8fd9\u91cc",
+ "browse": "\u6d4f\u89c8\u6587\u4ef6",
+ "sizeLimit": "\u9650\u5236\uff1a",
+ "errors": {
+ "failed": "\u4e0a\u4f20\u5931\u8d25",
+ "cancelled": "\u5df2\u53d6\u6d88\u4e0a\u4f20"
+ }
+ },
+ "messages": {
+ "status": {
+ "using": "\u4f7f\u7528\u4e2d",
+ "used": "\u5df2\u4f7f\u7528"
+ },
+ "actions": {
+ "copy": {
+ "button": "\u590d\u5236\u5230\u526a\u8d34\u677f",
+ "success": "\u5df2\u590d\u5236\uff01"
+ }
+ },
+ "feedback": {
+ "positive": "\u6709\u5e2e\u52a9",
+ "negative": "\u6ca1\u6709\u5e2e\u52a9",
+ "edit": "\u7f16\u8f91\u53cd\u9988",
+ "dialog": {
+ "title": "\u6dfb\u52a0\u8bc4\u8bba",
+ "submit": "\u63d0\u4ea4\u53cd\u9988"
+ },
+ "status": {
+ "updating": "\u66f4\u65b0\u4e2d",
+ "updated": "\u53cd\u9988\u5df2\u66f4\u65b0"
+ }
+ }
+ },
+ "history": {
+ "title": "\u6700\u8fd1\u8f93\u5165",
+ "empty": "\u7a7a\u7a7a\u5982\u4e5f...",
+ "show": "\u663e\u793a\u5386\u53f2"
+ },
+ "settings": {
+ "title": "\u8bbe\u7f6e\u9762\u677f"
+ },
+ "watermark": "\u6280\u672f\u652f\u6301"
+ },
+ "threadHistory": {
+ "sidebar": {
+ "title": "\u5386\u53f2\u5bf9\u8bdd",
+ "filters": {
+ "search": "\u641c\u7d22",
+ "placeholder": "\u641c\u7d22\u4f1a\u8bdd..."
+ },
+ "timeframes": {
+ "today": "\u4eca\u5929",
+ "yesterday": "\u6628\u5929",
+ "previous7days": "\u8fc7\u53bb7\u5929",
+ "previous30days": "\u8fc7\u53bb30\u5929"
+ },
+ "empty": "\u672a\u627e\u5230\u5bf9\u8bdd",
+ "actions": {
+ "close": "\u5173\u95ed\u4fa7\u8fb9\u680f",
+ "open": "\u6253\u5f00\u4fa7\u8fb9\u680f"
+ }
+ },
+ "thread": {
+ "untitled": "\u672a\u547d\u540d\u5bf9\u8bdd",
+ "menu": {
+ "rename": "\u91cd\u547d\u540d",
+ "delete": "\u5220\u9664"
+ },
+ "actions": {
+ "delete": {
+ "title": "\u786e\u8ba4\u5220\u9664",
+ "description": "\u8fd9\u5c06\u5220\u9664\u8be5\u5bf9\u8bdd\u53ca\u5176\u6240\u6709\u6d88\u606f\u548c\u5143\u7d20\u3002\u6b64\u64cd\u4f5c\u65e0\u6cd5\u64a4\u9500",
+ "success": "\u5bf9\u8bdd\u5df2\u5220\u9664",
+ "inProgress": "\u6b63\u5728\u5220\u9664\u5bf9\u8bdd"
+ },
+ "rename": {
+ "title": "\u91cd\u547d\u540d\u5bf9\u8bdd",
+ "description": "\u4e3a\u6b64\u5bf9\u8bdd\u8f93\u5165\u65b0\u540d\u79f0",
+ "form": {
+ "name": {
+ "label": "\u540d\u79f0",
+ "placeholder": "\u8f93\u5165\u65b0\u540d\u79f0"
+ }
+ },
+ "success": "\u5bf9\u8bdd\u5df2\u91cd\u547d\u540d\uff01",
+ "inProgress": "\u6b63\u5728\u91cd\u547d\u540d\u5bf9\u8bdd"
+ }
+ }
+ }
+ },
+ "navigation": {
+ "header": {
+ "chat": "\u804a\u5929",
+ "readme": "\u8bf4\u660e",
+ "theme": {
+ "light": "\u6d45\u8272\u4e3b\u9898",
+ "dark": "\u6df1\u8272\u4e3b\u9898",
+ "system": "\u8ddf\u968f\u7cfb\u7edf"
+ }
+ },
+ "newChat": {
+ "button": "\u65b0\u5efa\u5bf9\u8bdd",
+ "dialog": {
+ "title": "\u521b\u5efa\u65b0\u5bf9\u8bdd",
+ "description": "\u8fd9\u5c06\u6e05\u9664\u60a8\u5f53\u524d\u7684\u804a\u5929\u8bb0\u5f55\u3002\u786e\u5b9a\u8981\u7ee7\u7eed\u5417\uff1f",
+ "tooltip": "\u65b0\u5efa\u5bf9\u8bdd"
+ }
+ },
+ "user": {
+ "menu": {
+ "settings": "\u8bbe\u7f6e",
+ "settingsKey": "S",
+ "apiKeys": "API\u5bc6\u94a5",
+ "logout": "\u9000\u51fa\u767b\u5f55"
+ }
+ }
+ },
+ "apiKeys": {
+ "title": "\u6240\u9700API\u5bc6\u94a5",
+ "description": "\u4f7f\u7528\u6b64\u5e94\u7528\u9700\u8981\u4ee5\u4e0bAPI\u5bc6\u94a5\u3002\u8fd9\u4e9b\u5bc6\u94a5\u5b58\u50a8\u5728\u60a8\u8bbe\u5907\u7684\u672c\u5730\u5b58\u50a8\u4e2d\u3002",
+ "success": {
+ "saved": "\u4fdd\u5b58\u6210\u529f"
+ }
+ },
+ "alerts": {
+ "info": "\u4fe1\u606f",
+ "note": "\u6ce8\u91ca",
+ "tip": "\u63d0\u793a",
+ "important": "\u91cd\u8981",
+ "warning": "\u8b66\u544a",
+ "caution": "\u6ce8\u610f",
+ "debug": "\u8c03\u8bd5",
+ "example": "\u793a\u4f8b",
+ "success": "\u6210\u529f",
+ "help": "\u5e2e\u52a9",
+ "idea": "\u60f3\u6cd5",
+ "pending": "\u5f85\u5904\u7406",
+ "security": "\u5b89\u5168",
+ "beta": "\u6d4b\u8bd5",
+ "best-practice": "\u6700\u4f73\u5b9e\u8df5"
+ }
+}
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/before/.env.example b/examples/agent/langgraph-fsi-agent/before/.env.example
new file mode 100644
index 00000000..7b81cbac
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/.env.example
@@ -0,0 +1,7 @@
+# AI services
+OPENAI_API_KEY= # Your OpenAI API key
+# OPENAI_BASE_URL= # Optional if you are not using the public OpenAI API.
+MODEL_NAME= # The name of the model you want to use.
+
+# The API key for Pinecone
+PINECONE_API_KEY= # Your Pinecone API key.
diff --git a/examples/agent/langgraph-fsi-agent/before/.gitignore b/examples/agent/langgraph-fsi-agent/before/.gitignore
new file mode 100644
index 00000000..a1dd94cb
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/.gitignore
@@ -0,0 +1,126 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a PyInstaller build script
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# VS Code
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+
+# macOS
+.DS_Store
+
+# ruff
+.ruff_cache
\ No newline at end of file
diff --git a/examples/agent/langgraph-fsi-agent/before/LICENSE b/examples/agent/langgraph-fsi-agent/before/LICENSE
new file mode 100644
index 00000000..d5857e3c
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2025 Jim Bennett
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/examples/agent/langgraph-fsi-agent/before/app.py b/examples/agent/langgraph-fsi-agent/before/app.py
new file mode 100644
index 00000000..e9a58c68
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/app.py
@@ -0,0 +1,80 @@
+"""
+A demo Financial Services Agent using Chainlit and LangGraph, with Splunk AO as the evaluation platform.
+"""
+
+from typing import Any
+import chainlit as cl
+
+from langchain.schema.runnable.config import RunnableConfig
+from langchain_core.callbacks import Callbacks
+from langchain_core.messages import HumanMessage, AIMessage
+
+from dotenv import load_dotenv
+
+from src.galileo_langgraph_fsi_agent.agents.supervisor_agent import (
+ create_supervisor_agent,
+)
+
+# Load environment variables from .env file
+load_dotenv()
+
+
+# Build the agent graph
+supervisor_agent = create_supervisor_agent()
+
+
+@cl.on_chat_start
+async def on_chat_start() -> None:
+ """
+ Handle the start of a chat session.
+
+ This function is called when a new chat session starts.
+ It initializes the chat with a welcome message.
+ """
+
+ # Send a welcome message to the user
+ await cl.Message(content="Welcome to the Brahe Bank assistant! How can I help you today?").send()
+
+
+@cl.on_message
+async def main(msg: cl.Message) -> None:
+ """
+ Handle the message from the user.
+
+ param message: The message object containing user input.
+ """
+ # Create a config using the current Chainlit session ID. This is linked to the memory saver in the graph
+ # to allow you to continue the conversation with the same context.
+ config: dict[str, Any] = {"configurable": {"thread_id": cl.context.session.id}}
+
+ # Prepare the final answer message to stream the response back to the user
+ final_answer = cl.Message(content="")
+
+ # Build the messages dictionary with the user's message
+ messages: dict[str, Any] = {"messages": [HumanMessage(content=msg.content)]}
+
+ callbacks: Callbacks = []
+
+ # Set up the config for the streaming response
+ runnable_config = RunnableConfig(callbacks=callbacks, **config)
+
+ # Call the graph with the user's message and stream the response back to the user
+ async for response_msg in supervisor_agent.astream(input=messages, stream_mode="updates", config=runnable_config):
+ # Check for a response from the supervisor agent with the final message
+ if supervisor_agent.name in response_msg and "messages" in response_msg[supervisor_agent.name]:
+ # Get the last message from the supervisor's response
+ message = response_msg[supervisor_agent.name]["messages"][-1]
+ # If it is an AI message, then it is the final answer
+ if isinstance(message, AIMessage) and message.content:
+ await final_answer.stream_token(message.content) # type: ignore
+
+ # Send the final answer message to the user
+ await final_answer.send()
+
+
+# This is the entry point for running the Chainlit application used for debugging
+# Otherwise to run this with hot reload, use `chainlit run app.py -w`
+if __name__ == "__main__":
+ from chainlit.cli import run_chainlit
+
+ run_chainlit(__file__)
diff --git a/examples/agent/langgraph-fsi-agent/before/chainlit.md b/examples/agent/langgraph-fsi-agent/before/chainlit.md
new file mode 100644
index 00000000..4507ac46
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/chainlit.md
@@ -0,0 +1,14 @@
+# Welcome to Chainlit! 🚀🤖
+
+Hi there, Developer! 👋 We're excited to have you on board. Chainlit is a powerful tool designed to help you prototype, debug and share applications built on top of LLMs.
+
+## Useful Links 🔗
+
+- **Documentation:** Get started with our comprehensive [Chainlit Documentation](https://docs.chainlit.io) 📚
+- **Discord Community:** Join our friendly [Chainlit Discord](https://discord.gg/k73SQ3FyUh) to ask questions, share your projects, and connect with other developers! 💬
+
+We can't wait to see what you create with Chainlit! Happy coding! 💻😊
+
+## Welcome screen
+
+To modify the welcome screen, edit the `chainlit.md` file at the root of your project. If you do not want a welcome screen, just leave this file empty.
diff --git a/examples/agent/langgraph-fsi-agent/before/images/bot-demo.gif b/examples/agent/langgraph-fsi-agent/before/images/bot-demo.gif
new file mode 100644
index 00000000..ea25d775
Binary files /dev/null and b/examples/agent/langgraph-fsi-agent/before/images/bot-demo.gif differ
diff --git a/examples/agent/langgraph-fsi-agent/before/poetry.lock b/examples/agent/langgraph-fsi-agent/before/poetry.lock
new file mode 100644
index 00000000..3b82dd1c
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/poetry.lock
@@ -0,0 +1,5144 @@
+# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand.
+
+[[package]]
+name = "aiofiles"
+version = "24.1.0"
+description = "File support for asyncio."
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5"},
+ {file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"},
+]
+
+[[package]]
+name = "aiohappyeyeballs"
+version = "2.6.1"
+description = "Happy Eyeballs for asyncio"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8"},
+ {file = "aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558"},
+]
+
+[[package]]
+name = "aiohttp"
+version = "3.12.13"
+description = "Async http client/server framework (asyncio)"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "aiohttp-3.12.13-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5421af8f22a98f640261ee48aae3a37f0c41371e99412d55eaf2f8a46d5dad29"},
+ {file = "aiohttp-3.12.13-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0fcda86f6cb318ba36ed8f1396a6a4a3fd8f856f84d426584392083d10da4de0"},
+ {file = "aiohttp-3.12.13-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cd71c9fb92aceb5a23c4c39d8ecc80389c178eba9feab77f19274843eb9412d"},
+ {file = "aiohttp-3.12.13-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34ebf1aca12845066c963016655dac897651e1544f22a34c9b461ac3b4b1d3aa"},
+ {file = "aiohttp-3.12.13-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:893a4639694c5b7edd4bdd8141be296042b6806e27cc1d794e585c43010cc294"},
+ {file = "aiohttp-3.12.13-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:663d8ee3ffb3494502ebcccb49078faddbb84c1d870f9c1dd5a29e85d1f747ce"},
+ {file = "aiohttp-3.12.13-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0f8f6a85a0006ae2709aa4ce05749ba2cdcb4b43d6c21a16c8517c16593aabe"},
+ {file = "aiohttp-3.12.13-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1582745eb63df267c92d8b61ca655a0ce62105ef62542c00a74590f306be8cb5"},
+ {file = "aiohttp-3.12.13-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d59227776ee2aa64226f7e086638baa645f4b044f2947dbf85c76ab11dcba073"},
+ {file = "aiohttp-3.12.13-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06b07c418bde1c8e737d8fa67741072bd3f5b0fb66cf8c0655172188c17e5fa6"},
+ {file = "aiohttp-3.12.13-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:9445c1842680efac0f81d272fd8db7163acfcc2b1436e3f420f4c9a9c5a50795"},
+ {file = "aiohttp-3.12.13-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:09c4767af0b0b98c724f5d47f2bf33395c8986995b0a9dab0575ca81a554a8c0"},
+ {file = "aiohttp-3.12.13-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f3854fbde7a465318ad8d3fc5bef8f059e6d0a87e71a0d3360bb56c0bf87b18a"},
+ {file = "aiohttp-3.12.13-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2332b4c361c05ecd381edb99e2a33733f3db906739a83a483974b3df70a51b40"},
+ {file = "aiohttp-3.12.13-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1561db63fa1b658cd94325d303933553ea7d89ae09ff21cc3bcd41b8521fbbb6"},
+ {file = "aiohttp-3.12.13-cp310-cp310-win32.whl", hash = "sha256:a0be857f0b35177ba09d7c472825d1b711d11c6d0e8a2052804e3b93166de1ad"},
+ {file = "aiohttp-3.12.13-cp310-cp310-win_amd64.whl", hash = "sha256:fcc30ad4fb5cb41a33953292d45f54ef4066746d625992aeac33b8c681173178"},
+ {file = "aiohttp-3.12.13-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7c229b1437aa2576b99384e4be668af1db84b31a45305d02f61f5497cfa6f60c"},
+ {file = "aiohttp-3.12.13-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:04076d8c63471e51e3689c93940775dc3d12d855c0c80d18ac5a1c68f0904358"},
+ {file = "aiohttp-3.12.13-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:55683615813ce3601640cfaa1041174dc956d28ba0511c8cbd75273eb0587014"},
+ {file = "aiohttp-3.12.13-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:921bc91e602d7506d37643e77819cb0b840d4ebb5f8d6408423af3d3bf79a7b7"},
+ {file = "aiohttp-3.12.13-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e72d17fe0974ddeae8ed86db297e23dba39c7ac36d84acdbb53df2e18505a013"},
+ {file = "aiohttp-3.12.13-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0653d15587909a52e024a261943cf1c5bdc69acb71f411b0dd5966d065a51a47"},
+ {file = "aiohttp-3.12.13-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a77b48997c66722c65e157c06c74332cdf9c7ad00494b85ec43f324e5c5a9b9a"},
+ {file = "aiohttp-3.12.13-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6946bae55fd36cfb8e4092c921075cde029c71c7cb571d72f1079d1e4e013bc"},
+ {file = "aiohttp-3.12.13-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f95db8c8b219bcf294a53742c7bda49b80ceb9d577c8e7aa075612b7f39ffb7"},
+ {file = "aiohttp-3.12.13-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:03d5eb3cfb4949ab4c74822fb3326cd9655c2b9fe22e4257e2100d44215b2e2b"},
+ {file = "aiohttp-3.12.13-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:6383dd0ffa15515283c26cbf41ac8e6705aab54b4cbb77bdb8935a713a89bee9"},
+ {file = "aiohttp-3.12.13-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6548a411bc8219b45ba2577716493aa63b12803d1e5dc70508c539d0db8dbf5a"},
+ {file = "aiohttp-3.12.13-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:81b0fcbfe59a4ca41dc8f635c2a4a71e63f75168cc91026c61be665945739e2d"},
+ {file = "aiohttp-3.12.13-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:6a83797a0174e7995e5edce9dcecc517c642eb43bc3cba296d4512edf346eee2"},
+ {file = "aiohttp-3.12.13-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5734d8469a5633a4e9ffdf9983ff7cdb512524645c7a3d4bc8a3de45b935ac3"},
+ {file = "aiohttp-3.12.13-cp311-cp311-win32.whl", hash = "sha256:fef8d50dfa482925bb6b4c208b40d8e9fa54cecba923dc65b825a72eed9a5dbd"},
+ {file = "aiohttp-3.12.13-cp311-cp311-win_amd64.whl", hash = "sha256:9a27da9c3b5ed9d04c36ad2df65b38a96a37e9cfba6f1381b842d05d98e6afe9"},
+ {file = "aiohttp-3.12.13-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0aa580cf80558557285b49452151b9c69f2fa3ad94c5c9e76e684719a8791b73"},
+ {file = "aiohttp-3.12.13-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b103a7e414b57e6939cc4dece8e282cfb22043efd0c7298044f6594cf83ab347"},
+ {file = "aiohttp-3.12.13-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:78f64e748e9e741d2eccff9597d09fb3cd962210e5b5716047cbb646dc8fe06f"},
+ {file = "aiohttp-3.12.13-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29c955989bf4c696d2ededc6b0ccb85a73623ae6e112439398935362bacfaaf6"},
+ {file = "aiohttp-3.12.13-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d640191016763fab76072c87d8854a19e8e65d7a6fcfcbf017926bdbbb30a7e5"},
+ {file = "aiohttp-3.12.13-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4dc507481266b410dede95dd9f26c8d6f5a14315372cc48a6e43eac652237d9b"},
+ {file = "aiohttp-3.12.13-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8a94daa873465d518db073bd95d75f14302e0208a08e8c942b2f3f1c07288a75"},
+ {file = "aiohttp-3.12.13-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177f52420cde4ce0bb9425a375d95577fe082cb5721ecb61da3049b55189e4e6"},
+ {file = "aiohttp-3.12.13-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f7df1f620ec40f1a7fbcb99ea17d7326ea6996715e78f71a1c9a021e31b96b8"},
+ {file = "aiohttp-3.12.13-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3062d4ad53b36e17796dce1c0d6da0ad27a015c321e663657ba1cc7659cfc710"},
+ {file = "aiohttp-3.12.13-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:8605e22d2a86b8e51ffb5253d9045ea73683d92d47c0b1438e11a359bdb94462"},
+ {file = "aiohttp-3.12.13-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:54fbbe6beafc2820de71ece2198458a711e224e116efefa01b7969f3e2b3ddae"},
+ {file = "aiohttp-3.12.13-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:050bd277dfc3768b606fd4eae79dd58ceda67d8b0b3c565656a89ae34525d15e"},
+ {file = "aiohttp-3.12.13-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2637a60910b58f50f22379b6797466c3aa6ae28a6ab6404e09175ce4955b4e6a"},
+ {file = "aiohttp-3.12.13-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e986067357550d1aaa21cfe9897fa19e680110551518a5a7cf44e6c5638cb8b5"},
+ {file = "aiohttp-3.12.13-cp312-cp312-win32.whl", hash = "sha256:ac941a80aeea2aaae2875c9500861a3ba356f9ff17b9cb2dbfb5cbf91baaf5bf"},
+ {file = "aiohttp-3.12.13-cp312-cp312-win_amd64.whl", hash = "sha256:671f41e6146a749b6c81cb7fd07f5a8356d46febdaaaf07b0e774ff04830461e"},
+ {file = "aiohttp-3.12.13-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d4a18e61f271127465bdb0e8ff36e8f02ac4a32a80d8927aa52371e93cd87938"},
+ {file = "aiohttp-3.12.13-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:532542cb48691179455fab429cdb0d558b5e5290b033b87478f2aa6af5d20ace"},
+ {file = "aiohttp-3.12.13-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d7eea18b52f23c050ae9db5d01f3d264ab08f09e7356d6f68e3f3ac2de9dfabb"},
+ {file = "aiohttp-3.12.13-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad7c8e5c25f2a26842a7c239de3f7b6bfb92304593ef997c04ac49fb703ff4d7"},
+ {file = "aiohttp-3.12.13-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6af355b483e3fe9d7336d84539fef460120c2f6e50e06c658fe2907c69262d6b"},
+ {file = "aiohttp-3.12.13-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a95cf9f097498f35c88e3609f55bb47b28a5ef67f6888f4390b3d73e2bac6177"},
+ {file = "aiohttp-3.12.13-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8ed8c38a1c584fe99a475a8f60eefc0b682ea413a84c6ce769bb19a7ff1c5ef"},
+ {file = "aiohttp-3.12.13-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7a0b9170d5d800126b5bc89d3053a2363406d6e327afb6afaeda2d19ee8bb103"},
+ {file = "aiohttp-3.12.13-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:372feeace612ef8eb41f05ae014a92121a512bd5067db8f25101dd88a8db11da"},
+ {file = "aiohttp-3.12.13-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a946d3702f7965d81f7af7ea8fb03bb33fe53d311df48a46eeca17e9e0beed2d"},
+ {file = "aiohttp-3.12.13-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a0c4725fae86555bbb1d4082129e21de7264f4ab14baf735278c974785cd2041"},
+ {file = "aiohttp-3.12.13-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9b28ea2f708234f0a5c44eb6c7d9eb63a148ce3252ba0140d050b091b6e842d1"},
+ {file = "aiohttp-3.12.13-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d4f5becd2a5791829f79608c6f3dc745388162376f310eb9c142c985f9441cc1"},
+ {file = "aiohttp-3.12.13-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:60f2ce6b944e97649051d5f5cc0f439360690b73909230e107fd45a359d3e911"},
+ {file = "aiohttp-3.12.13-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:69fc1909857401b67bf599c793f2183fbc4804717388b0b888f27f9929aa41f3"},
+ {file = "aiohttp-3.12.13-cp313-cp313-win32.whl", hash = "sha256:7d7e68787a2046b0e44ba5587aa723ce05d711e3a3665b6b7545328ac8e3c0dd"},
+ {file = "aiohttp-3.12.13-cp313-cp313-win_amd64.whl", hash = "sha256:5a178390ca90419bfd41419a809688c368e63c86bd725e1186dd97f6b89c2706"},
+ {file = "aiohttp-3.12.13-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:36f6c973e003dc9b0bb4e8492a643641ea8ef0e97ff7aaa5c0f53d68839357b4"},
+ {file = "aiohttp-3.12.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6cbfc73179bd67c229eb171e2e3745d2afd5c711ccd1e40a68b90427f282eab1"},
+ {file = "aiohttp-3.12.13-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1e8b27b2d414f7e3205aa23bb4a692e935ef877e3a71f40d1884f6e04fd7fa74"},
+ {file = "aiohttp-3.12.13-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eabded0c2b2ef56243289112c48556c395d70150ce4220d9008e6b4b3dd15690"},
+ {file = "aiohttp-3.12.13-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:003038e83f1a3ff97409999995ec02fe3008a1d675478949643281141f54751d"},
+ {file = "aiohttp-3.12.13-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b6f46613031dbc92bdcaad9c4c22c7209236ec501f9c0c5f5f0b6a689bf50f3"},
+ {file = "aiohttp-3.12.13-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c332c6bb04650d59fb94ed96491f43812549a3ba6e7a16a218e612f99f04145e"},
+ {file = "aiohttp-3.12.13-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fea41a2c931fb582cb15dc86a3037329e7b941df52b487a9f8b5aa960153cbd"},
+ {file = "aiohttp-3.12.13-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:846104f45d18fb390efd9b422b27d8f3cf8853f1218c537f36e71a385758c896"},
+ {file = "aiohttp-3.12.13-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d6c85ac7dd350f8da2520bac8205ce99df4435b399fa7f4dc4a70407073e390"},
+ {file = "aiohttp-3.12.13-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:5a1ecce0ed281bec7da8550da052a6b89552db14d0a0a45554156f085a912f48"},
+ {file = "aiohttp-3.12.13-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:5304d74867028cca8f64f1cc1215eb365388033c5a691ea7aa6b0dc47412f495"},
+ {file = "aiohttp-3.12.13-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:64d1f24ee95a2d1e094a4cd7a9b7d34d08db1bbcb8aa9fb717046b0a884ac294"},
+ {file = "aiohttp-3.12.13-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:119c79922a7001ca6a9e253228eb39b793ea994fd2eccb79481c64b5f9d2a055"},
+ {file = "aiohttp-3.12.13-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:bb18f00396d22e2f10cd8825d671d9f9a3ba968d708a559c02a627536b36d91c"},
+ {file = "aiohttp-3.12.13-cp39-cp39-win32.whl", hash = "sha256:0022de47ef63fd06b065d430ac79c6b0bd24cdae7feaf0e8c6bac23b805a23a8"},
+ {file = "aiohttp-3.12.13-cp39-cp39-win_amd64.whl", hash = "sha256:29e08111ccf81b2734ae03f1ad1cb03b9615e7d8f616764f22f71209c094f122"},
+ {file = "aiohttp-3.12.13.tar.gz", hash = "sha256:47e2da578528264a12e4e3dd8dd72a7289e5f812758fe086473fab037a10fcce"},
+]
+
+[package.dependencies]
+aiohappyeyeballs = ">=2.5.0"
+aiosignal = ">=1.1.2"
+attrs = ">=17.3.0"
+frozenlist = ">=1.1.1"
+multidict = ">=4.5,<7.0"
+propcache = ">=0.2.0"
+yarl = ">=1.17.0,<2.0"
+
+[package.extras]
+speedups = ["Brotli ; platform_python_implementation == \"CPython\"", "aiodns (>=3.3.0)", "brotlicffi ; platform_python_implementation != \"CPython\""]
+
+[[package]]
+name = "aiohttp-retry"
+version = "2.9.1"
+description = "Simple retry client for aiohttp"
+optional = false
+python-versions = ">=3.7"
+groups = ["main"]
+files = [
+ {file = "aiohttp_retry-2.9.1-py3-none-any.whl", hash = "sha256:66d2759d1921838256a05a3f80ad7e724936f083e35be5abb5e16eed6be6dc54"},
+ {file = "aiohttp_retry-2.9.1.tar.gz", hash = "sha256:8eb75e904ed4ee5c2ec242fefe85bf04240f685391c4879d8f541d6028ff01f1"},
+]
+
+[package.dependencies]
+aiohttp = "*"
+
+[[package]]
+name = "aiosignal"
+version = "1.4.0"
+description = "aiosignal: a list of registered asynchronous callbacks"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e"},
+ {file = "aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7"},
+]
+
+[package.dependencies]
+frozenlist = ">=1.1.0"
+typing-extensions = {version = ">=4.2", markers = "python_version < \"3.13\""}
+
+[[package]]
+name = "annotated-types"
+version = "0.7.0"
+description = "Reusable constraint types to use with typing.Annotated"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
+ {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
+]
+
+[[package]]
+name = "anthropic"
+version = "0.57.1"
+description = "The official Python library for the anthropic API"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "anthropic-0.57.1-py3-none-any.whl", hash = "sha256:33afc1f395af207d07ff1bffc0a3d1caac53c371793792569c5d2f09283ea306"},
+ {file = "anthropic-0.57.1.tar.gz", hash = "sha256:7815dd92245a70d21f65f356f33fc80c5072eada87fb49437767ea2918b2c4b0"},
+]
+
+[package.dependencies]
+anyio = ">=3.5.0,<5"
+distro = ">=1.7.0,<2"
+httpx = ">=0.25.0,<1"
+jiter = ">=0.4.0,<1"
+pydantic = ">=1.9.0,<3"
+sniffio = "*"
+typing-extensions = ">=4.10,<5"
+
+[package.extras]
+aiohttp = ["aiohttp", "httpx-aiohttp (>=0.1.6)"]
+bedrock = ["boto3 (>=1.28.57)", "botocore (>=1.31.57)"]
+vertex = ["google-auth[requests] (>=2,<3)"]
+
+[[package]]
+name = "anyio"
+version = "4.9.0"
+description = "High level compatibility layer for multiple asynchronous event loop implementations"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c"},
+ {file = "anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028"},
+]
+
+[package.dependencies]
+idna = ">=2.8"
+sniffio = ">=1.1"
+typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""}
+
+[package.extras]
+doc = ["Sphinx (>=8.2,<9.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"]
+test = ["anyio[trio]", "blockbuster (>=1.5.23)", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""]
+trio = ["trio (>=0.26.1)"]
+
+[[package]]
+name = "asyncer"
+version = "0.0.7"
+description = "Asyncer, async and await, focused on developer experience."
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "asyncer-0.0.7-py3-none-any.whl", hash = "sha256:f0d579d4f67c4ead52ede3a45c854f462cae569058a8a6a68a4ebccac1c335d8"},
+ {file = "asyncer-0.0.7.tar.gz", hash = "sha256:d5e563fb0f56eb87b97257984703658a4f5bbdb52ff851b3e8ed864cc200b1d2"},
+]
+
+[package.dependencies]
+anyio = ">=3.4.0,<5.0"
+
+[[package]]
+name = "attrs"
+version = "25.3.0"
+description = "Classes Without Boilerplate"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3"},
+ {file = "attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b"},
+]
+
+[package.extras]
+benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
+cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
+dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
+docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier"]
+tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
+tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""]
+
+[[package]]
+name = "backoff"
+version = "2.2.1"
+description = "Function decoration for backoff and retry"
+optional = false
+python-versions = ">=3.7,<4.0"
+groups = ["main"]
+files = [
+ {file = "backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8"},
+ {file = "backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba"},
+]
+
+[[package]]
+name = "bidict"
+version = "0.23.1"
+description = "The bidirectional mapping library for Python."
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "bidict-0.23.1-py3-none-any.whl", hash = "sha256:5dae8d4d79b552a71cbabc7deb25dfe8ce710b17ff41711e13010ead2abfc3e5"},
+ {file = "bidict-0.23.1.tar.gz", hash = "sha256:03069d763bc387bbd20e7d49914e75fc4132a41937fa3405417e1a5a2d006d71"},
+]
+
+[[package]]
+name = "certifi"
+version = "2025.6.15"
+description = "Python package for providing Mozilla's CA Bundle."
+optional = false
+python-versions = ">=3.7"
+groups = ["main"]
+files = [
+ {file = "certifi-2025.6.15-py3-none-any.whl", hash = "sha256:2e0c7ce7cb5d8f8634ca55d2ba7e6ec2689a2fd6537d8dec1296a477a4910057"},
+ {file = "certifi-2025.6.15.tar.gz", hash = "sha256:d747aa5a8b9bbbb1bb8c22bb13e22bd1f18e9796defa16bab421f7f7a317323b"},
+]
+
+[[package]]
+name = "cffi"
+version = "1.17.1"
+description = "Foreign Function Interface for Python calling C code."
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"},
+ {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"},
+ {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"},
+ {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"},
+ {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"},
+ {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"},
+ {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"},
+ {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"},
+ {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"},
+ {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"},
+ {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"},
+ {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"},
+ {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"},
+ {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"},
+ {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"},
+ {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"},
+ {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"},
+ {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"},
+ {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"},
+ {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"},
+ {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"},
+ {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"},
+ {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"},
+ {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"},
+ {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"},
+ {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"},
+ {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"},
+ {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"},
+ {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"},
+ {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"},
+ {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"},
+ {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"},
+ {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"},
+ {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"},
+ {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"},
+ {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"},
+ {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"},
+ {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"},
+ {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"},
+ {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"},
+ {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"},
+ {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"},
+ {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"},
+]
+
+[package.dependencies]
+pycparser = "*"
+
+[[package]]
+name = "chainlit"
+version = "2.5.5"
+description = "Build Conversational AI."
+optional = false
+python-versions = "<4.0.0,>=3.10"
+groups = ["main"]
+files = [
+ {file = "chainlit-2.5.5-py3-none-any.whl", hash = "sha256:1783c7b868fe41158283b498020fa18a23c39d07319ad9927e429f1e888f6eb5"},
+ {file = "chainlit-2.5.5.tar.gz", hash = "sha256:d6388f93b9089e3a80bc2bd286a157a4a9d8016dc2c806372fd77119bcc0d36c"},
+]
+
+[package.dependencies]
+aiofiles = ">=23.1.0,<25.0.0"
+asyncer = ">=0.0.7,<0.0.8"
+click = ">=8.1.3,<9.0.0"
+dataclasses_json = ">=0.6.7,<0.7.0"
+fastapi = ">=0.115.3,<0.116"
+filetype = ">=1.2.0,<2.0.0"
+httpx = ">=0.23.0"
+lazify = ">=0.4.0,<0.5.0"
+literalai = "0.1.201"
+mcp = ">=1.3.0,<2.0.0"
+nest-asyncio = ">=1.6.0,<2.0.0"
+packaging = ">=23.1"
+pydantic = ">=2.7.2,<3"
+pyjwt = ">=2.8.0,<3.0.0"
+python-dotenv = ">=1.0.0,<2.0.0"
+python-multipart = ">=0.0.18,<0.0.19"
+python-socketio = ">=5.11.0,<6.0.0"
+starlette = ">=0.41.2,<0.42.0"
+syncer = ">=2.0.3,<3.0.0"
+tomli = ">=2.0.1,<3.0.0"
+uptrace = ">=1.29.0,<2.0.0"
+uvicorn = ">=0.25.0"
+watchfiles = ">=0.20.0,<0.21.0"
+
+[[package]]
+name = "charset-normalizer"
+version = "3.4.2"
+description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
+optional = false
+python-versions = ">=3.7"
+groups = ["main"]
+files = [
+ {file = "charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a"},
+ {file = "charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a"},
+ {file = "charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c"},
+ {file = "charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7"},
+ {file = "charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-win32.whl", hash = "sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58"},
+ {file = "charset_normalizer-3.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-win32.whl", hash = "sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7"},
+ {file = "charset_normalizer-3.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-win32.whl", hash = "sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471"},
+ {file = "charset_normalizer-3.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e"},
+ {file = "charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0"},
+ {file = "charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63"},
+]
+
+[[package]]
+name = "chevron"
+version = "0.14.0"
+description = "Mustache templating language renderer"
+optional = false
+python-versions = "*"
+groups = ["main"]
+files = [
+ {file = "chevron-0.14.0-py3-none-any.whl", hash = "sha256:fbf996a709f8da2e745ef763f482ce2d311aa817d287593a5b990d6d6e4f0443"},
+ {file = "chevron-0.14.0.tar.gz", hash = "sha256:87613aafdf6d77b6a90ff073165a61ae5086e21ad49057aa0e53681601800ebf"},
+]
+
+[[package]]
+name = "click"
+version = "8.2.1"
+description = "Composable command line interface toolkit"
+optional = false
+python-versions = ">=3.10"
+groups = ["main"]
+files = [
+ {file = "click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b"},
+ {file = "click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+
+[[package]]
+name = "colorama"
+version = "0.4.6"
+description = "Cross-platform colored terminal text."
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
+groups = ["main"]
+files = [
+ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
+ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
+]
+
+[[package]]
+name = "dataclasses-json"
+version = "0.6.7"
+description = "Easily serialize dataclasses to and from JSON."
+optional = false
+python-versions = "<4.0,>=3.7"
+groups = ["main"]
+files = [
+ {file = "dataclasses_json-0.6.7-py3-none-any.whl", hash = "sha256:0dbf33f26c8d5305befd61b39d2b3414e8a407bedc2834dea9b8d642666fb40a"},
+ {file = "dataclasses_json-0.6.7.tar.gz", hash = "sha256:b6b3e528266ea45b9535223bc53ca645f5208833c29229e847b3f26a1cc55fc0"},
+]
+
+[package.dependencies]
+marshmallow = ">=3.18.0,<4.0.0"
+typing-inspect = ">=0.4.0,<1"
+
+[[package]]
+name = "deprecated"
+version = "1.2.18"
+description = "Python @deprecated decorator to deprecate old python classes, functions or methods."
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
+groups = ["main"]
+files = [
+ {file = "Deprecated-1.2.18-py2.py3-none-any.whl", hash = "sha256:bd5011788200372a32418f888e326a09ff80d0214bd961147cfed01b5c018eec"},
+ {file = "deprecated-1.2.18.tar.gz", hash = "sha256:422b6f6d859da6f2ef57857761bfb392480502a64c3028ca9bbe86085d72115d"},
+]
+
+[package.dependencies]
+wrapt = ">=1.10,<2"
+
+[package.extras]
+dev = ["PyTest", "PyTest-Cov", "bump2version (<1)", "setuptools ; python_version >= \"3.12\"", "tox"]
+
+[[package]]
+name = "distro"
+version = "1.9.0"
+description = "Distro - an OS platform information API"
+optional = false
+python-versions = ">=3.6"
+groups = ["main"]
+files = [
+ {file = "distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2"},
+ {file = "distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed"},
+]
+
+[[package]]
+name = "fastapi"
+version = "0.115.14"
+description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "fastapi-0.115.14-py3-none-any.whl", hash = "sha256:6c0c8bf9420bd58f565e585036d971872472b4f7d3f6c73b698e10cffdefb3ca"},
+ {file = "fastapi-0.115.14.tar.gz", hash = "sha256:b1de15cdc1c499a4da47914db35d0e4ef8f1ce62b624e94e0e5824421df99739"},
+]
+
+[package.dependencies]
+pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0"
+starlette = ">=0.40.0,<0.47.0"
+typing-extensions = ">=4.8.0"
+
+[package.extras]
+all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"]
+standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "jinja2 (>=3.1.5)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"]
+
+[[package]]
+name = "filelock"
+version = "3.18.0"
+description = "A platform independent file lock."
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de"},
+ {file = "filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2"},
+]
+
+[package.extras]
+docs = ["furo (>=2024.8.6)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"]
+testing = ["covdefaults (>=2.3)", "coverage (>=7.6.10)", "diff-cover (>=9.2.1)", "pytest (>=8.3.4)", "pytest-asyncio (>=0.25.2)", "pytest-cov (>=6)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.28.1)"]
+typing = ["typing-extensions (>=4.12.2) ; python_version < \"3.11\""]
+
+[[package]]
+name = "filetype"
+version = "1.2.0"
+description = "Infer file type and MIME type of any file/buffer. No external dependencies."
+optional = false
+python-versions = "*"
+groups = ["main"]
+files = [
+ {file = "filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25"},
+ {file = "filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb"},
+]
+
+[[package]]
+name = "frozenlist"
+version = "1.7.0"
+description = "A list-like structure which implements collections.abc.MutableSequence"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a"},
+ {file = "frozenlist-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:716a9973a2cc963160394f701964fe25012600f3d311f60c790400b00e568b61"},
+ {file = "frozenlist-1.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0fd1bad056a3600047fb9462cff4c5322cebc59ebf5d0a3725e0ee78955001d"},
+ {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3789ebc19cb811163e70fe2bd354cea097254ce6e707ae42e56f45e31e96cb8e"},
+ {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af369aa35ee34f132fcfad5be45fbfcde0e3a5f6a1ec0712857f286b7d20cca9"},
+ {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac64b6478722eeb7a3313d494f8342ef3478dff539d17002f849101b212ef97c"},
+ {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f89f65d85774f1797239693cef07ad4c97fdd0639544bad9ac4b869782eb1981"},
+ {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1073557c941395fdfcfac13eb2456cb8aad89f9de27bae29fabca8e563b12615"},
+ {file = "frozenlist-1.7.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed8d2fa095aae4bdc7fdd80351009a48d286635edffee66bf865e37a9125c50"},
+ {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:24c34bea555fe42d9f928ba0a740c553088500377448febecaa82cc3e88aa1fa"},
+ {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:69cac419ac6a6baad202c85aaf467b65ac860ac2e7f2ac1686dc40dbb52f6577"},
+ {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:960d67d0611f4c87da7e2ae2eacf7ea81a5be967861e0c63cf205215afbfac59"},
+ {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:41be2964bd4b15bf575e5daee5a5ce7ed3115320fb3c2b71fca05582ffa4dc9e"},
+ {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:46d84d49e00c9429238a7ce02dc0be8f6d7cd0cd405abd1bebdc991bf27c15bd"},
+ {file = "frozenlist-1.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15900082e886edb37480335d9d518cec978afc69ccbc30bd18610b7c1b22a718"},
+ {file = "frozenlist-1.7.0-cp310-cp310-win32.whl", hash = "sha256:400ddd24ab4e55014bba442d917203c73b2846391dd42ca5e38ff52bb18c3c5e"},
+ {file = "frozenlist-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:6eb93efb8101ef39d32d50bce242c84bcbddb4f7e9febfa7b524532a239b4464"},
+ {file = "frozenlist-1.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa51e147a66b2d74de1e6e2cf5921890de6b0f4820b257465101d7f37b49fb5a"},
+ {file = "frozenlist-1.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9b35db7ce1cd71d36ba24f80f0c9e7cff73a28d7a74e91fe83e23d27c7828750"},
+ {file = "frozenlist-1.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34a69a85e34ff37791e94542065c8416c1afbf820b68f720452f636d5fb990cd"},
+ {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a646531fa8d82c87fe4bb2e596f23173caec9185bfbca5d583b4ccfb95183e2"},
+ {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:79b2ffbba483f4ed36a0f236ccb85fbb16e670c9238313709638167670ba235f"},
+ {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a26f205c9ca5829cbf82bb2a84b5c36f7184c4316617d7ef1b271a56720d6b30"},
+ {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bcacfad3185a623fa11ea0e0634aac7b691aa925d50a440f39b458e41c561d98"},
+ {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72c1b0fe8fe451b34f12dce46445ddf14bd2a5bcad7e324987194dc8e3a74c86"},
+ {file = "frozenlist-1.7.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61d1a5baeaac6c0798ff6edfaeaa00e0e412d49946c53fae8d4b8e8b3566c4ae"},
+ {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7edf5c043c062462f09b6820de9854bf28cc6cc5b6714b383149745e287181a8"},
+ {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d50ac7627b3a1bd2dcef6f9da89a772694ec04d9a61b66cf87f7d9446b4a0c31"},
+ {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce48b2fece5aeb45265bb7a58259f45027db0abff478e3077e12b05b17fb9da7"},
+ {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fe2365ae915a1fafd982c146754e1de6ab3478def8a59c86e1f7242d794f97d5"},
+ {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:45a6f2fdbd10e074e8814eb98b05292f27bad7d1883afbe009d96abdcf3bc898"},
+ {file = "frozenlist-1.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:21884e23cffabb157a9dd7e353779077bf5b8f9a58e9b262c6caad2ef5f80a56"},
+ {file = "frozenlist-1.7.0-cp311-cp311-win32.whl", hash = "sha256:284d233a8953d7b24f9159b8a3496fc1ddc00f4db99c324bd5fb5f22d8698ea7"},
+ {file = "frozenlist-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:387cbfdcde2f2353f19c2f66bbb52406d06ed77519ac7ee21be0232147c2592d"},
+ {file = "frozenlist-1.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2"},
+ {file = "frozenlist-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb"},
+ {file = "frozenlist-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478"},
+ {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8"},
+ {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08"},
+ {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4"},
+ {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b"},
+ {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e"},
+ {file = "frozenlist-1.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca"},
+ {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df"},
+ {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5"},
+ {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025"},
+ {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01"},
+ {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08"},
+ {file = "frozenlist-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43"},
+ {file = "frozenlist-1.7.0-cp312-cp312-win32.whl", hash = "sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3"},
+ {file = "frozenlist-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a"},
+ {file = "frozenlist-1.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee80eeda5e2a4e660651370ebffd1286542b67e268aa1ac8d6dbe973120ef7ee"},
+ {file = "frozenlist-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d1a81c85417b914139e3a9b995d4a1c84559afc839a93cf2cb7f15e6e5f6ed2d"},
+ {file = "frozenlist-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cbb65198a9132ebc334f237d7b0df163e4de83fb4f2bdfe46c1e654bdb0c5d43"},
+ {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dab46c723eeb2c255a64f9dc05b8dd601fde66d6b19cdb82b2e09cc6ff8d8b5d"},
+ {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6aeac207a759d0dedd2e40745575ae32ab30926ff4fa49b1635def65806fddee"},
+ {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd8c4e58ad14b4fa7802b8be49d47993182fdd4023393899632c88fd8cd994eb"},
+ {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04fb24d104f425da3540ed83cbfc31388a586a7696142004c577fa61c6298c3f"},
+ {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a5c505156368e4ea6b53b5ac23c92d7edc864537ff911d2fb24c140bb175e60"},
+ {file = "frozenlist-1.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bd7eb96a675f18aa5c553eb7ddc24a43c8c18f22e1f9925528128c052cdbe00"},
+ {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:05579bf020096fe05a764f1f84cd104a12f78eaab68842d036772dc6d4870b4b"},
+ {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:376b6222d114e97eeec13d46c486facd41d4f43bab626b7c3f6a8b4e81a5192c"},
+ {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa7e176ebe115379b5b1c95b4096fb1c17cce0847402e227e712c27bdb5a949"},
+ {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3fbba20e662b9c2130dc771e332a99eff5da078b2b2648153a40669a6d0e36ca"},
+ {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f4410a0a601d349dd406b5713fec59b4cee7e71678d5b17edda7f4655a940b"},
+ {file = "frozenlist-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cdfaaec6a2f9327bf43c933c0319a7c429058e8537c508964a133dffee412e"},
+ {file = "frozenlist-1.7.0-cp313-cp313-win32.whl", hash = "sha256:5fc4df05a6591c7768459caba1b342d9ec23fa16195e744939ba5914596ae3e1"},
+ {file = "frozenlist-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba"},
+ {file = "frozenlist-1.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a6f86e4193bb0e235ef6ce3dde5cbabed887e0b11f516ce8a0f4d3b33078ec2d"},
+ {file = "frozenlist-1.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:82d664628865abeb32d90ae497fb93df398a69bb3434463d172b80fc25b0dd7d"},
+ {file = "frozenlist-1.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:912a7e8375a1c9a68325a902f3953191b7b292aa3c3fb0d71a216221deca460b"},
+ {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537c2777167488d539bc5de2ad262efc44388230e5118868e172dd4a552b146"},
+ {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f34560fb1b4c3e30ba35fa9a13894ba39e5acfc5f60f57d8accde65f46cc5e74"},
+ {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acd03d224b0175f5a850edc104ac19040d35419eddad04e7cf2d5986d98427f1"},
+ {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2038310bc582f3d6a09b3816ab01737d60bf7b1ec70f5356b09e84fb7408ab1"},
+ {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c05e4c8e5f36e5e088caa1bf78a687528f83c043706640a92cb76cd6999384"},
+ {file = "frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:765bb588c86e47d0b68f23c1bee323d4b703218037765dcf3f25c838c6fecceb"},
+ {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:32dc2e08c67d86d0969714dd484fd60ff08ff81d1a1e40a77dd34a387e6ebc0c"},
+ {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:c0303e597eb5a5321b4de9c68e9845ac8f290d2ab3f3e2c864437d3c5a30cd65"},
+ {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a47f2abb4e29b3a8d0b530f7c3598badc6b134562b1a5caee867f7c62fee51e3"},
+ {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3d688126c242a6fabbd92e02633414d40f50bb6002fa4cf995a1d18051525657"},
+ {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4e7e9652b3d367c7bd449a727dc79d5043f48b88d0cbfd4f9f1060cf2b414104"},
+ {file = "frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1a85e345b4c43db8b842cab1feb41be5cc0b10a1830e6295b69d7310f99becaf"},
+ {file = "frozenlist-1.7.0-cp313-cp313t-win32.whl", hash = "sha256:3a14027124ddb70dfcee5148979998066897e79f89f64b13328595c4bdf77c81"},
+ {file = "frozenlist-1.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3bf8010d71d4507775f658e9823210b7427be36625b387221642725b515dcf3e"},
+ {file = "frozenlist-1.7.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:cea3dbd15aea1341ea2de490574a4a37ca080b2ae24e4b4f4b51b9057b4c3630"},
+ {file = "frozenlist-1.7.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7d536ee086b23fecc36c2073c371572374ff50ef4db515e4e503925361c24f71"},
+ {file = "frozenlist-1.7.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dfcebf56f703cb2e346315431699f00db126d158455e513bd14089d992101e44"},
+ {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:974c5336e61d6e7eb1ea5b929cb645e882aadab0095c5a6974a111e6479f8878"},
+ {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c70db4a0ab5ab20878432c40563573229a7ed9241506181bba12f6b7d0dc41cb"},
+ {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1137b78384eebaf70560a36b7b229f752fb64d463d38d1304939984d5cb887b6"},
+ {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e793a9f01b3e8b5c0bc646fb59140ce0efcc580d22a3468d70766091beb81b35"},
+ {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:74739ba8e4e38221d2c5c03d90a7e542cb8ad681915f4ca8f68d04f810ee0a87"},
+ {file = "frozenlist-1.7.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e63344c4e929b1a01e29bc184bbb5fd82954869033765bfe8d65d09e336a677"},
+ {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2ea2a7369eb76de2217a842f22087913cdf75f63cf1307b9024ab82dfb525938"},
+ {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:836b42f472a0e006e02499cef9352ce8097f33df43baaba3e0a28a964c26c7d2"},
+ {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:e22b9a99741294b2571667c07d9f8cceec07cb92aae5ccda39ea1b6052ed4319"},
+ {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:9a19e85cc503d958abe5218953df722748d87172f71b73cf3c9257a91b999890"},
+ {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:f22dac33bb3ee8fe3e013aa7b91dc12f60d61d05b7fe32191ffa84c3aafe77bd"},
+ {file = "frozenlist-1.7.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9ccec739a99e4ccf664ea0775149f2749b8a6418eb5b8384b4dc0a7d15d304cb"},
+ {file = "frozenlist-1.7.0-cp39-cp39-win32.whl", hash = "sha256:b3950f11058310008a87757f3eee16a8e1ca97979833239439586857bc25482e"},
+ {file = "frozenlist-1.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:43a82fce6769c70f2f5a06248b614a7d268080a9d20f7457ef10ecee5af82b63"},
+ {file = "frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e"},
+ {file = "frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f"},
+]
+
+[[package]]
+name = "fsspec"
+version = "2025.5.1"
+description = "File-system specification"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "fsspec-2025.5.1-py3-none-any.whl", hash = "sha256:24d3a2e663d5fc735ab256263c4075f374a174c3410c0b25e5bd1970bceaa462"},
+ {file = "fsspec-2025.5.1.tar.gz", hash = "sha256:2e55e47a540b91843b755e83ded97c6e897fa0942b11490113f09e9c443c2475"},
+]
+
+[package.extras]
+abfs = ["adlfs"]
+adl = ["adlfs"]
+arrow = ["pyarrow (>=1)"]
+dask = ["dask", "distributed"]
+dev = ["pre-commit", "ruff"]
+doc = ["numpydoc", "sphinx", "sphinx-design", "sphinx-rtd-theme", "yarl"]
+dropbox = ["dropbox", "dropboxdrivefs", "requests"]
+full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "dask", "distributed", "dropbox", "dropboxdrivefs", "fusepy", "gcsfs", "libarchive-c", "ocifs", "panel", "paramiko", "pyarrow (>=1)", "pygit2", "requests", "s3fs", "smbprotocol", "tqdm"]
+fuse = ["fusepy"]
+gcs = ["gcsfs"]
+git = ["pygit2"]
+github = ["requests"]
+gs = ["gcsfs"]
+gui = ["panel"]
+hdfs = ["pyarrow (>=1)"]
+http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)"]
+libarchive = ["libarchive-c"]
+oci = ["ocifs"]
+s3 = ["s3fs"]
+sftp = ["paramiko"]
+smb = ["smbprotocol"]
+ssh = ["paramiko"]
+test = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "numpy", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "requests"]
+test-downstream = ["aiobotocore (>=2.5.4,<3.0.0)", "dask[dataframe,test]", "moto[server] (>4,<5)", "pytest-timeout", "xarray"]
+test-full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "cloudpickle", "dask", "distributed", "dropbox", "dropboxdrivefs", "fastparquet", "fusepy", "gcsfs", "jinja2", "kerchunk", "libarchive-c", "lz4", "notebook", "numpy", "ocifs", "pandas", "panel", "paramiko", "pyarrow", "pyarrow (>=1)", "pyftpdlib", "pygit2", "pytest", "pytest-asyncio (!=0.22.0)", "pytest-benchmark", "pytest-cov", "pytest-mock", "pytest-recording", "pytest-rerunfailures", "python-snappy", "requests", "smbprotocol", "tqdm", "urllib3", "zarr", "zstandard"]
+tqdm = ["tqdm"]
+
+[[package]]
+name = "googleapis-common-protos"
+version = "1.70.0"
+description = "Common protobufs used in Google APIs"
+optional = false
+python-versions = ">=3.7"
+groups = ["main"]
+files = [
+ {file = "googleapis_common_protos-1.70.0-py3-none-any.whl", hash = "sha256:b8bfcca8c25a2bb253e0e0b0adaf8c00773e5e6af6fd92397576680b807e0fd8"},
+ {file = "googleapis_common_protos-1.70.0.tar.gz", hash = "sha256:0e1b44e0ea153e6594f9f394fef15193a68aaaea2d843f83e2742717ca753257"},
+]
+
+[package.dependencies]
+protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<7.0.0"
+
+[package.extras]
+grpc = ["grpcio (>=1.44.0,<2.0.0)"]
+
+[[package]]
+name = "grandalf"
+version = "0.8"
+description = "Graph and drawing algorithms framework"
+optional = false
+python-versions = "*"
+groups = ["main"]
+files = [
+ {file = "grandalf-0.8-py3-none-any.whl", hash = "sha256:793ca254442f4a79252ea9ff1ab998e852c1e071b863593e5383afee906b4185"},
+ {file = "grandalf-0.8.tar.gz", hash = "sha256:2813f7aab87f0d20f334a3162ccfbcbf085977134a17a5b516940a93a77ea974"},
+]
+
+[package.dependencies]
+pyparsing = "*"
+
+[package.extras]
+full = ["numpy", "ply"]
+
+[[package]]
+name = "greenlet"
+version = "3.2.3"
+description = "Lightweight in-process concurrent programming"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+markers = "platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\""
+files = [
+ {file = "greenlet-3.2.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:1afd685acd5597349ee6d7a88a8bec83ce13c106ac78c196ee9dde7c04fe87be"},
+ {file = "greenlet-3.2.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:761917cac215c61e9dc7324b2606107b3b292a8349bdebb31503ab4de3f559ac"},
+ {file = "greenlet-3.2.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:a433dbc54e4a37e4fff90ef34f25a8c00aed99b06856f0119dcf09fbafa16392"},
+ {file = "greenlet-3.2.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:72e77ed69312bab0434d7292316d5afd6896192ac4327d44f3d613ecb85b037c"},
+ {file = "greenlet-3.2.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:68671180e3849b963649254a882cd544a3c75bfcd2c527346ad8bb53494444db"},
+ {file = "greenlet-3.2.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:49c8cfb18fb419b3d08e011228ef8a25882397f3a859b9fe1436946140b6756b"},
+ {file = "greenlet-3.2.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:efc6dc8a792243c31f2f5674b670b3a95d46fa1c6a912b8e310d6f542e7b0712"},
+ {file = "greenlet-3.2.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:731e154aba8e757aedd0781d4b240f1225b075b4409f1bb83b05ff410582cf00"},
+ {file = "greenlet-3.2.3-cp310-cp310-win_amd64.whl", hash = "sha256:96c20252c2f792defe9a115d3287e14811036d51e78b3aaddbee23b69b216302"},
+ {file = "greenlet-3.2.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:784ae58bba89fa1fa5733d170d42486580cab9decda3484779f4759345b29822"},
+ {file = "greenlet-3.2.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0921ac4ea42a5315d3446120ad48f90c3a6b9bb93dd9b3cf4e4d84a66e42de83"},
+ {file = "greenlet-3.2.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:d2971d93bb99e05f8c2c0c2f4aa9484a18d98c4c3bd3c62b65b7e6ae33dfcfaf"},
+ {file = "greenlet-3.2.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c667c0bf9d406b77a15c924ef3285e1e05250948001220368e039b6aa5b5034b"},
+ {file = "greenlet-3.2.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:592c12fb1165be74592f5de0d70f82bc5ba552ac44800d632214b76089945147"},
+ {file = "greenlet-3.2.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:29e184536ba333003540790ba29829ac14bb645514fbd7e32af331e8202a62a5"},
+ {file = "greenlet-3.2.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:93c0bb79844a367782ec4f429d07589417052e621aa39a5ac1fb99c5aa308edc"},
+ {file = "greenlet-3.2.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:751261fc5ad7b6705f5f76726567375bb2104a059454e0226e1eef6c756748ba"},
+ {file = "greenlet-3.2.3-cp311-cp311-win_amd64.whl", hash = "sha256:83a8761c75312361aa2b5b903b79da97f13f556164a7dd2d5448655425bd4c34"},
+ {file = "greenlet-3.2.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:25ad29caed5783d4bd7a85c9251c651696164622494c00802a139c00d639242d"},
+ {file = "greenlet-3.2.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:88cd97bf37fe24a6710ec6a3a7799f3f81d9cd33317dcf565ff9950c83f55e0b"},
+ {file = "greenlet-3.2.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:baeedccca94880d2f5666b4fa16fc20ef50ba1ee353ee2d7092b383a243b0b0d"},
+ {file = "greenlet-3.2.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:be52af4b6292baecfa0f397f3edb3c6092ce071b499dd6fe292c9ac9f2c8f264"},
+ {file = "greenlet-3.2.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0cc73378150b8b78b0c9fe2ce56e166695e67478550769536a6742dca3651688"},
+ {file = "greenlet-3.2.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:706d016a03e78df129f68c4c9b4c4f963f7d73534e48a24f5f5a7101ed13dbbb"},
+ {file = "greenlet-3.2.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:419e60f80709510c343c57b4bb5a339d8767bf9aef9b8ce43f4f143240f88b7c"},
+ {file = "greenlet-3.2.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:93d48533fade144203816783373f27a97e4193177ebaaf0fc396db19e5d61163"},
+ {file = "greenlet-3.2.3-cp312-cp312-win_amd64.whl", hash = "sha256:7454d37c740bb27bdeddfc3f358f26956a07d5220818ceb467a483197d84f849"},
+ {file = "greenlet-3.2.3-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:500b8689aa9dd1ab26872a34084503aeddefcb438e2e7317b89b11eaea1901ad"},
+ {file = "greenlet-3.2.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:a07d3472c2a93117af3b0136f246b2833fdc0b542d4a9799ae5f41c28323faef"},
+ {file = "greenlet-3.2.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:8704b3768d2f51150626962f4b9a9e4a17d2e37c8a8d9867bbd9fa4eb938d3b3"},
+ {file = "greenlet-3.2.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:5035d77a27b7c62db6cf41cf786cfe2242644a7a337a0e155c80960598baab95"},
+ {file = "greenlet-3.2.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2d8aa5423cd4a396792f6d4580f88bdc6efcb9205891c9d40d20f6e670992efb"},
+ {file = "greenlet-3.2.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2c724620a101f8170065d7dded3f962a2aea7a7dae133a009cada42847e04a7b"},
+ {file = "greenlet-3.2.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:873abe55f134c48e1f2a6f53f7d1419192a3d1a4e873bace00499a4e45ea6af0"},
+ {file = "greenlet-3.2.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:024571bbce5f2c1cfff08bf3fbaa43bbc7444f580ae13b0099e95d0e6e67ed36"},
+ {file = "greenlet-3.2.3-cp313-cp313-win_amd64.whl", hash = "sha256:5195fb1e75e592dd04ce79881c8a22becdfa3e6f500e7feb059b1e6fdd54d3e3"},
+ {file = "greenlet-3.2.3-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:3d04332dddb10b4a211b68111dabaee2e1a073663d117dc10247b5b1642bac86"},
+ {file = "greenlet-3.2.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8186162dffde068a465deab08fc72c767196895c39db26ab1c17c0b77a6d8b97"},
+ {file = "greenlet-3.2.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f4bfbaa6096b1b7a200024784217defedf46a07c2eee1a498e94a1b5f8ec5728"},
+ {file = "greenlet-3.2.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:ed6cfa9200484d234d8394c70f5492f144b20d4533f69262d530a1a082f6ee9a"},
+ {file = "greenlet-3.2.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:02b0df6f63cd15012bed5401b47829cfd2e97052dc89da3cfaf2c779124eb892"},
+ {file = "greenlet-3.2.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:86c2d68e87107c1792e2e8d5399acec2487a4e993ab76c792408e59394d52141"},
+ {file = "greenlet-3.2.3-cp314-cp314-win_amd64.whl", hash = "sha256:8c47aae8fbbfcf82cc13327ae802ba13c9c36753b67e760023fd116bc124a62a"},
+ {file = "greenlet-3.2.3-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:42efc522c0bd75ffa11a71e09cd8a399d83fafe36db250a87cf1dacfaa15dc64"},
+ {file = "greenlet-3.2.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d760f9bdfe79bff803bad32b4d8ffb2c1d2ce906313fc10a83976ffb73d64ca7"},
+ {file = "greenlet-3.2.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:8324319cbd7b35b97990090808fdc99c27fe5338f87db50514959f8059999805"},
+ {file = "greenlet-3.2.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:8c37ef5b3787567d322331d5250e44e42b58c8c713859b8a04c6065f27efbf72"},
+ {file = "greenlet-3.2.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ce539fb52fb774d0802175d37fcff5c723e2c7d249c65916257f0a940cee8904"},
+ {file = "greenlet-3.2.3-cp39-cp39-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:003c930e0e074db83559edc8705f3a2d066d4aa8c2f198aff1e454946efd0f26"},
+ {file = "greenlet-3.2.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7e70ea4384b81ef9e84192e8a77fb87573138aa5d4feee541d8014e452b434da"},
+ {file = "greenlet-3.2.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:22eb5ba839c4b2156f18f76768233fe44b23a31decd9cc0d4cc8141c211fd1b4"},
+ {file = "greenlet-3.2.3-cp39-cp39-win32.whl", hash = "sha256:4532f0d25df67f896d137431b13f4cdce89f7e3d4a96387a41290910df4d3a57"},
+ {file = "greenlet-3.2.3-cp39-cp39-win_amd64.whl", hash = "sha256:aaa7aae1e7f75eaa3ae400ad98f8644bb81e1dc6ba47ce8a93d3f17274e08322"},
+ {file = "greenlet-3.2.3.tar.gz", hash = "sha256:8b0dd8ae4c0d6f5e54ee55ba935eeb3d735a9b58a8a1e5b5cbab64e01a39f365"},
+]
+
+[package.extras]
+docs = ["Sphinx", "furo"]
+test = ["objgraph", "psutil"]
+
+[[package]]
+name = "grpcio"
+version = "1.73.1"
+description = "HTTP/2-based RPC framework"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "grpcio-1.73.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:2d70f4ddd0a823436c2624640570ed6097e40935c9194482475fe8e3d9754d55"},
+ {file = "grpcio-1.73.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:3841a8a5a66830261ab6a3c2a3dc539ed84e4ab019165f77b3eeb9f0ba621f26"},
+ {file = "grpcio-1.73.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:628c30f8e77e0258ab788750ec92059fc3d6628590fb4b7cea8c102503623ed7"},
+ {file = "grpcio-1.73.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67a0468256c9db6d5ecb1fde4bf409d016f42cef649323f0a08a72f352d1358b"},
+ {file = "grpcio-1.73.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68b84d65bbdebd5926eb5c53b0b9ec3b3f83408a30e4c20c373c5337b4219ec5"},
+ {file = "grpcio-1.73.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c54796ca22b8349cc594d18b01099e39f2b7ffb586ad83217655781a350ce4da"},
+ {file = "grpcio-1.73.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:75fc8e543962ece2f7ecd32ada2d44c0c8570ae73ec92869f9af8b944863116d"},
+ {file = "grpcio-1.73.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6a6037891cd2b1dd1406b388660522e1565ed340b1fea2955b0234bdd941a862"},
+ {file = "grpcio-1.73.1-cp310-cp310-win32.whl", hash = "sha256:cce7265b9617168c2d08ae570fcc2af4eaf72e84f8c710ca657cc546115263af"},
+ {file = "grpcio-1.73.1-cp310-cp310-win_amd64.whl", hash = "sha256:6a2b372e65fad38842050943f42ce8fee00c6f2e8ea4f7754ba7478d26a356ee"},
+ {file = "grpcio-1.73.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:ba2cea9f7ae4bc21f42015f0ec98f69ae4179848ad744b210e7685112fa507a1"},
+ {file = "grpcio-1.73.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:d74c3f4f37b79e746271aa6cdb3a1d7e4432aea38735542b23adcabaaee0c097"},
+ {file = "grpcio-1.73.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:5b9b1805a7d61c9e90541cbe8dfe0a593dfc8c5c3a43fe623701b6a01b01d710"},
+ {file = "grpcio-1.73.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3215f69a0670a8cfa2ab53236d9e8026bfb7ead5d4baabe7d7dc11d30fda967"},
+ {file = "grpcio-1.73.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc5eccfd9577a5dc7d5612b2ba90cca4ad14c6d949216c68585fdec9848befb1"},
+ {file = "grpcio-1.73.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dc7d7fd520614fce2e6455ba89791458020a39716951c7c07694f9dbae28e9c0"},
+ {file = "grpcio-1.73.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:105492124828911f85127e4825d1c1234b032cb9d238567876b5515d01151379"},
+ {file = "grpcio-1.73.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:610e19b04f452ba6f402ac9aa94eb3d21fbc94553368008af634812c4a85a99e"},
+ {file = "grpcio-1.73.1-cp311-cp311-win32.whl", hash = "sha256:d60588ab6ba0ac753761ee0e5b30a29398306401bfbceffe7d68ebb21193f9d4"},
+ {file = "grpcio-1.73.1-cp311-cp311-win_amd64.whl", hash = "sha256:6957025a4608bb0a5ff42abd75bfbb2ed99eda29d5992ef31d691ab54b753643"},
+ {file = "grpcio-1.73.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:921b25618b084e75d424a9f8e6403bfeb7abef074bb6c3174701e0f2542debcf"},
+ {file = "grpcio-1.73.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:277b426a0ed341e8447fbf6c1d6b68c952adddf585ea4685aa563de0f03df887"},
+ {file = "grpcio-1.73.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:96c112333309493c10e118d92f04594f9055774757f5d101b39f8150f8c25582"},
+ {file = "grpcio-1.73.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f48e862aed925ae987eb7084409a80985de75243389dc9d9c271dd711e589918"},
+ {file = "grpcio-1.73.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83a6c2cce218e28f5040429835fa34a29319071079e3169f9543c3fbeff166d2"},
+ {file = "grpcio-1.73.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:65b0458a10b100d815a8426b1442bd17001fdb77ea13665b2f7dc9e8587fdc6b"},
+ {file = "grpcio-1.73.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:0a9f3ea8dce9eae9d7cb36827200133a72b37a63896e0e61a9d5ec7d61a59ab1"},
+ {file = "grpcio-1.73.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:de18769aea47f18e782bf6819a37c1c528914bfd5683b8782b9da356506190c8"},
+ {file = "grpcio-1.73.1-cp312-cp312-win32.whl", hash = "sha256:24e06a5319e33041e322d32c62b1e728f18ab8c9dbc91729a3d9f9e3ed336642"},
+ {file = "grpcio-1.73.1-cp312-cp312-win_amd64.whl", hash = "sha256:303c8135d8ab176f8038c14cc10d698ae1db9c480f2b2823f7a987aa2a4c5646"},
+ {file = "grpcio-1.73.1-cp313-cp313-linux_armv7l.whl", hash = "sha256:b310824ab5092cf74750ebd8a8a8981c1810cb2b363210e70d06ef37ad80d4f9"},
+ {file = "grpcio-1.73.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:8f5a6df3fba31a3485096ac85b2e34b9666ffb0590df0cd044f58694e6a1f6b5"},
+ {file = "grpcio-1.73.1-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:052e28fe9c41357da42250a91926a3e2f74c046575c070b69659467ca5aa976b"},
+ {file = "grpcio-1.73.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c0bf15f629b1497436596b1cbddddfa3234273490229ca29561209778ebe182"},
+ {file = "grpcio-1.73.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ab860d5bfa788c5a021fba264802e2593688cd965d1374d31d2b1a34cacd854"},
+ {file = "grpcio-1.73.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:ad1d958c31cc91ab050bd8a91355480b8e0683e21176522bacea225ce51163f2"},
+ {file = "grpcio-1.73.1-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:f43ffb3bd415c57224c7427bfb9e6c46a0b6e998754bfa0d00f408e1873dcbb5"},
+ {file = "grpcio-1.73.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:686231cdd03a8a8055f798b2b54b19428cdf18fa1549bee92249b43607c42668"},
+ {file = "grpcio-1.73.1-cp313-cp313-win32.whl", hash = "sha256:89018866a096e2ce21e05eabed1567479713ebe57b1db7cbb0f1e3b896793ba4"},
+ {file = "grpcio-1.73.1-cp313-cp313-win_amd64.whl", hash = "sha256:4a68f8c9966b94dff693670a5cf2b54888a48a5011c5d9ce2295a1a1465ee84f"},
+ {file = "grpcio-1.73.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:b4adc97d2d7f5c660a5498bda978ebb866066ad10097265a5da0511323ae9f50"},
+ {file = "grpcio-1.73.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:c45a28a0cfb6ddcc7dc50a29de44ecac53d115c3388b2782404218db51cb2df3"},
+ {file = "grpcio-1.73.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:10af9f2ab98a39f5b6c1896c6fc2036744b5b41d12739d48bed4c3e15b6cf900"},
+ {file = "grpcio-1.73.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:45cf17dcce5ebdb7b4fe9e86cb338fa99d7d1bb71defc78228e1ddf8d0de8cbb"},
+ {file = "grpcio-1.73.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c502c2e950fc7e8bf05c047e8a14522ef7babac59abbfde6dbf46b7a0d9c71e"},
+ {file = "grpcio-1.73.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6abfc0f9153dc4924536f40336f88bd4fe7bd7494f028675e2e04291b8c2c62a"},
+ {file = "grpcio-1.73.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ed451a0e39c8e51eb1612b78686839efd1a920666d1666c1adfdb4fd51680c0f"},
+ {file = "grpcio-1.73.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:07f08705a5505c9b5b0cbcbabafb96462b5a15b7236bbf6bbcc6b0b91e1cbd7e"},
+ {file = "grpcio-1.73.1-cp39-cp39-win32.whl", hash = "sha256:ad5c958cc3d98bb9d71714dc69f1c13aaf2f4b53e29d4cc3f1501ef2e4d129b2"},
+ {file = "grpcio-1.73.1-cp39-cp39-win_amd64.whl", hash = "sha256:42f0660bce31b745eb9d23f094a332d31f210dcadd0fc8e5be7e4c62a87ce86b"},
+ {file = "grpcio-1.73.1.tar.gz", hash = "sha256:7fce2cd1c0c1116cf3850564ebfc3264fba75d3c74a7414373f1238ea365ef87"},
+]
+
+[package.extras]
+protobuf = ["grpcio-tools (>=1.73.1)"]
+
+[[package]]
+name = "h11"
+version = "0.16.0"
+description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"},
+ {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"},
+]
+
+[[package]]
+name = "hf-xet"
+version = "1.1.5"
+description = "Fast transfer of large files with the Hugging Face Hub."
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+markers = "platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"arm64\" or platform_machine == \"aarch64\""
+files = [
+ {file = "hf_xet-1.1.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f52c2fa3635b8c37c7764d8796dfa72706cc4eded19d638331161e82b0792e23"},
+ {file = "hf_xet-1.1.5-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:9fa6e3ee5d61912c4a113e0708eaaef987047616465ac7aa30f7121a48fc1af8"},
+ {file = "hf_xet-1.1.5-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc874b5c843e642f45fd85cda1ce599e123308ad2901ead23d3510a47ff506d1"},
+ {file = "hf_xet-1.1.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dbba1660e5d810bd0ea77c511a99e9242d920790d0e63c0e4673ed36c4022d18"},
+ {file = "hf_xet-1.1.5-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ab34c4c3104133c495785d5d8bba3b1efc99de52c02e759cf711a91fd39d3a14"},
+ {file = "hf_xet-1.1.5-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:83088ecea236d5113de478acb2339f92c95b4fb0462acaa30621fac02f5a534a"},
+ {file = "hf_xet-1.1.5-cp37-abi3-win_amd64.whl", hash = "sha256:73e167d9807d166596b4b2f0b585c6d5bd84a26dea32843665a8b58f6edba245"},
+ {file = "hf_xet-1.1.5.tar.gz", hash = "sha256:69ebbcfd9ec44fdc2af73441619eeb06b94ee34511bbcf57cd423820090f5694"},
+]
+
+[package.extras]
+tests = ["pytest"]
+
+[[package]]
+name = "httpcore"
+version = "1.0.9"
+description = "A minimal low-level HTTP client."
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"},
+ {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"},
+]
+
+[package.dependencies]
+certifi = "*"
+h11 = ">=0.16"
+
+[package.extras]
+asyncio = ["anyio (>=4.0,<5.0)"]
+http2 = ["h2 (>=3,<5)"]
+socks = ["socksio (==1.*)"]
+trio = ["trio (>=0.22.0,<1.0)"]
+
+[[package]]
+name = "httpx"
+version = "0.28.1"
+description = "The next generation HTTP client."
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"},
+ {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"},
+]
+
+[package.dependencies]
+anyio = "*"
+certifi = "*"
+httpcore = "==1.*"
+idna = "*"
+
+[package.extras]
+brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""]
+cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
+http2 = ["h2 (>=3,<5)"]
+socks = ["socksio (==1.*)"]
+zstd = ["zstandard (>=0.18.0)"]
+
+[[package]]
+name = "httpx-sse"
+version = "0.4.1"
+description = "Consume Server-Sent Event (SSE) messages with HTTPX."
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "httpx_sse-0.4.1-py3-none-any.whl", hash = "sha256:cba42174344c3a5b06f255ce65b350880f962d99ead85e776f23c6618a377a37"},
+ {file = "httpx_sse-0.4.1.tar.gz", hash = "sha256:8f44d34414bc7b21bf3602713005c5df4917884f76072479b21f68befa4ea26e"},
+]
+
+[[package]]
+name = "huggingface-hub"
+version = "0.33.2"
+description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub"
+optional = false
+python-versions = ">=3.8.0"
+groups = ["main"]
+files = [
+ {file = "huggingface_hub-0.33.2-py3-none-any.whl", hash = "sha256:3749498bfa91e8cde2ddc2c1db92c79981f40e66434c20133b39e5928ac9bcc5"},
+ {file = "huggingface_hub-0.33.2.tar.gz", hash = "sha256:84221defaec8fa09c090390cd68c78b88e3c4c2b7befba68d3dc5aacbc3c2c5f"},
+]
+
+[package.dependencies]
+filelock = "*"
+fsspec = ">=2023.5.0"
+hf-xet = {version = ">=1.1.2,<2.0.0", markers = "platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"arm64\" or platform_machine == \"aarch64\""}
+packaging = ">=20.9"
+pyyaml = ">=5.1"
+requests = "*"
+tqdm = ">=4.42.1"
+typing-extensions = ">=3.7.4.3"
+
+[package.extras]
+all = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "authlib (>=1.3.2)", "fastapi", "gradio (>=4.0.0)", "httpx", "itsdangerous", "jedi", "libcst (==1.4.0)", "mypy (==1.15.0) ; python_version >= \"3.9\"", "mypy (>=1.14.1,<1.15.0) ; python_version == \"3.8\"", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.9.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"]
+cli = ["InquirerPy (==0.3.4)"]
+dev = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "authlib (>=1.3.2)", "fastapi", "gradio (>=4.0.0)", "httpx", "itsdangerous", "jedi", "libcst (==1.4.0)", "mypy (==1.15.0) ; python_version >= \"3.9\"", "mypy (>=1.14.1,<1.15.0) ; python_version == \"3.8\"", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "ruff (>=0.9.0)", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)", "urllib3 (<2.0)"]
+fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"]
+hf-transfer = ["hf-transfer (>=0.1.4)"]
+hf-xet = ["hf-xet (>=1.1.2,<2.0.0)"]
+inference = ["aiohttp"]
+mcp = ["aiohttp", "mcp (>=1.8.0)", "typer"]
+oauth = ["authlib (>=1.3.2)", "fastapi", "httpx", "itsdangerous"]
+quality = ["libcst (==1.4.0)", "mypy (==1.15.0) ; python_version >= \"3.9\"", "mypy (>=1.14.1,<1.15.0) ; python_version == \"3.8\"", "ruff (>=0.9.0)"]
+tensorflow = ["graphviz", "pydot", "tensorflow"]
+tensorflow-testing = ["keras (<3.0)", "tensorflow"]
+testing = ["InquirerPy (==0.3.4)", "Jinja2", "Pillow", "aiohttp", "authlib (>=1.3.2)", "fastapi", "gradio (>=4.0.0)", "httpx", "itsdangerous", "jedi", "numpy", "pytest (>=8.1.1,<8.2.2)", "pytest-asyncio", "pytest-cov", "pytest-env", "pytest-mock", "pytest-rerunfailures", "pytest-vcr", "pytest-xdist", "soundfile", "urllib3 (<2.0)"]
+torch = ["safetensors[torch]", "torch"]
+typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3", "typing-extensions (>=4.8.0)"]
+
+[[package]]
+name = "idna"
+version = "3.10"
+description = "Internationalized Domain Names in Applications (IDNA)"
+optional = false
+python-versions = ">=3.6"
+groups = ["main"]
+files = [
+ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"},
+ {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"},
+]
+
+[package.extras]
+all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"]
+
+[[package]]
+name = "importlib-metadata"
+version = "8.7.0"
+description = "Read metadata from Python packages"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd"},
+ {file = "importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000"},
+]
+
+[package.dependencies]
+zipp = ">=3.20"
+
+[package.extras]
+check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""]
+cover = ["pytest-cov"]
+doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
+enabler = ["pytest-enabler (>=2.2)"]
+perf = ["ipython"]
+test = ["flufl.flake8", "importlib_resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"]
+type = ["pytest-mypy"]
+
+[[package]]
+name = "inflection"
+version = "0.5.1"
+description = "A port of Ruby on Rails inflector to Python"
+optional = false
+python-versions = ">=3.5"
+groups = ["main"]
+files = [
+ {file = "inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2"},
+ {file = "inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417"},
+]
+
+[[package]]
+name = "iniconfig"
+version = "2.1.0"
+description = "brain-dead simple config-ini parsing"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"},
+ {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"},
+]
+
+[[package]]
+name = "jinja2"
+version = "3.1.6"
+description = "A very fast and expressive template engine."
+optional = false
+python-versions = ">=3.7"
+groups = ["main"]
+files = [
+ {file = "jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67"},
+ {file = "jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d"},
+]
+
+[package.dependencies]
+MarkupSafe = ">=2.0"
+
+[package.extras]
+i18n = ["Babel (>=2.7)"]
+
+[[package]]
+name = "jiter"
+version = "0.10.0"
+description = "Fast iterable JSON parser."
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "jiter-0.10.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cd2fb72b02478f06a900a5782de2ef47e0396b3e1f7d5aba30daeb1fce66f303"},
+ {file = "jiter-0.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:32bb468e3af278f095d3fa5b90314728a6916d89ba3d0ffb726dd9bf7367285e"},
+ {file = "jiter-0.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa8b3e0068c26ddedc7abc6fac37da2d0af16b921e288a5a613f4b86f050354f"},
+ {file = "jiter-0.10.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:286299b74cc49e25cd42eea19b72aa82c515d2f2ee12d11392c56d8701f52224"},
+ {file = "jiter-0.10.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6ed5649ceeaeffc28d87fb012d25a4cd356dcd53eff5acff1f0466b831dda2a7"},
+ {file = "jiter-0.10.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2ab0051160cb758a70716448908ef14ad476c3774bd03ddce075f3c1f90a3d6"},
+ {file = "jiter-0.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03997d2f37f6b67d2f5c475da4412be584e1cec273c1cfc03d642c46db43f8cf"},
+ {file = "jiter-0.10.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c404a99352d839fed80d6afd6c1d66071f3bacaaa5c4268983fc10f769112e90"},
+ {file = "jiter-0.10.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:66e989410b6666d3ddb27a74c7e50d0829704ede652fd4c858e91f8d64b403d0"},
+ {file = "jiter-0.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b532d3af9ef4f6374609a3bcb5e05a1951d3bf6190dc6b176fdb277c9bbf15ee"},
+ {file = "jiter-0.10.0-cp310-cp310-win32.whl", hash = "sha256:da9be20b333970e28b72edc4dff63d4fec3398e05770fb3205f7fb460eb48dd4"},
+ {file = "jiter-0.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:f59e533afed0c5b0ac3eba20d2548c4a550336d8282ee69eb07b37ea526ee4e5"},
+ {file = "jiter-0.10.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:3bebe0c558e19902c96e99217e0b8e8b17d570906e72ed8a87170bc290b1e978"},
+ {file = "jiter-0.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:558cc7e44fd8e507a236bee6a02fa17199ba752874400a0ca6cd6e2196cdb7dc"},
+ {file = "jiter-0.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d613e4b379a07d7c8453c5712ce7014e86c6ac93d990a0b8e7377e18505e98d"},
+ {file = "jiter-0.10.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f62cf8ba0618eda841b9bf61797f21c5ebd15a7a1e19daab76e4e4b498d515b2"},
+ {file = "jiter-0.10.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:919d139cdfa8ae8945112398511cb7fca58a77382617d279556b344867a37e61"},
+ {file = "jiter-0.10.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13ddbc6ae311175a3b03bd8994881bc4635c923754932918e18da841632349db"},
+ {file = "jiter-0.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c440ea003ad10927a30521a9062ce10b5479592e8a70da27f21eeb457b4a9c5"},
+ {file = "jiter-0.10.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dc347c87944983481e138dea467c0551080c86b9d21de6ea9306efb12ca8f606"},
+ {file = "jiter-0.10.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:13252b58c1f4d8c5b63ab103c03d909e8e1e7842d302473f482915d95fefd605"},
+ {file = "jiter-0.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7d1bbf3c465de4a24ab12fb7766a0003f6f9bce48b8b6a886158c4d569452dc5"},
+ {file = "jiter-0.10.0-cp311-cp311-win32.whl", hash = "sha256:db16e4848b7e826edca4ccdd5b145939758dadf0dc06e7007ad0e9cfb5928ae7"},
+ {file = "jiter-0.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:9c9c1d5f10e18909e993f9641f12fe1c77b3e9b533ee94ffa970acc14ded3812"},
+ {file = "jiter-0.10.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1e274728e4a5345a6dde2d343c8da018b9d4bd4350f5a472fa91f66fda44911b"},
+ {file = "jiter-0.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7202ae396446c988cb2a5feb33a543ab2165b786ac97f53b59aafb803fef0744"},
+ {file = "jiter-0.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23ba7722d6748b6920ed02a8f1726fb4b33e0fd2f3f621816a8b486c66410ab2"},
+ {file = "jiter-0.10.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:371eab43c0a288537d30e1f0b193bc4eca90439fc08a022dd83e5e07500ed026"},
+ {file = "jiter-0.10.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c675736059020365cebc845a820214765162728b51ab1e03a1b7b3abb70f74c"},
+ {file = "jiter-0.10.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c5867d40ab716e4684858e4887489685968a47e3ba222e44cde6e4a2154f959"},
+ {file = "jiter-0.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:395bb9a26111b60141757d874d27fdea01b17e8fac958b91c20128ba8f4acc8a"},
+ {file = "jiter-0.10.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6842184aed5cdb07e0c7e20e5bdcfafe33515ee1741a6835353bb45fe5d1bd95"},
+ {file = "jiter-0.10.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:62755d1bcea9876770d4df713d82606c8c1a3dca88ff39046b85a048566d56ea"},
+ {file = "jiter-0.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:533efbce2cacec78d5ba73a41756beff8431dfa1694b6346ce7af3a12c42202b"},
+ {file = "jiter-0.10.0-cp312-cp312-win32.whl", hash = "sha256:8be921f0cadd245e981b964dfbcd6fd4bc4e254cdc069490416dd7a2632ecc01"},
+ {file = "jiter-0.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:a7c7d785ae9dda68c2678532a5a1581347e9c15362ae9f6e68f3fdbfb64f2e49"},
+ {file = "jiter-0.10.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e0588107ec8e11b6f5ef0e0d656fb2803ac6cf94a96b2b9fc675c0e3ab5e8644"},
+ {file = "jiter-0.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cafc4628b616dc32530c20ee53d71589816cf385dd9449633e910d596b1f5c8a"},
+ {file = "jiter-0.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:520ef6d981172693786a49ff5b09eda72a42e539f14788124a07530f785c3ad6"},
+ {file = "jiter-0.10.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:554dedfd05937f8fc45d17ebdf298fe7e0c77458232bcb73d9fbbf4c6455f5b3"},
+ {file = "jiter-0.10.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5bc299da7789deacf95f64052d97f75c16d4fc8c4c214a22bf8d859a4288a1c2"},
+ {file = "jiter-0.10.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5161e201172de298a8a1baad95eb85db4fb90e902353b1f6a41d64ea64644e25"},
+ {file = "jiter-0.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e2227db6ba93cb3e2bf67c87e594adde0609f146344e8207e8730364db27041"},
+ {file = "jiter-0.10.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:15acb267ea5e2c64515574b06a8bf393fbfee6a50eb1673614aa45f4613c0cca"},
+ {file = "jiter-0.10.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:901b92f2e2947dc6dfcb52fd624453862e16665ea909a08398dde19c0731b7f4"},
+ {file = "jiter-0.10.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d0cb9a125d5a3ec971a094a845eadde2db0de85b33c9f13eb94a0c63d463879e"},
+ {file = "jiter-0.10.0-cp313-cp313-win32.whl", hash = "sha256:48a403277ad1ee208fb930bdf91745e4d2d6e47253eedc96e2559d1e6527006d"},
+ {file = "jiter-0.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:75f9eb72ecb640619c29bf714e78c9c46c9c4eaafd644bf78577ede459f330d4"},
+ {file = "jiter-0.10.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:28ed2a4c05a1f32ef0e1d24c2611330219fed727dae01789f4a335617634b1ca"},
+ {file = "jiter-0.10.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14a4c418b1ec86a195f1ca69da8b23e8926c752b685af665ce30777233dfe070"},
+ {file = "jiter-0.10.0-cp313-cp313t-win_amd64.whl", hash = "sha256:d7bfed2fe1fe0e4dda6ef682cee888ba444b21e7a6553e03252e4feb6cf0adca"},
+ {file = "jiter-0.10.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:5e9251a5e83fab8d87799d3e1a46cb4b7f2919b895c6f4483629ed2446f66522"},
+ {file = "jiter-0.10.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:023aa0204126fe5b87ccbcd75c8a0d0261b9abdbbf46d55e7ae9f8e22424eeb8"},
+ {file = "jiter-0.10.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c189c4f1779c05f75fc17c0c1267594ed918996a231593a21a5ca5438445216"},
+ {file = "jiter-0.10.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:15720084d90d1098ca0229352607cd68256c76991f6b374af96f36920eae13c4"},
+ {file = "jiter-0.10.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4f2fb68e5f1cfee30e2b2a09549a00683e0fde4c6a2ab88c94072fc33cb7426"},
+ {file = "jiter-0.10.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ce541693355fc6da424c08b7edf39a2895f58d6ea17d92cc2b168d20907dee12"},
+ {file = "jiter-0.10.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31c50c40272e189d50006ad5c73883caabb73d4e9748a688b216e85a9a9ca3b9"},
+ {file = "jiter-0.10.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fa3402a2ff9815960e0372a47b75c76979d74402448509ccd49a275fa983ef8a"},
+ {file = "jiter-0.10.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:1956f934dca32d7bb647ea21d06d93ca40868b505c228556d3373cbd255ce853"},
+ {file = "jiter-0.10.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:fcedb049bdfc555e261d6f65a6abe1d5ad68825b7202ccb9692636c70fcced86"},
+ {file = "jiter-0.10.0-cp314-cp314-win32.whl", hash = "sha256:ac509f7eccca54b2a29daeb516fb95b6f0bd0d0d8084efaf8ed5dfc7b9f0b357"},
+ {file = "jiter-0.10.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5ed975b83a2b8639356151cef5c0d597c68376fc4922b45d0eb384ac058cfa00"},
+ {file = "jiter-0.10.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aa96f2abba33dc77f79b4cf791840230375f9534e5fac927ccceb58c5e604a5"},
+ {file = "jiter-0.10.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bd6292a43c0fc09ce7c154ec0fa646a536b877d1e8f2f96c19707f65355b5a4d"},
+ {file = "jiter-0.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:39de429dcaeb6808d75ffe9effefe96a4903c6a4b376b2f6d08d77c1aaee2f18"},
+ {file = "jiter-0.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52ce124f13a7a616fad3bb723f2bfb537d78239d1f7f219566dc52b6f2a9e48d"},
+ {file = "jiter-0.10.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:166f3606f11920f9a1746b2eea84fa2c0a5d50fd313c38bdea4edc072000b0af"},
+ {file = "jiter-0.10.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:28dcecbb4ba402916034fc14eba7709f250c4d24b0c43fc94d187ee0580af181"},
+ {file = "jiter-0.10.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86c5aa6910f9bebcc7bc4f8bc461aff68504388b43bfe5e5c0bd21efa33b52f4"},
+ {file = "jiter-0.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ceeb52d242b315d7f1f74b441b6a167f78cea801ad7c11c36da77ff2d42e8a28"},
+ {file = "jiter-0.10.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ff76d8887c8c8ee1e772274fcf8cc1071c2c58590d13e33bd12d02dc9a560397"},
+ {file = "jiter-0.10.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a9be4d0fa2b79f7222a88aa488bd89e2ae0a0a5b189462a12def6ece2faa45f1"},
+ {file = "jiter-0.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9ab7fd8738094139b6c1ab1822d6f2000ebe41515c537235fd45dabe13ec9324"},
+ {file = "jiter-0.10.0-cp39-cp39-win32.whl", hash = "sha256:5f51e048540dd27f204ff4a87f5d79294ea0aa3aa552aca34934588cf27023cf"},
+ {file = "jiter-0.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:1b28302349dc65703a9e4ead16f163b1c339efffbe1049c30a44b001a2a4fff9"},
+ {file = "jiter-0.10.0.tar.gz", hash = "sha256:07a7142c38aacc85194391108dc91b5b57093c978a9932bd86a36862759d9500"},
+]
+
+[[package]]
+name = "jsonpatch"
+version = "1.33"
+description = "Apply JSON-Patches (RFC 6902)"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*"
+groups = ["main"]
+files = [
+ {file = "jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"},
+ {file = "jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c"},
+]
+
+[package.dependencies]
+jsonpointer = ">=1.9"
+
+[[package]]
+name = "jsonpointer"
+version = "3.0.0"
+description = "Identify specific nodes in a JSON document (RFC 6901)"
+optional = false
+python-versions = ">=3.7"
+groups = ["main"]
+files = [
+ {file = "jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942"},
+ {file = "jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef"},
+]
+
+[[package]]
+name = "jsonschema"
+version = "4.24.0"
+description = "An implementation of JSON Schema validation for Python"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "jsonschema-4.24.0-py3-none-any.whl", hash = "sha256:a462455f19f5faf404a7902952b6f0e3ce868f3ee09a359b05eca6673bd8412d"},
+ {file = "jsonschema-4.24.0.tar.gz", hash = "sha256:0b4e8069eb12aedfa881333004bccaec24ecef5a8a6a4b6df142b2cc9599d196"},
+]
+
+[package.dependencies]
+attrs = ">=22.2.0"
+jsonschema-specifications = ">=2023.03.6"
+referencing = ">=0.28.4"
+rpds-py = ">=0.7.1"
+
+[package.extras]
+format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"]
+format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=24.6.0)"]
+
+[[package]]
+name = "jsonschema-specifications"
+version = "2025.4.1"
+description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "jsonschema_specifications-2025.4.1-py3-none-any.whl", hash = "sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af"},
+ {file = "jsonschema_specifications-2025.4.1.tar.gz", hash = "sha256:630159c9f4dbea161a6a2205c3011cc4f18ff381b189fff48bb39b9bf26ae608"},
+]
+
+[package.dependencies]
+referencing = ">=0.31.0"
+
+[[package]]
+name = "langchain"
+version = "0.3.26"
+description = "Building applications with LLMs through composability"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "langchain-0.3.26-py3-none-any.whl", hash = "sha256:361bb2e61371024a8c473da9f9c55f4ee50f269c5ab43afdb2b1309cb7ac36cf"},
+ {file = "langchain-0.3.26.tar.gz", hash = "sha256:8ff034ee0556d3e45eff1f1e96d0d745ced57858414dba7171c8ebdbeb5580c9"},
+]
+
+[package.dependencies]
+langchain-core = ">=0.3.66,<1.0.0"
+langchain-openai = {version = "*", optional = true, markers = "extra == \"openai\""}
+langchain-text-splitters = ">=0.3.8,<1.0.0"
+langsmith = ">=0.1.17"
+pydantic = ">=2.7.4,<3.0.0"
+PyYAML = ">=5.3"
+requests = ">=2,<3"
+SQLAlchemy = ">=1.4,<3"
+
+[package.extras]
+anthropic = ["langchain-anthropic"]
+aws = ["langchain-aws"]
+azure-ai = ["langchain-azure-ai"]
+cohere = ["langchain-cohere"]
+community = ["langchain-community"]
+deepseek = ["langchain-deepseek"]
+fireworks = ["langchain-fireworks"]
+google-genai = ["langchain-google-genai"]
+google-vertexai = ["langchain-google-vertexai"]
+groq = ["langchain-groq"]
+huggingface = ["langchain-huggingface"]
+mistralai = ["langchain-mistralai"]
+ollama = ["langchain-ollama"]
+openai = ["langchain-openai"]
+perplexity = ["langchain-perplexity"]
+together = ["langchain-together"]
+xai = ["langchain-xai"]
+
+[[package]]
+name = "langchain-community"
+version = "0.3.27"
+description = "Community contributed LangChain integrations."
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "langchain_community-0.3.27-py3-none-any.whl", hash = "sha256:581f97b795f9633da738ea95da9cb78f8879b538090c9b7a68c0aed49c828f0d"},
+ {file = "langchain_community-0.3.27.tar.gz", hash = "sha256:e1037c3b9da0c6d10bf06e838b034eb741e016515c79ef8f3f16e53ead33d882"},
+]
+
+[package.dependencies]
+aiohttp = ">=3.8.3,<4.0.0"
+dataclasses-json = ">=0.5.7,<0.7"
+httpx-sse = ">=0.4.0,<1.0.0"
+langchain = ">=0.3.26,<1.0.0"
+langchain-core = ">=0.3.66,<1.0.0"
+langsmith = ">=0.1.125"
+numpy = [
+ {version = ">=1.26.2", markers = "python_version < \"3.13\""},
+ {version = ">=2.1.0", markers = "python_version >= \"3.13\""},
+]
+pydantic-settings = ">=2.4.0,<3.0.0"
+PyYAML = ">=5.3"
+requests = ">=2,<3"
+SQLAlchemy = ">=1.4,<3"
+tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<10"
+
+[[package]]
+name = "langchain-core"
+version = "0.3.68"
+description = "Building applications with LLMs through composability"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "langchain_core-0.3.68-py3-none-any.whl", hash = "sha256:5e5c1fbef419590537c91b8c2d86af896fbcbaf0d5ed7fdcdd77f7d8f3467ba0"},
+ {file = "langchain_core-0.3.68.tar.gz", hash = "sha256:312e1932ac9aa2eaf111b70fdc171776fa571d1a86c1f873dcac88a094b19c6f"},
+]
+
+[package.dependencies]
+jsonpatch = ">=1.33,<2.0"
+langsmith = ">=0.3.45"
+packaging = ">=23.2,<25"
+pydantic = ">=2.7.4"
+PyYAML = ">=5.3"
+tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<10.0.0"
+typing-extensions = ">=4.7"
+
+[[package]]
+name = "langchain-openai"
+version = "0.3.27"
+description = "An integration package connecting OpenAI and LangChain"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "langchain_openai-0.3.27-py3-none-any.whl", hash = "sha256:efe636c3523978c44adc41cf55c8b3766c05c77547982465884d1258afe705df"},
+ {file = "langchain_openai-0.3.27.tar.gz", hash = "sha256:5d5a55adbff739274dfc3a4102925771736f893758f63679b64ae62fed79ca30"},
+]
+
+[package.dependencies]
+langchain-core = ">=0.3.66,<1.0.0"
+openai = ">=1.86.0,<2.0.0"
+tiktoken = ">=0.7,<1"
+
+[[package]]
+name = "langchain-pinecone"
+version = "0.2.8"
+description = "An integration package connecting Pinecone and LangChain"
+optional = false
+python-versions = "<3.14,>=3.9"
+groups = ["main"]
+files = [
+ {file = "langchain_pinecone-0.2.8-py3-none-any.whl", hash = "sha256:513063269f686b537cc0b9468ce66970377a9f874944bbe0a93cf2148bbf2ef1"},
+ {file = "langchain_pinecone-0.2.8.tar.gz", hash = "sha256:9bffa98dc950af1fb0761dc790232a9850eac8e99fe514bdfad63e9fe75f8d72"},
+]
+
+[package.dependencies]
+langchain-core = ">=0.3.34,<1.0.0"
+langchain-openai = ">=0.3.11"
+langchain-tests = ">=0.3.7,<1.0.0"
+numpy = ">=1.26.4"
+pinecone = {version = ">=6.0.0,<8.0.0", extras = ["asyncio"]}
+
+[[package]]
+name = "langchain-tests"
+version = "0.3.20"
+description = "Standard tests for LangChain implementations"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "langchain_tests-0.3.20-py3-none-any.whl", hash = "sha256:6cc7ae64eb8dea65360a968840abe8d947c5382b95e065431c9dd061ee1dacd8"},
+ {file = "langchain_tests-0.3.20.tar.gz", hash = "sha256:b94c05e37d191d4768a1a5064f2ca4053bacd48ff41e10af245ffa6a065ead4d"},
+]
+
+[package.dependencies]
+httpx = ">=0.25.0,<1"
+langchain-core = ">=0.3.63,<1.0.0"
+numpy = [
+ {version = ">=1.26.2", markers = "python_version < \"3.13\""},
+ {version = ">=2.1.0", markers = "python_version >= \"3.13\""},
+]
+pytest = ">=7,<9"
+pytest-asyncio = ">=0.20,<1"
+pytest-benchmark = "*"
+pytest-codspeed = "*"
+pytest-recording = "*"
+pytest-socket = ">=0.6.0,<1"
+syrupy = ">=4,<5"
+vcrpy = ">=7.0"
+
+[[package]]
+name = "langchain-text-splitters"
+version = "0.3.8"
+description = "LangChain text splitting utilities"
+optional = false
+python-versions = "<4.0,>=3.9"
+groups = ["main"]
+files = [
+ {file = "langchain_text_splitters-0.3.8-py3-none-any.whl", hash = "sha256:e75cc0f4ae58dcf07d9f18776400cf8ade27fadd4ff6d264df6278bb302f6f02"},
+ {file = "langchain_text_splitters-0.3.8.tar.gz", hash = "sha256:116d4b9f2a22dda357d0b79e30acf005c5518177971c66a9f1ab0edfdb0f912e"},
+]
+
+[package.dependencies]
+langchain-core = ">=0.3.51,<1.0.0"
+
+[[package]]
+name = "langgraph"
+version = "0.4.10"
+description = "Building stateful, multi-actor applications with LLMs"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "langgraph-0.4.10-py3-none-any.whl", hash = "sha256:fa1257afba55778f222981362c1221fb0cc166467a543c13729eb104b9becbc9"},
+ {file = "langgraph-0.4.10.tar.gz", hash = "sha256:391dadf5051bab212d711da62b10ae6c97bbc912a9f812b4b27e92a934a401c6"},
+]
+
+[package.dependencies]
+langchain-core = ">=0.1"
+langgraph-checkpoint = ">=2.0.26"
+langgraph-prebuilt = ">=0.2.0"
+langgraph-sdk = ">=0.1.42"
+pydantic = ">=2.7.4"
+xxhash = ">=3.5.0"
+
+[[package]]
+name = "langgraph-checkpoint"
+version = "2.1.0"
+description = "Library with base interfaces for LangGraph checkpoint savers."
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "langgraph_checkpoint-2.1.0-py3-none-any.whl", hash = "sha256:4cea3e512081da1241396a519cbfe4c5d92836545e2c64e85b6f5c34a1b8bc61"},
+ {file = "langgraph_checkpoint-2.1.0.tar.gz", hash = "sha256:cdaa2f0b49aa130ab185c02d82f02b40299a1fbc9ac59ac20cecce09642a1abe"},
+]
+
+[package.dependencies]
+langchain-core = ">=0.2.38"
+ormsgpack = ">=1.10.0"
+
+[[package]]
+name = "langgraph-prebuilt"
+version = "0.5.2"
+description = "Library with high-level APIs for creating and executing LangGraph agents and tools."
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "langgraph_prebuilt-0.5.2-py3-none-any.whl", hash = "sha256:1f4cd55deca49dffc3e5127eec12fcd244fc381321002f728afa88642d5ec59d"},
+ {file = "langgraph_prebuilt-0.5.2.tar.gz", hash = "sha256:2c900a5be0d6a93ea2521e0d931697cad2b646f1fcda7aa5c39d8d7539772465"},
+]
+
+[package.dependencies]
+langchain-core = ">=0.3.67"
+langgraph-checkpoint = ">=2.1.0"
+
+[[package]]
+name = "langgraph-sdk"
+version = "0.1.72"
+description = "SDK for interacting with LangGraph API"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "langgraph_sdk-0.1.72-py3-none-any.whl", hash = "sha256:925d3fcc7a26361db04f9c4beb3ec05bc36361b2a836d181ff2ab145071ec3ce"},
+ {file = "langgraph_sdk-0.1.72.tar.gz", hash = "sha256:396d8195881830700e2d54a0a9ee273e8b1173428e667502ef9c182a3cec7ab7"},
+]
+
+[package.dependencies]
+httpx = ">=0.25.2"
+orjson = ">=3.10.1"
+
+[[package]]
+name = "langgraph-supervisor"
+version = "0.0.27"
+description = "An implementation of a supervisor multi-agent architecture using LangGraph"
+optional = false
+python-versions = ">=3.10"
+groups = ["main"]
+files = [
+ {file = "langgraph_supervisor-0.0.27-py3-none-any.whl", hash = "sha256:f3b200acf04fd7a0476b4688136fee49b0ed1505e6cec7058367e62fec2e8121"},
+ {file = "langgraph_supervisor-0.0.27.tar.gz", hash = "sha256:1d07b722f54ab446e4ce8ad45f26cde7a593a77b1d1641684d91cb8fe6ac725a"},
+]
+
+[package.dependencies]
+langchain-core = ">=0.3.40"
+langgraph = ">=0.3.5"
+langgraph-prebuilt = ">=0.1.7"
+
+[[package]]
+name = "langsmith"
+version = "0.4.4"
+description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform."
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "langsmith-0.4.4-py3-none-any.whl", hash = "sha256:014c68329bd085bd6c770a6405c61bb6881f82eb554ce8c4d1984b0035fd1716"},
+ {file = "langsmith-0.4.4.tar.gz", hash = "sha256:70c53bbff24a7872e88e6fa0af98270f4986a6e364f9e85db1cc5636defa4d66"},
+]
+
+[package.dependencies]
+httpx = ">=0.23.0,<1"
+orjson = {version = ">=3.9.14,<4.0.0", markers = "platform_python_implementation != \"PyPy\""}
+packaging = ">=23.2"
+pydantic = ">=1,<3"
+requests = ">=2,<3"
+requests-toolbelt = ">=1.0.0,<2.0.0"
+zstandard = ">=0.23.0,<0.24.0"
+
+[package.extras]
+langsmith-pyo3 = ["langsmith-pyo3 (>=0.1.0rc2,<0.2.0)"]
+openai-agents = ["openai-agents (>=0.0.3,<0.1)"]
+otel = ["opentelemetry-api (>=1.30.0,<2.0.0)", "opentelemetry-exporter-otlp-proto-http (>=1.30.0,<2.0.0)", "opentelemetry-sdk (>=1.30.0,<2.0.0)"]
+pytest = ["pytest (>=7.0.0)", "rich (>=13.9.4,<14.0.0)"]
+
+[[package]]
+name = "lazify"
+version = "0.4.0"
+description = "Lazify all the things!"
+optional = false
+python-versions = "*"
+groups = ["main"]
+files = [
+ {file = "Lazify-0.4.0-py2.py3-none-any.whl", hash = "sha256:c2c17a7a33e9406897e3f66fde4cd3f84716218d580330e5af10cfe5a0cd195a"},
+ {file = "Lazify-0.4.0.tar.gz", hash = "sha256:7102bfe63e56de2ab62b3bc661a7190c4056771a8624f04a8b785275c3dd1f9b"},
+]
+
+[[package]]
+name = "literalai"
+version = "0.1.201"
+description = "An SDK for observability in Python applications"
+optional = false
+python-versions = "*"
+groups = ["main"]
+files = [
+ {file = "literalai-0.1.201.tar.gz", hash = "sha256:29e4ccadd9d68bfea319a7f0b4fc32611b081990d9195f98e5e97a14d24d3713"},
+]
+
+[package.dependencies]
+chevron = ">=0.14.0"
+httpx = ">=0.23.0"
+packaging = ">=23.0"
+pydantic = ">=1,<3"
+traceloop-sdk = ">=0.33.12"
+
+[[package]]
+name = "markdown-it-py"
+version = "3.0.0"
+description = "Python port of markdown-it. Markdown parsing, done right!"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
+ {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
+]
+
+[package.dependencies]
+mdurl = ">=0.1,<1.0"
+
+[package.extras]
+benchmarking = ["psutil", "pytest", "pytest-benchmark"]
+code-style = ["pre-commit (>=3.0,<4.0)"]
+compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"]
+linkify = ["linkify-it-py (>=1,<3)"]
+plugins = ["mdit-py-plugins"]
+profiling = ["gprof2dot"]
+rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"]
+testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"]
+
+[[package]]
+name = "markupsafe"
+version = "3.0.2"
+description = "Safely add untrusted strings to HTML/XML markup."
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"},
+ {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"},
+ {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"},
+ {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"},
+ {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"},
+ {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"},
+ {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"},
+]
+
+[[package]]
+name = "marshmallow"
+version = "3.26.1"
+description = "A lightweight library for converting complex datatypes to and from native Python datatypes."
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "marshmallow-3.26.1-py3-none-any.whl", hash = "sha256:3350409f20a70a7e4e11a27661187b77cdcaeb20abca41c1454fe33636bea09c"},
+ {file = "marshmallow-3.26.1.tar.gz", hash = "sha256:e6d8affb6cb61d39d26402096dc0aee12d5a26d490a121f118d2e81dc0719dc6"},
+]
+
+[package.dependencies]
+packaging = ">=17.0"
+
+[package.extras]
+dev = ["marshmallow[tests]", "pre-commit (>=3.5,<5.0)", "tox"]
+docs = ["autodocsumm (==0.2.14)", "furo (==2024.8.6)", "sphinx (==8.1.3)", "sphinx-copybutton (==0.5.2)", "sphinx-issues (==5.0.0)", "sphinxext-opengraph (==0.9.1)"]
+tests = ["pytest", "simplejson"]
+
+[[package]]
+name = "mcp"
+version = "1.10.1"
+description = "Model Context Protocol SDK"
+optional = false
+python-versions = ">=3.10"
+groups = ["main"]
+files = [
+ {file = "mcp-1.10.1-py3-none-any.whl", hash = "sha256:4d08301aefe906dce0fa482289db55ce1db831e3e67212e65b5e23ad8454b3c5"},
+ {file = "mcp-1.10.1.tar.gz", hash = "sha256:aaa0957d8307feeff180da2d9d359f2b801f35c0c67f1882136239055ef034c2"},
+]
+
+[package.dependencies]
+anyio = ">=4.5"
+httpx = ">=0.27"
+httpx-sse = ">=0.4"
+jsonschema = ">=4.20.0"
+pydantic = ">=2.7.2,<3.0.0"
+pydantic-settings = ">=2.5.2"
+python-multipart = ">=0.0.9"
+sse-starlette = ">=1.6.1"
+starlette = ">=0.27"
+uvicorn = {version = ">=0.23.1", markers = "sys_platform != \"emscripten\""}
+
+[package.extras]
+cli = ["python-dotenv (>=1.0.0)", "typer (>=0.12.4)"]
+rich = ["rich (>=13.9.4)"]
+ws = ["websockets (>=15.0.1)"]
+
+[[package]]
+name = "mdurl"
+version = "0.1.2"
+description = "Markdown URL utilities"
+optional = false
+python-versions = ">=3.7"
+groups = ["main"]
+files = [
+ {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
+ {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
+]
+
+[[package]]
+name = "monotonic"
+version = "1.6"
+description = "An implementation of time.monotonic() for Python 2 & < 3.3"
+optional = false
+python-versions = "*"
+groups = ["main"]
+files = [
+ {file = "monotonic-1.6-py2.py3-none-any.whl", hash = "sha256:68687e19a14f11f26d140dd5c86f3dba4bf5df58003000ed467e0e2a69bca96c"},
+ {file = "monotonic-1.6.tar.gz", hash = "sha256:3a55207bcfed53ddd5c5bae174524062935efed17792e9de2ad0205ce9ad63f7"},
+]
+
+[[package]]
+name = "multidict"
+version = "6.6.3"
+description = "multidict implementation"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "multidict-6.6.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a2be5b7b35271f7fff1397204ba6708365e3d773579fe2a30625e16c4b4ce817"},
+ {file = "multidict-6.6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12f4581d2930840295c461764b9a65732ec01250b46c6b2c510d7ee68872b140"},
+ {file = "multidict-6.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dd7793bab517e706c9ed9d7310b06c8672fd0aeee5781bfad612f56b8e0f7d14"},
+ {file = "multidict-6.6.3-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:72d8815f2cd3cf3df0f83cac3f3ef801d908b2d90409ae28102e0553af85545a"},
+ {file = "multidict-6.6.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:531e331a2ee53543ab32b16334e2deb26f4e6b9b28e41f8e0c87e99a6c8e2d69"},
+ {file = "multidict-6.6.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:42ca5aa9329a63be8dc49040f63817d1ac980e02eeddba763a9ae5b4027b9c9c"},
+ {file = "multidict-6.6.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:208b9b9757060b9faa6f11ab4bc52846e4f3c2fb8b14d5680c8aac80af3dc751"},
+ {file = "multidict-6.6.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:acf6b97bd0884891af6a8b43d0f586ab2fcf8e717cbd47ab4bdddc09e20652d8"},
+ {file = "multidict-6.6.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:68e9e12ed00e2089725669bdc88602b0b6f8d23c0c95e52b95f0bc69f7fe9b55"},
+ {file = "multidict-6.6.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:05db2f66c9addb10cfa226e1acb363450fab2ff8a6df73c622fefe2f5af6d4e7"},
+ {file = "multidict-6.6.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:0db58da8eafb514db832a1b44f8fa7906fdd102f7d982025f816a93ba45e3dcb"},
+ {file = "multidict-6.6.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:14117a41c8fdb3ee19c743b1c027da0736fdb79584d61a766da53d399b71176c"},
+ {file = "multidict-6.6.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:877443eaaabcd0b74ff32ebeed6f6176c71850feb7d6a1d2db65945256ea535c"},
+ {file = "multidict-6.6.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:70b72e749a4f6e7ed8fb334fa8d8496384840319512746a5f42fa0aec79f4d61"},
+ {file = "multidict-6.6.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:43571f785b86afd02b3855c5ac8e86ec921b760298d6f82ff2a61daf5a35330b"},
+ {file = "multidict-6.6.3-cp310-cp310-win32.whl", hash = "sha256:20c5a0c3c13a15fd5ea86c42311859f970070e4e24de5a550e99d7c271d76318"},
+ {file = "multidict-6.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:ab0a34a007704c625e25a9116c6770b4d3617a071c8a7c30cd338dfbadfe6485"},
+ {file = "multidict-6.6.3-cp310-cp310-win_arm64.whl", hash = "sha256:769841d70ca8bdd140a715746199fc6473414bd02efd678d75681d2d6a8986c5"},
+ {file = "multidict-6.6.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:18f4eba0cbac3546b8ae31e0bbc55b02c801ae3cbaf80c247fcdd89b456ff58c"},
+ {file = "multidict-6.6.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef43b5dd842382329e4797c46f10748d8c2b6e0614f46b4afe4aee9ac33159df"},
+ {file = "multidict-6.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf9bd1fd5eec01494e0f2e8e446a74a85d5e49afb63d75a9934e4a5423dba21d"},
+ {file = "multidict-6.6.3-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:5bd8d6f793a787153956cd35e24f60485bf0651c238e207b9a54f7458b16d539"},
+ {file = "multidict-6.6.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1bf99b4daf908c73856bd87ee0a2499c3c9a3d19bb04b9c6025e66af3fd07462"},
+ {file = "multidict-6.6.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b9e59946b49dafaf990fd9c17ceafa62976e8471a14952163d10a7a630413a9"},
+ {file = "multidict-6.6.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e2db616467070d0533832d204c54eea6836a5e628f2cb1e6dfd8cd6ba7277cb7"},
+ {file = "multidict-6.6.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7394888236621f61dcdd25189b2768ae5cc280f041029a5bcf1122ac63df79f9"},
+ {file = "multidict-6.6.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f114d8478733ca7388e7c7e0ab34b72547476b97009d643644ac33d4d3fe1821"},
+ {file = "multidict-6.6.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cdf22e4db76d323bcdc733514bf732e9fb349707c98d341d40ebcc6e9318ef3d"},
+ {file = "multidict-6.6.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e995a34c3d44ab511bfc11aa26869b9d66c2d8c799fa0e74b28a473a692532d6"},
+ {file = "multidict-6.6.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:766a4a5996f54361d8d5a9050140aa5362fe48ce51c755a50c0bc3706460c430"},
+ {file = "multidict-6.6.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3893a0d7d28a7fe6ca7a1f760593bc13038d1d35daf52199d431b61d2660602b"},
+ {file = "multidict-6.6.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:934796c81ea996e61914ba58064920d6cad5d99140ac3167901eb932150e2e56"},
+ {file = "multidict-6.6.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9ed948328aec2072bc00f05d961ceadfd3e9bfc2966c1319aeaf7b7c21219183"},
+ {file = "multidict-6.6.3-cp311-cp311-win32.whl", hash = "sha256:9f5b28c074c76afc3e4c610c488e3493976fe0e596dd3db6c8ddfbb0134dcac5"},
+ {file = "multidict-6.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc7f6fbc61b1c16050a389c630da0b32fc6d4a3d191394ab78972bf5edc568c2"},
+ {file = "multidict-6.6.3-cp311-cp311-win_arm64.whl", hash = "sha256:d4e47d8faffaae822fb5cba20937c048d4f734f43572e7079298a6c39fb172cb"},
+ {file = "multidict-6.6.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:056bebbeda16b2e38642d75e9e5310c484b7c24e3841dc0fb943206a72ec89d6"},
+ {file = "multidict-6.6.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e5f481cccb3c5c5e5de5d00b5141dc589c1047e60d07e85bbd7dea3d4580d63f"},
+ {file = "multidict-6.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:10bea2ee839a759ee368b5a6e47787f399b41e70cf0c20d90dfaf4158dfb4e55"},
+ {file = "multidict-6.6.3-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:2334cfb0fa9549d6ce2c21af2bfbcd3ac4ec3646b1b1581c88e3e2b1779ec92b"},
+ {file = "multidict-6.6.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8fee016722550a2276ca2cb5bb624480e0ed2bd49125b2b73b7010b9090e888"},
+ {file = "multidict-6.6.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5511cb35f5c50a2db21047c875eb42f308c5583edf96bd8ebf7d770a9d68f6d"},
+ {file = "multidict-6.6.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:712b348f7f449948e0a6c4564a21c7db965af900973a67db432d724619b3c680"},
+ {file = "multidict-6.6.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e4e15d2138ee2694e038e33b7c3da70e6b0ad8868b9f8094a72e1414aeda9c1a"},
+ {file = "multidict-6.6.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8df25594989aebff8a130f7899fa03cbfcc5d2b5f4a461cf2518236fe6f15961"},
+ {file = "multidict-6.6.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:159ca68bfd284a8860f8d8112cf0521113bffd9c17568579e4d13d1f1dc76b65"},
+ {file = "multidict-6.6.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e098c17856a8c9ade81b4810888c5ad1914099657226283cab3062c0540b0643"},
+ {file = "multidict-6.6.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:67c92ed673049dec52d7ed39f8cf9ebbadf5032c774058b4406d18c8f8fe7063"},
+ {file = "multidict-6.6.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:bd0578596e3a835ef451784053cfd327d607fc39ea1a14812139339a18a0dbc3"},
+ {file = "multidict-6.6.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:346055630a2df2115cd23ae271910b4cae40f4e336773550dca4889b12916e75"},
+ {file = "multidict-6.6.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:555ff55a359302b79de97e0468e9ee80637b0de1fce77721639f7cd9440b3a10"},
+ {file = "multidict-6.6.3-cp312-cp312-win32.whl", hash = "sha256:73ab034fb8d58ff85c2bcbadc470efc3fafeea8affcf8722855fb94557f14cc5"},
+ {file = "multidict-6.6.3-cp312-cp312-win_amd64.whl", hash = "sha256:04cbcce84f63b9af41bad04a54d4cc4e60e90c35b9e6ccb130be2d75b71f8c17"},
+ {file = "multidict-6.6.3-cp312-cp312-win_arm64.whl", hash = "sha256:0f1130b896ecb52d2a1e615260f3ea2af55fa7dc3d7c3003ba0c3121a759b18b"},
+ {file = "multidict-6.6.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:540d3c06d48507357a7d57721e5094b4f7093399a0106c211f33540fdc374d55"},
+ {file = "multidict-6.6.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9c19cea2a690f04247d43f366d03e4eb110a0dc4cd1bbeee4d445435428ed35b"},
+ {file = "multidict-6.6.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7af039820cfd00effec86bda5d8debef711a3e86a1d3772e85bea0f243a4bd65"},
+ {file = "multidict-6.6.3-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:500b84f51654fdc3944e936f2922114349bf8fdcac77c3092b03449f0e5bc2b3"},
+ {file = "multidict-6.6.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3fc723ab8a5c5ed6c50418e9bfcd8e6dceba6c271cee6728a10a4ed8561520c"},
+ {file = "multidict-6.6.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:94c47ea3ade005b5976789baaed66d4de4480d0a0bf31cef6edaa41c1e7b56a6"},
+ {file = "multidict-6.6.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dbc7cf464cc6d67e83e136c9f55726da3a30176f020a36ead246eceed87f1cd8"},
+ {file = "multidict-6.6.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:900eb9f9da25ada070f8ee4a23f884e0ee66fe4e1a38c3af644256a508ad81ca"},
+ {file = "multidict-6.6.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c6df517cf177da5d47ab15407143a89cd1a23f8b335f3a28d57e8b0a3dbb884"},
+ {file = "multidict-6.6.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4ef421045f13879e21c994b36e728d8e7d126c91a64b9185810ab51d474f27e7"},
+ {file = "multidict-6.6.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:6c1e61bb4f80895c081790b6b09fa49e13566df8fbff817da3f85b3a8192e36b"},
+ {file = "multidict-6.6.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e5e8523bb12d7623cd8300dbd91b9e439a46a028cd078ca695eb66ba31adee3c"},
+ {file = "multidict-6.6.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:ef58340cc896219e4e653dade08fea5c55c6df41bcc68122e3be3e9d873d9a7b"},
+ {file = "multidict-6.6.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fc9dc435ec8699e7b602b94fe0cd4703e69273a01cbc34409af29e7820f777f1"},
+ {file = "multidict-6.6.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9e864486ef4ab07db5e9cb997bad2b681514158d6954dd1958dfb163b83d53e6"},
+ {file = "multidict-6.6.3-cp313-cp313-win32.whl", hash = "sha256:5633a82fba8e841bc5c5c06b16e21529573cd654f67fd833650a215520a6210e"},
+ {file = "multidict-6.6.3-cp313-cp313-win_amd64.whl", hash = "sha256:e93089c1570a4ad54c3714a12c2cef549dc9d58e97bcded193d928649cab78e9"},
+ {file = "multidict-6.6.3-cp313-cp313-win_arm64.whl", hash = "sha256:c60b401f192e79caec61f166da9c924e9f8bc65548d4246842df91651e83d600"},
+ {file = "multidict-6.6.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:02fd8f32d403a6ff13864b0851f1f523d4c988051eea0471d4f1fd8010f11134"},
+ {file = "multidict-6.6.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f3aa090106b1543f3f87b2041eef3c156c8da2aed90c63a2fbed62d875c49c37"},
+ {file = "multidict-6.6.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e924fb978615a5e33ff644cc42e6aa241effcf4f3322c09d4f8cebde95aff5f8"},
+ {file = "multidict-6.6.3-cp313-cp313t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:b9fe5a0e57c6dbd0e2ce81ca66272282c32cd11d31658ee9553849d91289e1c1"},
+ {file = "multidict-6.6.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b24576f208793ebae00280c59927c3b7c2a3b1655e443a25f753c4611bc1c373"},
+ {file = "multidict-6.6.3-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:135631cb6c58eac37d7ac0df380294fecdc026b28837fa07c02e459c7fb9c54e"},
+ {file = "multidict-6.6.3-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:274d416b0df887aef98f19f21578653982cfb8a05b4e187d4a17103322eeaf8f"},
+ {file = "multidict-6.6.3-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e252017a817fad7ce05cafbe5711ed40faeb580e63b16755a3a24e66fa1d87c0"},
+ {file = "multidict-6.6.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e4cc8d848cd4fe1cdee28c13ea79ab0ed37fc2e89dd77bac86a2e7959a8c3bc"},
+ {file = "multidict-6.6.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9e236a7094b9c4c1b7585f6b9cca34b9d833cf079f7e4c49e6a4a6ec9bfdc68f"},
+ {file = "multidict-6.6.3-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:e0cb0ab69915c55627c933f0b555a943d98ba71b4d1c57bc0d0a66e2567c7471"},
+ {file = "multidict-6.6.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:81ef2f64593aba09c5212a3d0f8c906a0d38d710a011f2f42759704d4557d3f2"},
+ {file = "multidict-6.6.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:b9cbc60010de3562545fa198bfc6d3825df430ea96d2cc509c39bd71e2e7d648"},
+ {file = "multidict-6.6.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:70d974eaaa37211390cd02ef93b7e938de564bbffa866f0b08d07e5e65da783d"},
+ {file = "multidict-6.6.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3713303e4a6663c6d01d648a68f2848701001f3390a030edaaf3fc949c90bf7c"},
+ {file = "multidict-6.6.3-cp313-cp313t-win32.whl", hash = "sha256:639ecc9fe7cd73f2495f62c213e964843826f44505a3e5d82805aa85cac6f89e"},
+ {file = "multidict-6.6.3-cp313-cp313t-win_amd64.whl", hash = "sha256:9f97e181f344a0ef3881b573d31de8542cc0dbc559ec68c8f8b5ce2c2e91646d"},
+ {file = "multidict-6.6.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ce8b7693da41a3c4fde5871c738a81490cea5496c671d74374c8ab889e1834fb"},
+ {file = "multidict-6.6.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c8161b5a7778d3137ea2ee7ae8a08cce0010de3b00ac671c5ebddeaa17cefd22"},
+ {file = "multidict-6.6.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1328201ee930f069961ae707d59c6627ac92e351ed5b92397cf534d1336ce557"},
+ {file = "multidict-6.6.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b1db4d2093d6b235de76932febf9d50766cf49a5692277b2c28a501c9637f616"},
+ {file = "multidict-6.6.3-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53becb01dd8ebd19d1724bebe369cfa87e4e7f29abbbe5c14c98ce4c383e16cd"},
+ {file = "multidict-6.6.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41bb9d1d4c303886e2d85bade86e59885112a7f4277af5ad47ab919a2251f306"},
+ {file = "multidict-6.6.3-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:775b464d31dac90f23192af9c291dc9f423101857e33e9ebf0020a10bfcf4144"},
+ {file = "multidict-6.6.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d04d01f0a913202205a598246cf77826fe3baa5a63e9f6ccf1ab0601cf56eca0"},
+ {file = "multidict-6.6.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d25594d3b38a2e6cabfdcafef339f754ca6e81fbbdb6650ad773ea9775af35ab"},
+ {file = "multidict-6.6.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:35712f1748d409e0707b165bf49f9f17f9e28ae85470c41615778f8d4f7d9609"},
+ {file = "multidict-6.6.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1c8082e5814b662de8589d6a06c17e77940d5539080cbab9fe6794b5241b76d9"},
+ {file = "multidict-6.6.3-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:61af8a4b771f1d4d000b3168c12c3120ccf7284502a94aa58c68a81f5afac090"},
+ {file = "multidict-6.6.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:448e4a9afccbf297577f2eaa586f07067441e7b63c8362a3540ba5a38dc0f14a"},
+ {file = "multidict-6.6.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:233ad16999afc2bbd3e534ad8dbe685ef8ee49a37dbc2cdc9514e57b6d589ced"},
+ {file = "multidict-6.6.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:bb933c891cd4da6bdcc9733d048e994e22e1883287ff7540c2a0f3b117605092"},
+ {file = "multidict-6.6.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:37b09ca60998e87734699e88c2363abfd457ed18cfbf88e4009a4e83788e63ed"},
+ {file = "multidict-6.6.3-cp39-cp39-win32.whl", hash = "sha256:f54cb79d26d0cd420637d184af38f0668558f3c4bbe22ab7ad830e67249f2e0b"},
+ {file = "multidict-6.6.3-cp39-cp39-win_amd64.whl", hash = "sha256:295adc9c0551e5d5214b45cf29ca23dbc28c2d197a9c30d51aed9e037cb7c578"},
+ {file = "multidict-6.6.3-cp39-cp39-win_arm64.whl", hash = "sha256:15332783596f227db50fb261c2c251a58ac3873c457f3a550a95d5c0aa3c770d"},
+ {file = "multidict-6.6.3-py3-none-any.whl", hash = "sha256:8db10f29c7541fc5da4defd8cd697e1ca429db743fa716325f236079b96f775a"},
+ {file = "multidict-6.6.3.tar.gz", hash = "sha256:798a9eb12dab0a6c2e29c1de6f3468af5cb2da6053a20dfa3344907eed0937cc"},
+]
+
+[[package]]
+name = "mypy-extensions"
+version = "1.1.0"
+description = "Type system extensions for programs checked with the mypy type checker."
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"},
+ {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"},
+]
+
+[[package]]
+name = "nest-asyncio"
+version = "1.6.0"
+description = "Patch asyncio to allow nested event loops"
+optional = false
+python-versions = ">=3.5"
+groups = ["main"]
+files = [
+ {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"},
+ {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"},
+]
+
+[[package]]
+name = "numpy"
+version = "2.3.1"
+description = "Fundamental package for array computing in Python"
+optional = false
+python-versions = ">=3.11"
+groups = ["main"]
+files = [
+ {file = "numpy-2.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6ea9e48336a402551f52cd8f593343699003d2353daa4b72ce8d34f66b722070"},
+ {file = "numpy-2.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5ccb7336eaf0e77c1635b232c141846493a588ec9ea777a7c24d7166bb8533ae"},
+ {file = "numpy-2.3.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:0bb3a4a61e1d327e035275d2a993c96fa786e4913aa089843e6a2d9dd205c66a"},
+ {file = "numpy-2.3.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:e344eb79dab01f1e838ebb67aab09965fb271d6da6b00adda26328ac27d4a66e"},
+ {file = "numpy-2.3.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:467db865b392168ceb1ef1ffa6f5a86e62468c43e0cfb4ab6da667ede10e58db"},
+ {file = "numpy-2.3.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:afed2ce4a84f6b0fc6c1ce734ff368cbf5a5e24e8954a338f3bdffa0718adffb"},
+ {file = "numpy-2.3.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0025048b3c1557a20bc80d06fdeb8cc7fc193721484cca82b2cfa072fec71a93"},
+ {file = "numpy-2.3.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a5ee121b60aa509679b682819c602579e1df14a5b07fe95671c8849aad8f2115"},
+ {file = "numpy-2.3.1-cp311-cp311-win32.whl", hash = "sha256:a8b740f5579ae4585831b3cf0e3b0425c667274f82a484866d2adf9570539369"},
+ {file = "numpy-2.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:d4580adadc53311b163444f877e0789f1c8861e2698f6b2a4ca852fda154f3ff"},
+ {file = "numpy-2.3.1-cp311-cp311-win_arm64.whl", hash = "sha256:ec0bdafa906f95adc9a0c6f26a4871fa753f25caaa0e032578a30457bff0af6a"},
+ {file = "numpy-2.3.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2959d8f268f3d8ee402b04a9ec4bb7604555aeacf78b360dc4ec27f1d508177d"},
+ {file = "numpy-2.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:762e0c0c6b56bdedfef9a8e1d4538556438288c4276901ea008ae44091954e29"},
+ {file = "numpy-2.3.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:867ef172a0976aaa1f1d1b63cf2090de8b636a7674607d514505fb7276ab08fc"},
+ {file = "numpy-2.3.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:4e602e1b8682c2b833af89ba641ad4176053aaa50f5cacda1a27004352dde943"},
+ {file = "numpy-2.3.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:8e333040d069eba1652fb08962ec5b76af7f2c7bce1df7e1418c8055cf776f25"},
+ {file = "numpy-2.3.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e7cbf5a5eafd8d230a3ce356d892512185230e4781a361229bd902ff403bc660"},
+ {file = "numpy-2.3.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5f1b8f26d1086835f442286c1d9b64bb3974b0b1e41bb105358fd07d20872952"},
+ {file = "numpy-2.3.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ee8340cb48c9b7a5899d1149eece41ca535513a9698098edbade2a8e7a84da77"},
+ {file = "numpy-2.3.1-cp312-cp312-win32.whl", hash = "sha256:e772dda20a6002ef7061713dc1e2585bc1b534e7909b2030b5a46dae8ff077ab"},
+ {file = "numpy-2.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:cfecc7822543abdea6de08758091da655ea2210b8ffa1faf116b940693d3df76"},
+ {file = "numpy-2.3.1-cp312-cp312-win_arm64.whl", hash = "sha256:7be91b2239af2658653c5bb6f1b8bccafaf08226a258caf78ce44710a0160d30"},
+ {file = "numpy-2.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:25a1992b0a3fdcdaec9f552ef10d8103186f5397ab45e2d25f8ac51b1a6b97e8"},
+ {file = "numpy-2.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7dea630156d39b02a63c18f508f85010230409db5b2927ba59c8ba4ab3e8272e"},
+ {file = "numpy-2.3.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:bada6058dd886061f10ea15f230ccf7dfff40572e99fef440a4a857c8728c9c0"},
+ {file = "numpy-2.3.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:a894f3816eb17b29e4783e5873f92faf55b710c2519e5c351767c51f79d8526d"},
+ {file = "numpy-2.3.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:18703df6c4a4fee55fd3d6e5a253d01c5d33a295409b03fda0c86b3ca2ff41a1"},
+ {file = "numpy-2.3.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:5902660491bd7a48b2ec16c23ccb9124b8abfd9583c5fdfa123fe6b421e03de1"},
+ {file = "numpy-2.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:36890eb9e9d2081137bd78d29050ba63b8dab95dff7912eadf1185e80074b2a0"},
+ {file = "numpy-2.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a780033466159c2270531e2b8ac063704592a0bc62ec4a1b991c7c40705eb0e8"},
+ {file = "numpy-2.3.1-cp313-cp313-win32.whl", hash = "sha256:39bff12c076812595c3a306f22bfe49919c5513aa1e0e70fac756a0be7c2a2b8"},
+ {file = "numpy-2.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:8d5ee6eec45f08ce507a6570e06f2f879b374a552087a4179ea7838edbcbfa42"},
+ {file = "numpy-2.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:0c4d9e0a8368db90f93bd192bfa771ace63137c3488d198ee21dfb8e7771916e"},
+ {file = "numpy-2.3.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:b0b5397374f32ec0649dd98c652a1798192042e715df918c20672c62fb52d4b8"},
+ {file = "numpy-2.3.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c5bdf2015ccfcee8253fb8be695516ac4457c743473a43290fd36eba6a1777eb"},
+ {file = "numpy-2.3.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:d70f20df7f08b90a2062c1f07737dd340adccf2068d0f1b9b3d56e2038979fee"},
+ {file = "numpy-2.3.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:2fb86b7e58f9ac50e1e9dd1290154107e47d1eef23a0ae9145ded06ea606f992"},
+ {file = "numpy-2.3.1-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:23ab05b2d241f76cb883ce8b9a93a680752fbfcbd51c50eff0b88b979e471d8c"},
+ {file = "numpy-2.3.1-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:ce2ce9e5de4703a673e705183f64fd5da5bf36e7beddcb63a25ee2286e71ca48"},
+ {file = "numpy-2.3.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c4913079974eeb5c16ccfd2b1f09354b8fed7e0d6f2cab933104a09a6419b1ee"},
+ {file = "numpy-2.3.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:010ce9b4f00d5c036053ca684c77441f2f2c934fd23bee058b4d6f196efd8280"},
+ {file = "numpy-2.3.1-cp313-cp313t-win32.whl", hash = "sha256:6269b9edfe32912584ec496d91b00b6d34282ca1d07eb10e82dfc780907d6c2e"},
+ {file = "numpy-2.3.1-cp313-cp313t-win_amd64.whl", hash = "sha256:2a809637460e88a113e186e87f228d74ae2852a2e0c44de275263376f17b5bdc"},
+ {file = "numpy-2.3.1-cp313-cp313t-win_arm64.whl", hash = "sha256:eccb9a159db9aed60800187bc47a6d3451553f0e1b08b068d8b277ddfbb9b244"},
+ {file = "numpy-2.3.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ad506d4b09e684394c42c966ec1527f6ebc25da7f4da4b1b056606ffe446b8a3"},
+ {file = "numpy-2.3.1-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:ebb8603d45bc86bbd5edb0d63e52c5fd9e7945d3a503b77e486bd88dde67a19b"},
+ {file = "numpy-2.3.1-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:15aa4c392ac396e2ad3d0a2680c0f0dee420f9fed14eef09bdb9450ee6dcb7b7"},
+ {file = "numpy-2.3.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c6e0bf9d1a2f50d2b65a7cf56db37c095af17b59f6c132396f7c6d5dd76484df"},
+ {file = "numpy-2.3.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:eabd7e8740d494ce2b4ea0ff05afa1b7b291e978c0ae075487c51e8bd93c0c68"},
+ {file = "numpy-2.3.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:e610832418a2bc09d974cc9fecebfa51e9532d6190223bc5ef6a7402ebf3b5cb"},
+ {file = "numpy-2.3.1.tar.gz", hash = "sha256:1ec9ae20a4226da374362cca3c62cd753faf2f951440b0e3b98e93c235441d2b"},
+]
+
+[[package]]
+name = "openai"
+version = "1.93.0"
+description = "The official Python library for the openai API"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "openai-1.93.0-py3-none-any.whl", hash = "sha256:3d746fe5498f0dd72e0d9ab706f26c91c0f646bf7459e5629af8ba7c9dbdf090"},
+ {file = "openai-1.93.0.tar.gz", hash = "sha256:988f31ade95e1ff0585af11cc5a64510225e4f5cd392698c675d0a9265b8e337"},
+]
+
+[package.dependencies]
+anyio = ">=3.5.0,<5"
+distro = ">=1.7.0,<2"
+httpx = ">=0.23.0,<1"
+jiter = ">=0.4.0,<1"
+pydantic = ">=1.9.0,<3"
+sniffio = "*"
+tqdm = ">4"
+typing-extensions = ">=4.11,<5"
+
+[package.extras]
+aiohttp = ["aiohttp", "httpx-aiohttp (>=0.1.6)"]
+datalib = ["numpy (>=1)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"]
+realtime = ["websockets (>=13,<16)"]
+voice-helpers = ["numpy (>=2.0.2)", "sounddevice (>=0.5.1)"]
+
+[[package]]
+name = "opentelemetry-api"
+version = "1.34.1"
+description = "OpenTelemetry Python API"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_api-1.34.1-py3-none-any.whl", hash = "sha256:b7df4cb0830d5a6c29ad0c0691dbae874d8daefa934b8b1d642de48323d32a8c"},
+ {file = "opentelemetry_api-1.34.1.tar.gz", hash = "sha256:64f0bd06d42824843731d05beea88d4d4b6ae59f9fe347ff7dfa2cc14233bbb3"},
+]
+
+[package.dependencies]
+importlib-metadata = ">=6.0,<8.8.0"
+typing-extensions = ">=4.5.0"
+
+[[package]]
+name = "opentelemetry-exporter-otlp"
+version = "1.34.1"
+description = "OpenTelemetry Collector Exporters"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_exporter_otlp-1.34.1-py3-none-any.whl", hash = "sha256:f4a453e9cde7f6362fd4a090d8acf7881d1dc585540c7b65cbd63e36644238d4"},
+ {file = "opentelemetry_exporter_otlp-1.34.1.tar.gz", hash = "sha256:71c9ad342d665d9e4235898d205db17c5764cd7a69acb8a5dcd6d5e04c4c9988"},
+]
+
+[package.dependencies]
+opentelemetry-exporter-otlp-proto-grpc = "1.34.1"
+opentelemetry-exporter-otlp-proto-http = "1.34.1"
+
+[[package]]
+name = "opentelemetry-exporter-otlp-proto-common"
+version = "1.34.1"
+description = "OpenTelemetry Protobuf encoding"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_exporter_otlp_proto_common-1.34.1-py3-none-any.whl", hash = "sha256:8e2019284bf24d3deebbb6c59c71e6eef3307cd88eff8c633e061abba33f7e87"},
+ {file = "opentelemetry_exporter_otlp_proto_common-1.34.1.tar.gz", hash = "sha256:b59a20a927facd5eac06edaf87a07e49f9e4a13db487b7d8a52b37cb87710f8b"},
+]
+
+[package.dependencies]
+opentelemetry-proto = "1.34.1"
+
+[[package]]
+name = "opentelemetry-exporter-otlp-proto-grpc"
+version = "1.34.1"
+description = "OpenTelemetry Collector Protobuf over gRPC Exporter"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_exporter_otlp_proto_grpc-1.34.1-py3-none-any.whl", hash = "sha256:04bb8b732b02295be79f8a86a4ad28fae3d4ddb07307a98c7aa6f331de18cca6"},
+ {file = "opentelemetry_exporter_otlp_proto_grpc-1.34.1.tar.gz", hash = "sha256:7c841b90caa3aafcfc4fee58487a6c71743c34c6dc1787089d8b0578bbd794dd"},
+]
+
+[package.dependencies]
+googleapis-common-protos = ">=1.52,<2.0"
+grpcio = [
+ {version = ">=1.63.2,<2.0.0", markers = "python_version < \"3.13\""},
+ {version = ">=1.66.2,<2.0.0", markers = "python_version >= \"3.13\""},
+]
+opentelemetry-api = ">=1.15,<2.0"
+opentelemetry-exporter-otlp-proto-common = "1.34.1"
+opentelemetry-proto = "1.34.1"
+opentelemetry-sdk = ">=1.34.1,<1.35.0"
+typing-extensions = ">=4.5.0"
+
+[[package]]
+name = "opentelemetry-exporter-otlp-proto-http"
+version = "1.34.1"
+description = "OpenTelemetry Collector Protobuf over HTTP Exporter"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_exporter_otlp_proto_http-1.34.1-py3-none-any.whl", hash = "sha256:5251f00ca85872ce50d871f6d3cc89fe203b94c3c14c964bbdc3883366c705d8"},
+ {file = "opentelemetry_exporter_otlp_proto_http-1.34.1.tar.gz", hash = "sha256:aaac36fdce46a8191e604dcf632e1f9380c7d5b356b27b3e0edb5610d9be28ad"},
+]
+
+[package.dependencies]
+googleapis-common-protos = ">=1.52,<2.0"
+opentelemetry-api = ">=1.15,<2.0"
+opentelemetry-exporter-otlp-proto-common = "1.34.1"
+opentelemetry-proto = "1.34.1"
+opentelemetry-sdk = ">=1.34.1,<1.35.0"
+requests = ">=2.7,<3.0"
+typing-extensions = ">=4.5.0"
+
+[[package]]
+name = "opentelemetry-instrumentation"
+version = "0.55b1"
+description = "Instrumentation Tools & Auto Instrumentation for OpenTelemetry Python"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation-0.55b1-py3-none-any.whl", hash = "sha256:cbb1496b42bc394e01bc63701b10e69094e8564e281de063e4328d122cc7a97e"},
+ {file = "opentelemetry_instrumentation-0.55b1.tar.gz", hash = "sha256:2dc50aa207b9bfa16f70a1a0571e011e737a9917408934675b89ef4d5718c87b"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.4,<2.0"
+opentelemetry-semantic-conventions = "0.55b1"
+packaging = ">=18.0"
+wrapt = ">=1.0.0,<2.0.0"
+
+[[package]]
+name = "opentelemetry-instrumentation-alephalpha"
+version = "0.40.14"
+description = "OpenTelemetry Aleph Alpha instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_alephalpha-0.40.14-py3-none-any.whl", hash = "sha256:2dfc50a7ab40edca2fecc18c38f3b7ef3942294bda2e8283298bbd51ec1f3f82"},
+ {file = "opentelemetry_instrumentation_alephalpha-0.40.14.tar.gz", hash = "sha256:a015d7697645e9275637152d1d94f2df8e3f7c9d1ee3f983f4987ffc927f186c"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-anthropic"
+version = "0.40.14"
+description = "OpenTelemetry Anthropic instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_anthropic-0.40.14-py3-none-any.whl", hash = "sha256:d516a7aaa4b81b6fa6585f3db7a84feacb288fc56721484c63422ea6a9119c00"},
+ {file = "opentelemetry_instrumentation_anthropic-0.40.14.tar.gz", hash = "sha256:5450cc52fbbd916c21fc74df511e93ce794e889fbd916f90decaa1240893419e"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-bedrock"
+version = "0.40.14"
+description = "OpenTelemetry Bedrock instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_bedrock-0.40.14-py3-none-any.whl", hash = "sha256:ba2a78bbc83f246f52bd1eaf2ed6d4a53ab37fad09ff0ca550b7f7bc3f0f9466"},
+ {file = "opentelemetry_instrumentation_bedrock-0.40.14.tar.gz", hash = "sha256:6e3be927922825992baf07e45521ed4f9cfd5d015e7d14714d478920241d6656"},
+]
+
+[package.dependencies]
+anthropic = ">=0.17.0"
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+tokenizers = ">=0.13.0"
+
+[[package]]
+name = "opentelemetry-instrumentation-chromadb"
+version = "0.40.14"
+description = "OpenTelemetry Chroma DB instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_chromadb-0.40.14-py3-none-any.whl", hash = "sha256:ac721939d63c988f787e11f22e2df8003da4f8346c7485d7c25fb82a4edf5f9f"},
+ {file = "opentelemetry_instrumentation_chromadb-0.40.14.tar.gz", hash = "sha256:db2f01b324f95b5b69a6ad2152d855c1707290d3cd270702f3216cbae736c6d5"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-cohere"
+version = "0.40.14"
+description = "OpenTelemetry Cohere instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_cohere-0.40.14-py3-none-any.whl", hash = "sha256:23457fb8d0bffc405f1d22b940c49ac00358b2f5f5190466a2d687e62b819bf6"},
+ {file = "opentelemetry_instrumentation_cohere-0.40.14.tar.gz", hash = "sha256:4515396ca8b381fde45b7905db33a4da45a01c5346e4b4a567dff160bd85fb5e"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-crewai"
+version = "0.40.14"
+description = "OpenTelemetry crewAI instrumentation"
+optional = false
+python-versions = "<4,>=3.10"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_crewai-0.40.14-py3-none-any.whl", hash = "sha256:021ef20c0761a77be803623ce90e0697d17c27615d4aba8012d8b72982528641"},
+ {file = "opentelemetry_instrumentation_crewai-0.40.14.tar.gz", hash = "sha256:ce8b0140210c3a695a205bda1a6a0579c50aaf862598d20a5c3eebb7fb74401d"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-google-generativeai"
+version = "0.40.14"
+description = "OpenTelemetry Google Generative AI instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_google_generativeai-0.40.14-py3-none-any.whl", hash = "sha256:37493f5a71e78965f75656c41df79230ead1cc567605e14598881b636df1d160"},
+ {file = "opentelemetry_instrumentation_google_generativeai-0.40.14.tar.gz", hash = "sha256:2dcf193240641b31368624c1f7a5783ea0cf31c3be72d1460cf1cf014cc477de"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-groq"
+version = "0.40.14"
+description = "OpenTelemetry Groq instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_groq-0.40.14-py3-none-any.whl", hash = "sha256:f53342c8980d7546264e41cf4afecb604f4b590430dfe2d9d863b97225e2ee0a"},
+ {file = "opentelemetry_instrumentation_groq-0.40.14.tar.gz", hash = "sha256:f2f6b787382dac7309f28eed7f27a8ff6e36caf7e8fe85c02f09fc75b9967838"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-haystack"
+version = "0.40.14"
+description = "OpenTelemetry Haystack instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_haystack-0.40.14-py3-none-any.whl", hash = "sha256:b11c6e57c0c66dc9154f7c8328c5018501f268224c53307c0518a6e407d91cae"},
+ {file = "opentelemetry_instrumentation_haystack-0.40.14.tar.gz", hash = "sha256:e49be73ccb2302ebace9a28014ab20dbcaec6d00893358de54b9054202596f9b"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-lancedb"
+version = "0.40.14"
+description = "OpenTelemetry Lancedb instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_lancedb-0.40.14-py3-none-any.whl", hash = "sha256:3dc37d8b2791fe4769c1b8ffe90c9ccd53af57ccd0ec100ed3da387b60b88021"},
+ {file = "opentelemetry_instrumentation_lancedb-0.40.14.tar.gz", hash = "sha256:0907ddd3f8639880c2c65cb94789dc4ca0b0ef19a79173dd1278ab7fd80178a6"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-langchain"
+version = "0.40.14"
+description = "OpenTelemetry Langchain instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_langchain-0.40.14-py3-none-any.whl", hash = "sha256:f400d25b1c5fb03fcaabae40970a7980d9c45d2b22e0ceeb99ce62b7b3d3c6e2"},
+ {file = "opentelemetry_instrumentation_langchain-0.40.14.tar.gz", hash = "sha256:a196eef6990b98fc67acca945883e39fbdaf075f8a36636e7a9e580092f7c3ea"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-llamaindex"
+version = "0.40.14"
+description = "OpenTelemetry LlamaIndex instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_llamaindex-0.40.14-py3-none-any.whl", hash = "sha256:20362a9e94cf3a5632e62baaedd1f1a003674230d6a4352f2a83716751351267"},
+ {file = "opentelemetry_instrumentation_llamaindex-0.40.14.tar.gz", hash = "sha256:9916136126cd59c8360b189b022af6337f3ed091dccbf11317b045c452e5185b"},
+]
+
+[package.dependencies]
+inflection = ">=0.5.1,<0.6.0"
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-logging"
+version = "0.55b1"
+description = "OpenTelemetry Logging instrumentation"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_logging-0.55b1-py3-none-any.whl", hash = "sha256:1b34b7bfcfa6a22f58f2000f041f5c169c5074738cf23bd33599f60ae1ecf1c5"},
+ {file = "opentelemetry_instrumentation_logging-0.55b1.tar.gz", hash = "sha256:8ab1e68a2496d36ed2388ec3178495d9fa31f805b93c5845f83f1fab718f28d0"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.12,<2.0"
+opentelemetry-instrumentation = "0.55b1"
+
+[[package]]
+name = "opentelemetry-instrumentation-marqo"
+version = "0.40.14"
+description = "OpenTelemetry Marqo instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_marqo-0.40.14-py3-none-any.whl", hash = "sha256:db93511f2a6990cf6cc3dcbb1279847f72723671503ca4a5a896c3595711e932"},
+ {file = "opentelemetry_instrumentation_marqo-0.40.14.tar.gz", hash = "sha256:1710e2d079ccb7e5aef9d204acde5bae002028a95865fec3e711ae1f07ffbc25"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-mcp"
+version = "0.40.14"
+description = "OpenTelemetry mcp instrumentation"
+optional = false
+python-versions = "<4,>=3.10"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_mcp-0.40.14-py3-none-any.whl", hash = "sha256:8ac37b7e138c48ea85cb67c8e737fb3b18b618650a7c2239731e6a7190586e65"},
+ {file = "opentelemetry_instrumentation_mcp-0.40.14.tar.gz", hash = "sha256:32ed438acc1e21d26e991ea5c5c9b03f381faf8d963878f2822e45e666a41a1c"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-milvus"
+version = "0.40.14"
+description = "OpenTelemetry Milvus instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_milvus-0.40.14-py3-none-any.whl", hash = "sha256:02c3c8e50558aed577d3527ca81904106a3ea86304b69fef9a2e8d7b2f9581a5"},
+ {file = "opentelemetry_instrumentation_milvus-0.40.14.tar.gz", hash = "sha256:7c7e3fb830acfac2a0b102c408f4c40f2c5b86e22cf12bebe35cc7555c612e5b"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-mistralai"
+version = "0.40.14"
+description = "OpenTelemetry Mistral AI instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_mistralai-0.40.14-py3-none-any.whl", hash = "sha256:be0360b8184d287aaf94e970ada56812ff6c313c23f78984f886948279ad2df7"},
+ {file = "opentelemetry_instrumentation_mistralai-0.40.14.tar.gz", hash = "sha256:17f77f82d3f3843a4c5d25c42899e729d572e1b1d5ae1947a0b8e8a9ef4f5665"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-ollama"
+version = "0.40.14"
+description = "OpenTelemetry Ollama instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_ollama-0.40.14-py3-none-any.whl", hash = "sha256:d38f31f8d06ef25acce34c490c8d113476781e2b2b2b50964c97c79d4fef3ad7"},
+ {file = "opentelemetry_instrumentation_ollama-0.40.14.tar.gz", hash = "sha256:6589aef14575e87f68e129e0f989742a8d751f029e56bccf158791202380e2cb"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-openai"
+version = "0.40.14"
+description = "OpenTelemetry OpenAI instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_openai-0.40.14-py3-none-any.whl", hash = "sha256:72319113370a018390e9c987dc3dac569380591fbaa5639c5e5cacd3f3165f4a"},
+ {file = "opentelemetry_instrumentation_openai-0.40.14.tar.gz", hash = "sha256:3ba8e36a3853833f5c0c6b3b8ffa0f1289e6423e0d428bd1c7b3f27abdc545f0"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+tiktoken = ">=0.6.0,<1"
+
+[[package]]
+name = "opentelemetry-instrumentation-pinecone"
+version = "0.40.14"
+description = "OpenTelemetry Pinecone instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_pinecone-0.40.14-py3-none-any.whl", hash = "sha256:a3cd747468ddb4a6f4caf249f3d7a21b61dc8c3fb9c44cb586943a7eec56ab3a"},
+ {file = "opentelemetry_instrumentation_pinecone-0.40.14.tar.gz", hash = "sha256:314be6cdc847dacde4a96d352c3739d809ed8753992e6e25f1e7d9586eb781d3"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-qdrant"
+version = "0.40.14"
+description = "OpenTelemetry Qdrant instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_qdrant-0.40.14-py3-none-any.whl", hash = "sha256:12666e657529977c4b08f78c869eba4868ff214c77cf6f40947b36934254a0c2"},
+ {file = "opentelemetry_instrumentation_qdrant-0.40.14.tar.gz", hash = "sha256:eef5b9a8a4a8069eca1d06652c2d5ba0fa9a012c5b2f48c7577507b5219528d0"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-redis"
+version = "0.55b1"
+description = "OpenTelemetry Redis instrumentation"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_redis-0.55b1-py3-none-any.whl", hash = "sha256:8f40d742e1666e0e971f2385b47ddf6f55da2fe6bf77d2ff5f8f3b27cd5746b6"},
+ {file = "opentelemetry_instrumentation_redis-0.55b1.tar.gz", hash = "sha256:bce9b47907e08ede4961b845030fbffbf8e6f515e1b48b4697c5f36704a97743"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.12,<2.0"
+opentelemetry-instrumentation = "0.55b1"
+opentelemetry-semantic-conventions = "0.55b1"
+wrapt = ">=1.12.1"
+
+[package.extras]
+instruments = ["redis (>=2.6)"]
+
+[[package]]
+name = "opentelemetry-instrumentation-replicate"
+version = "0.40.14"
+description = "OpenTelemetry Replicate instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_replicate-0.40.14-py3-none-any.whl", hash = "sha256:7f204bb5b36ee69c2068c3cdaac6ec9b49b449c07b2d39cb47157b672e59751d"},
+ {file = "opentelemetry_instrumentation_replicate-0.40.14.tar.gz", hash = "sha256:d010113254a1cdc142bc74e7feaff555344692eb808b46eebb25c56a26db5281"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-requests"
+version = "0.55b1"
+description = "OpenTelemetry requests instrumentation"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_requests-0.55b1-py3-none-any.whl", hash = "sha256:c9ba0a67850b49aa965e760e87e4b68e52530e5373a0b3c15d290a8997136619"},
+ {file = "opentelemetry_instrumentation_requests-0.55b1.tar.gz", hash = "sha256:3a04ae7bc90af08acef074b369275cf77c60533b319fa91cad76a380fd035c83"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.12,<2.0"
+opentelemetry-instrumentation = "0.55b1"
+opentelemetry-semantic-conventions = "0.55b1"
+opentelemetry-util-http = "0.55b1"
+
+[package.extras]
+instruments = ["requests (>=2.0,<3.0)"]
+
+[[package]]
+name = "opentelemetry-instrumentation-sagemaker"
+version = "0.40.14"
+description = "OpenTelemetry SageMaker instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_sagemaker-0.40.14-py3-none-any.whl", hash = "sha256:28d7cc2c43b77bb69f20d8902c0bede9b828f9bfb7aa8ebe75fd542dcb8a6545"},
+ {file = "opentelemetry_instrumentation_sagemaker-0.40.14.tar.gz", hash = "sha256:d1d31423a4d57239428d2b925e4801d61782b52adb9b80baf4e86c6f03b1ad06"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.26.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-sqlalchemy"
+version = "0.55b1"
+description = "OpenTelemetry SQLAlchemy instrumentation"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_sqlalchemy-0.55b1-py3-none-any.whl", hash = "sha256:d6b3cac2cc3301083608d3c0e2b3979f62c6ab327a12f5a7c779f9ab05eb6633"},
+ {file = "opentelemetry_instrumentation_sqlalchemy-0.55b1.tar.gz", hash = "sha256:3a25cfb75de9bb14d26ab274b90d5613867c976e93cde0c5fb673cb731006532"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.12,<2.0"
+opentelemetry-instrumentation = "0.55b1"
+opentelemetry-semantic-conventions = "0.55b1"
+packaging = ">=21.0"
+wrapt = ">=1.11.2"
+
+[package.extras]
+instruments = ["sqlalchemy (>=1.0.0,<2.1.0)"]
+
+[[package]]
+name = "opentelemetry-instrumentation-threading"
+version = "0.55b1"
+description = "Thread context propagation support for OpenTelemetry"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_threading-0.55b1-py3-none-any.whl", hash = "sha256:f865542b32b219c8fd01deb03b8c3c9ba2eb3f0501ae303338403fd2242962c7"},
+ {file = "opentelemetry_instrumentation_threading-0.55b1.tar.gz", hash = "sha256:4ed68502e7ed017bfc10b1f9e508cc5ccaea0e46ac1010f7f2541ab9c6eacd92"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.12,<2.0"
+opentelemetry-instrumentation = "0.55b1"
+wrapt = ">=1.0.0,<2.0.0"
+
+[[package]]
+name = "opentelemetry-instrumentation-together"
+version = "0.40.14"
+description = "OpenTelemetry Together AI instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_together-0.40.14-py3-none-any.whl", hash = "sha256:7e5fe1793ab624fc8c104a46f707beabaaaec92666b0551c0ac80355ba324c17"},
+ {file = "opentelemetry_instrumentation_together-0.40.14.tar.gz", hash = "sha256:bdee203caa0e3a4dff5f20e0a7802860ea51d021a714e89de919091226fadb99"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-transformers"
+version = "0.40.14"
+description = "OpenTelemetry transformers instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_transformers-0.40.14-py3-none-any.whl", hash = "sha256:b7de54a27b4de8724981bb69c2cb4ec740e084dbea2ec834349b71b6d503c85d"},
+ {file = "opentelemetry_instrumentation_transformers-0.40.14.tar.gz", hash = "sha256:7dc3e11055a16c29e5bb9b0892deb9edb4927e4390d83c6678ca360af818fbff"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-urllib3"
+version = "0.55b1"
+description = "OpenTelemetry urllib3 instrumentation"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_urllib3-0.55b1-py3-none-any.whl", hash = "sha256:41c4a3a01194a713cd82c2067705f6ebc92652b9de56ac741594ce28afa01e09"},
+ {file = "opentelemetry_instrumentation_urllib3-0.55b1.tar.gz", hash = "sha256:2999eb2652c7461ea308ff1b3a61726a695e9df1cc2635b2627017b3a42ee214"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.12,<2.0"
+opentelemetry-instrumentation = "0.55b1"
+opentelemetry-semantic-conventions = "0.55b1"
+opentelemetry-util-http = "0.55b1"
+wrapt = ">=1.0.0,<2.0.0"
+
+[package.extras]
+instruments = ["urllib3 (>=1.0.0,<3.0.0)"]
+
+[[package]]
+name = "opentelemetry-instrumentation-vertexai"
+version = "0.40.14"
+description = "OpenTelemetry Vertex AI instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_vertexai-0.40.14-py3-none-any.whl", hash = "sha256:5146387a0060fbdec87a8cbbf5bee2aae7afb791cfd673fded2fa7394021cfb6"},
+ {file = "opentelemetry_instrumentation_vertexai-0.40.14.tar.gz", hash = "sha256:f6f8ecd47576575ff62d645d1b343cfbdc4143d7b3c4b1424605ab6278d5122b"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-watsonx"
+version = "0.40.14"
+description = "OpenTelemetry IBM Watsonx Instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_watsonx-0.40.14-py3-none-any.whl", hash = "sha256:119f0fc0e5a4dddac31a0ea9cfd7ea41398814923b3018836780fc4e46f930d1"},
+ {file = "opentelemetry_instrumentation_watsonx-0.40.14.tar.gz", hash = "sha256:e131f498b764fc76c1f433377b9ef554b12de604f2f6b8dd72e0440226034da7"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-instrumentation-weaviate"
+version = "0.40.14"
+description = "OpenTelemetry Weaviate instrumentation"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_instrumentation_weaviate-0.40.14-py3-none-any.whl", hash = "sha256:4ab8f786eb78394be37aed0df96ceefa46072d48f0aee7e9f8ad3526e04e23fd"},
+ {file = "opentelemetry_instrumentation_weaviate-0.40.14.tar.gz", hash = "sha256:539c62d542bcb2bf5e39a2939403397b1e898c852d5e343a3f348a9c33bfa7f5"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation = ">=0.50b0"
+opentelemetry-semantic-conventions = ">=0.50b0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+
+[[package]]
+name = "opentelemetry-proto"
+version = "1.34.1"
+description = "OpenTelemetry Python Proto"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_proto-1.34.1-py3-none-any.whl", hash = "sha256:eb4bb5ac27f2562df2d6857fc557b3a481b5e298bc04f94cc68041f00cebcbd2"},
+ {file = "opentelemetry_proto-1.34.1.tar.gz", hash = "sha256:16286214e405c211fc774187f3e4bbb1351290b8dfb88e8948af209ce85b719e"},
+]
+
+[package.dependencies]
+protobuf = ">=5.0,<6.0"
+
+[[package]]
+name = "opentelemetry-sdk"
+version = "1.34.1"
+description = "OpenTelemetry Python SDK"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_sdk-1.34.1-py3-none-any.whl", hash = "sha256:308effad4059562f1d92163c61c8141df649da24ce361827812c40abb2a1e96e"},
+ {file = "opentelemetry_sdk-1.34.1.tar.gz", hash = "sha256:8091db0d763fcd6098d4781bbc80ff0971f94e260739aa6afe6fd379cdf3aa4d"},
+]
+
+[package.dependencies]
+opentelemetry-api = "1.34.1"
+opentelemetry-semantic-conventions = "0.55b1"
+typing-extensions = ">=4.5.0"
+
+[[package]]
+name = "opentelemetry-semantic-conventions"
+version = "0.55b1"
+description = "OpenTelemetry Semantic Conventions"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_semantic_conventions-0.55b1-py3-none-any.whl", hash = "sha256:5da81dfdf7d52e3d37f8fe88d5e771e191de924cfff5f550ab0b8f7b2409baed"},
+ {file = "opentelemetry_semantic_conventions-0.55b1.tar.gz", hash = "sha256:ef95b1f009159c28d7a7849f5cbc71c4c34c845bb514d66adfdf1b3fff3598b3"},
+]
+
+[package.dependencies]
+opentelemetry-api = "1.34.1"
+typing-extensions = ">=4.5.0"
+
+[[package]]
+name = "opentelemetry-semantic-conventions-ai"
+version = "0.4.9"
+description = "OpenTelemetry Semantic Conventions Extension for Large Language Models"
+optional = false
+python-versions = "<4,>=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_semantic_conventions_ai-0.4.9-py3-none-any.whl", hash = "sha256:71149e46a72554ae17de46bca6c11ba540c19c89904bd4cc3111aac6edf10315"},
+ {file = "opentelemetry_semantic_conventions_ai-0.4.9.tar.gz", hash = "sha256:54a0b901959e2de5124384925846bac2ea0a6dab3de7e501ba6aecf5e293fe04"},
+]
+
+[[package]]
+name = "opentelemetry-util-http"
+version = "0.55b1"
+description = "Web util for OpenTelemetry"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "opentelemetry_util_http-0.55b1-py3-none-any.whl", hash = "sha256:e134218df8ff010e111466650e5f019496b29c3b4f1b7de0e8ff8ebeafeebdf4"},
+ {file = "opentelemetry_util_http-0.55b1.tar.gz", hash = "sha256:29e119c1f6796cccf5fc2aedb55274435cde5976d0ac3fec3ca20a80118f821e"},
+]
+
+[[package]]
+name = "orjson"
+version = "3.10.18"
+description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "orjson-3.10.18-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a45e5d68066b408e4bc383b6e4ef05e717c65219a9e1390abc6155a520cac402"},
+ {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be3b9b143e8b9db05368b13b04c84d37544ec85bb97237b3a923f076265ec89c"},
+ {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9b0aa09745e2c9b3bf779b096fa71d1cc2d801a604ef6dd79c8b1bfef52b2f92"},
+ {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53a245c104d2792e65c8d225158f2b8262749ffe64bc7755b00024757d957a13"},
+ {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9495ab2611b7f8a0a8a505bcb0f0cbdb5469caafe17b0e404c3c746f9900469"},
+ {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:73be1cbcebadeabdbc468f82b087df435843c809cd079a565fb16f0f3b23238f"},
+ {file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe8936ee2679e38903df158037a2f1c108129dee218975122e37847fb1d4ac68"},
+ {file = "orjson-3.10.18-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7115fcbc8525c74e4c2b608129bef740198e9a120ae46184dac7683191042056"},
+ {file = "orjson-3.10.18-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:771474ad34c66bc4d1c01f645f150048030694ea5b2709b87d3bda273ffe505d"},
+ {file = "orjson-3.10.18-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7c14047dbbea52886dd87169f21939af5d55143dad22d10db6a7514f058156a8"},
+ {file = "orjson-3.10.18-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:641481b73baec8db14fdf58f8967e52dc8bda1f2aba3aa5f5c1b07ed6df50b7f"},
+ {file = "orjson-3.10.18-cp310-cp310-win32.whl", hash = "sha256:607eb3ae0909d47280c1fc657c4284c34b785bae371d007595633f4b1a2bbe06"},
+ {file = "orjson-3.10.18-cp310-cp310-win_amd64.whl", hash = "sha256:8770432524ce0eca50b7efc2a9a5f486ee0113a5fbb4231526d414e6254eba92"},
+ {file = "orjson-3.10.18-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e0a183ac3b8e40471e8d843105da6fbe7c070faab023be3b08188ee3f85719b8"},
+ {file = "orjson-3.10.18-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:5ef7c164d9174362f85238d0cd4afdeeb89d9e523e4651add6a5d458d6f7d42d"},
+ {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afd14c5d99cdc7bf93f22b12ec3b294931518aa019e2a147e8aa2f31fd3240f7"},
+ {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7b672502323b6cd133c4af6b79e3bea36bad2d16bca6c1f645903fce83909a7a"},
+ {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:51f8c63be6e070ec894c629186b1c0fe798662b8687f3d9fdfa5e401c6bd7679"},
+ {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f9478ade5313d724e0495d167083c6f3be0dd2f1c9c8a38db9a9e912cdaf947"},
+ {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:187aefa562300a9d382b4b4eb9694806e5848b0cedf52037bb5c228c61bb66d4"},
+ {file = "orjson-3.10.18-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da552683bc9da222379c7a01779bddd0ad39dd699dd6300abaf43eadee38334"},
+ {file = "orjson-3.10.18-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e450885f7b47a0231979d9c49b567ed1c4e9f69240804621be87c40bc9d3cf17"},
+ {file = "orjson-3.10.18-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5e3c9cc2ba324187cd06287ca24f65528f16dfc80add48dc99fa6c836bb3137e"},
+ {file = "orjson-3.10.18-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:50ce016233ac4bfd843ac5471e232b865271d7d9d44cf9d33773bcd883ce442b"},
+ {file = "orjson-3.10.18-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b3ceff74a8f7ffde0b2785ca749fc4e80e4315c0fd887561144059fb1c138aa7"},
+ {file = "orjson-3.10.18-cp311-cp311-win32.whl", hash = "sha256:fdba703c722bd868c04702cac4cb8c6b8ff137af2623bc0ddb3b3e6a2c8996c1"},
+ {file = "orjson-3.10.18-cp311-cp311-win_amd64.whl", hash = "sha256:c28082933c71ff4bc6ccc82a454a2bffcef6e1d7379756ca567c772e4fb3278a"},
+ {file = "orjson-3.10.18-cp311-cp311-win_arm64.whl", hash = "sha256:a6c7c391beaedd3fa63206e5c2b7b554196f14debf1ec9deb54b5d279b1b46f5"},
+ {file = "orjson-3.10.18-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:50c15557afb7f6d63bc6d6348e0337a880a04eaa9cd7c9d569bcb4e760a24753"},
+ {file = "orjson-3.10.18-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:356b076f1662c9813d5fa56db7d63ccceef4c271b1fb3dd522aca291375fcf17"},
+ {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:559eb40a70a7494cd5beab2d73657262a74a2c59aff2068fdba8f0424ec5b39d"},
+ {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f3c29eb9a81e2fbc6fd7ddcfba3e101ba92eaff455b8d602bf7511088bbc0eae"},
+ {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6612787e5b0756a171c7d81ba245ef63a3533a637c335aa7fcb8e665f4a0966f"},
+ {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ac6bd7be0dcab5b702c9d43d25e70eb456dfd2e119d512447468f6405b4a69c"},
+ {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9f72f100cee8dde70100406d5c1abba515a7df926d4ed81e20a9730c062fe9ad"},
+ {file = "orjson-3.10.18-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9dca85398d6d093dd41dc0983cbf54ab8e6afd1c547b6b8a311643917fbf4e0c"},
+ {file = "orjson-3.10.18-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:22748de2a07fcc8781a70edb887abf801bb6142e6236123ff93d12d92db3d406"},
+ {file = "orjson-3.10.18-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:3a83c9954a4107b9acd10291b7f12a6b29e35e8d43a414799906ea10e75438e6"},
+ {file = "orjson-3.10.18-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:303565c67a6c7b1f194c94632a4a39918e067bd6176a48bec697393865ce4f06"},
+ {file = "orjson-3.10.18-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:86314fdb5053a2f5a5d881f03fca0219bfdf832912aa88d18676a5175c6916b5"},
+ {file = "orjson-3.10.18-cp312-cp312-win32.whl", hash = "sha256:187ec33bbec58c76dbd4066340067d9ece6e10067bb0cc074a21ae3300caa84e"},
+ {file = "orjson-3.10.18-cp312-cp312-win_amd64.whl", hash = "sha256:f9f94cf6d3f9cd720d641f8399e390e7411487e493962213390d1ae45c7814fc"},
+ {file = "orjson-3.10.18-cp312-cp312-win_arm64.whl", hash = "sha256:3d600be83fe4514944500fa8c2a0a77099025ec6482e8087d7659e891f23058a"},
+ {file = "orjson-3.10.18-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:69c34b9441b863175cc6a01f2935de994025e773f814412030f269da4f7be147"},
+ {file = "orjson-3.10.18-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:1ebeda919725f9dbdb269f59bc94f861afbe2a27dce5608cdba2d92772364d1c"},
+ {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5adf5f4eed520a4959d29ea80192fa626ab9a20b2ea13f8f6dc58644f6927103"},
+ {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7592bb48a214e18cd670974f289520f12b7aed1fa0b2e2616b8ed9e069e08595"},
+ {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f872bef9f042734110642b7a11937440797ace8c87527de25e0c53558b579ccc"},
+ {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0315317601149c244cb3ecef246ef5861a64824ccbcb8018d32c66a60a84ffbc"},
+ {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0da26957e77e9e55a6c2ce2e7182a36a6f6b180ab7189315cb0995ec362e049"},
+ {file = "orjson-3.10.18-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb70d489bc79b7519e5803e2cc4c72343c9dc1154258adf2f8925d0b60da7c58"},
+ {file = "orjson-3.10.18-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e9e86a6af31b92299b00736c89caf63816f70a4001e750bda179e15564d7a034"},
+ {file = "orjson-3.10.18-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:c382a5c0b5931a5fc5405053d36c1ce3fd561694738626c77ae0b1dfc0242ca1"},
+ {file = "orjson-3.10.18-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8e4b2ae732431127171b875cb2668f883e1234711d3c147ffd69fe5be51a8012"},
+ {file = "orjson-3.10.18-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2d808e34ddb24fc29a4d4041dcfafbae13e129c93509b847b14432717d94b44f"},
+ {file = "orjson-3.10.18-cp313-cp313-win32.whl", hash = "sha256:ad8eacbb5d904d5591f27dee4031e2c1db43d559edb8f91778efd642d70e6bea"},
+ {file = "orjson-3.10.18-cp313-cp313-win_amd64.whl", hash = "sha256:aed411bcb68bf62e85588f2a7e03a6082cc42e5a2796e06e72a962d7c6310b52"},
+ {file = "orjson-3.10.18-cp313-cp313-win_arm64.whl", hash = "sha256:f54c1385a0e6aba2f15a40d703b858bedad36ded0491e55d35d905b2c34a4cc3"},
+ {file = "orjson-3.10.18-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:c95fae14225edfd699454e84f61c3dd938df6629a00c6ce15e704f57b58433bb"},
+ {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5232d85f177f98e0cefabb48b5e7f60cff6f3f0365f9c60631fecd73849b2a82"},
+ {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2783e121cafedf0d85c148c248a20470018b4ffd34494a68e125e7d5857655d1"},
+ {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e54ee3722caf3db09c91f442441e78f916046aa58d16b93af8a91500b7bbf273"},
+ {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2daf7e5379b61380808c24f6fc182b7719301739e4271c3ec88f2984a2d61f89"},
+ {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7f39b371af3add20b25338f4b29a8d6e79a8c7ed0e9dd49e008228a065d07781"},
+ {file = "orjson-3.10.18-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b819ed34c01d88c6bec290e6842966f8e9ff84b7694632e88341363440d4cc0"},
+ {file = "orjson-3.10.18-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2f6c57debaef0b1aa13092822cbd3698a1fb0209a9ea013a969f4efa36bdea57"},
+ {file = "orjson-3.10.18-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:755b6d61ffdb1ffa1e768330190132e21343757c9aa2308c67257cc81a1a6f5a"},
+ {file = "orjson-3.10.18-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ce8d0a875a85b4c8579eab5ac535fb4b2a50937267482be402627ca7e7570ee3"},
+ {file = "orjson-3.10.18-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:57b5d0673cbd26781bebc2bf86f99dd19bd5a9cb55f71cc4f66419f6b50f3d77"},
+ {file = "orjson-3.10.18-cp39-cp39-win32.whl", hash = "sha256:951775d8b49d1d16ca8818b1f20c4965cae9157e7b562a2ae34d3967b8f21c8e"},
+ {file = "orjson-3.10.18-cp39-cp39-win_amd64.whl", hash = "sha256:fdd9d68f83f0bc4406610b1ac68bdcded8c5ee58605cc69e643a06f4d075f429"},
+ {file = "orjson-3.10.18.tar.gz", hash = "sha256:e8da3947d92123eda795b68228cafe2724815621fe35e8e320a9e9593a4bcd53"},
+]
+
+[[package]]
+name = "ormsgpack"
+version = "1.10.0"
+description = "Fast, correct Python msgpack library supporting dataclasses, datetimes, and numpy"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "ormsgpack-1.10.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8a52c7ce7659459f3dc8dec9fd6a6c76f855a0a7e2b61f26090982ac10b95216"},
+ {file = "ormsgpack-1.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:060f67fe927582f4f63a1260726d019204b72f460cf20930e6c925a1d129f373"},
+ {file = "ormsgpack-1.10.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7058ef6092f995561bf9f71d6c9a4da867b6cc69d2e94cb80184f579a3ceed5"},
+ {file = "ormsgpack-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f6f3509c1b0e51b15552d314b1d409321718122e90653122ce4b997f01453a"},
+ {file = "ormsgpack-1.10.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:51c1edafd5c72b863b1f875ec31c529f09c872a5ff6fe473b9dfaf188ccc3227"},
+ {file = "ormsgpack-1.10.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c780b44107a547a9e9327270f802fa4d6b0f6667c9c03c3338c0ce812259a0f7"},
+ {file = "ormsgpack-1.10.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:137aab0d5cdb6df702da950a80405eb2b7038509585e32b4e16289604ac7cb84"},
+ {file = "ormsgpack-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:3e666cb63030538fa5cd74b1e40cb55b6fdb6e2981f024997a288bf138ebad07"},
+ {file = "ormsgpack-1.10.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:4bb7df307e17b36cbf7959cd642c47a7f2046ae19408c564e437f0ec323a7775"},
+ {file = "ormsgpack-1.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8817ae439c671779e1127ee62f0ac67afdeaeeacb5f0db45703168aa74a2e4af"},
+ {file = "ormsgpack-1.10.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f345f81e852035d80232e64374d3a104139d60f8f43c6c5eade35c4bac5590e"},
+ {file = "ormsgpack-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21de648a1c7ef692bdd287fb08f047bd5371d7462504c0a7ae1553c39fee35e3"},
+ {file = "ormsgpack-1.10.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3a7d844ae9cbf2112c16086dd931b2acefce14cefd163c57db161170c2bfa22b"},
+ {file = "ormsgpack-1.10.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e4d80585403d86d7f800cf3d0aafac1189b403941e84e90dd5102bb2b92bf9d5"},
+ {file = "ormsgpack-1.10.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:da1de515a87e339e78a3ccf60e39f5fb740edac3e9e82d3c3d209e217a13ac08"},
+ {file = "ormsgpack-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:57c4601812684024132cbb32c17a7d4bb46ffc7daf2fddf5b697391c2c4f142a"},
+ {file = "ormsgpack-1.10.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:4e159d50cd4064d7540e2bc6a0ab66eab70b0cc40c618b485324ee17037527c0"},
+ {file = "ormsgpack-1.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eeb47c85f3a866e29279d801115b554af0fefc409e2ed8aa90aabfa77efe5cc6"},
+ {file = "ormsgpack-1.10.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c28249574934534c9bd5dce5485c52f21bcea0ee44d13ece3def6e3d2c3798b5"},
+ {file = "ormsgpack-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1957dcadbb16e6a981cd3f9caef9faf4c2df1125e2a1b702ee8236a55837ce07"},
+ {file = "ormsgpack-1.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3b29412558c740bf6bac156727aa85ac67f9952cd6f071318f29ee72e1a76044"},
+ {file = "ormsgpack-1.10.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6933f350c2041ec189fe739f0ba7d6117c8772f5bc81f45b97697a84d03020dd"},
+ {file = "ormsgpack-1.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a86de06d368fcc2e58b79dece527dc8ca831e0e8b9cec5d6e633d2777ec93d0"},
+ {file = "ormsgpack-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:35fa9f81e5b9a0dab42e09a73f7339ecffdb978d6dbf9deb2ecf1e9fc7808722"},
+ {file = "ormsgpack-1.10.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8d816d45175a878993b7372bd5408e0f3ec5a40f48e2d5b9d8f1cc5d31b61f1f"},
+ {file = "ormsgpack-1.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90345ccb058de0f35262893751c603b6376b05f02be2b6f6b7e05d9dd6d5643"},
+ {file = "ormsgpack-1.10.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:144b5e88f1999433e54db9d637bae6fe21e935888be4e3ac3daecd8260bd454e"},
+ {file = "ormsgpack-1.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2190b352509d012915921cca76267db136cd026ddee42f1b0d9624613cc7058c"},
+ {file = "ormsgpack-1.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:86fd9c1737eaba43d3bb2730add9c9e8b5fbed85282433705dd1b1e88ea7e6fb"},
+ {file = "ormsgpack-1.10.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:33afe143a7b61ad21bb60109a86bb4e87fec70ef35db76b89c65b17e32da7935"},
+ {file = "ormsgpack-1.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f23d45080846a7b90feabec0d330a9cc1863dc956728412e4f7986c80ab3a668"},
+ {file = "ormsgpack-1.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:534d18acb805c75e5fba09598bf40abe1851c853247e61dda0c01f772234da69"},
+ {file = "ormsgpack-1.10.0-cp39-cp39-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:efdb25cf6d54085f7ae557268d59fd2d956f1a09a340856e282d2960fe929f32"},
+ {file = "ormsgpack-1.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddfcb30d4b1be2439836249d675f297947f4fb8efcd3eeb6fd83021d773cadc4"},
+ {file = "ormsgpack-1.10.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee0944b6ccfd880beb1ca29f9442a774683c366f17f4207f8b81c5e24cadb453"},
+ {file = "ormsgpack-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35cdff6a0d3ba04e40a751129763c3b9b57a602c02944138e4b760ec99ae80a1"},
+ {file = "ormsgpack-1.10.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:599ccdabc19c618ef5de6e6f2e7f5d48c1f531a625fa6772313b8515bc710681"},
+ {file = "ormsgpack-1.10.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:bf46f57da9364bd5eefd92365c1b78797f56c6f780581eecd60cd7b367f9b4d3"},
+ {file = "ormsgpack-1.10.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b796f64fdf823dedb1e35436a4a6f889cf78b1aa42d3097c66e5adfd8c3bd72d"},
+ {file = "ormsgpack-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:106253ac9dc08520951e556b3c270220fcb8b4fef0d30b71eedac4befa4de749"},
+ {file = "ormsgpack-1.10.0.tar.gz", hash = "sha256:7f7a27efd67ef22d7182ec3b7fa7e9d147c3ad9be2a24656b23c989077e08b16"},
+]
+
+[[package]]
+name = "packaging"
+version = "24.2"
+description = "Core utilities for Python packages"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"},
+ {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"},
+]
+
+[[package]]
+name = "pinecone"
+version = "7.3.0"
+description = "Pinecone client and SDK"
+optional = false
+python-versions = "<4.0,>=3.9"
+groups = ["main"]
+files = [
+ {file = "pinecone-7.3.0-py3-none-any.whl", hash = "sha256:315b8fef20320bef723ecbb695dec0aafa75d8434d86e01e5a0e85933e1009a8"},
+ {file = "pinecone-7.3.0.tar.gz", hash = "sha256:307edc155621d487c20dc71b76c3ad5d6f799569ba42064190d03917954f9a7b"},
+]
+
+[package.dependencies]
+aiohttp = {version = ">=3.9.0", optional = true, markers = "extra == \"asyncio\""}
+aiohttp-retry = {version = ">=2.9.1,<3.0.0", optional = true, markers = "extra == \"asyncio\""}
+certifi = ">=2019.11.17"
+pinecone-plugin-assistant = ">=1.6.0,<2.0.0"
+pinecone-plugin-interface = ">=0.0.7,<0.0.8"
+python-dateutil = ">=2.5.3"
+typing-extensions = ">=3.7.4"
+urllib3 = [
+ {version = ">=1.26.0", markers = "python_version >= \"3.8\" and python_version < \"3.12\""},
+ {version = ">=1.26.5", markers = "python_version >= \"3.12\" and python_version < \"4.0\""},
+]
+
+[package.extras]
+asyncio = ["aiohttp (>=3.9.0)", "aiohttp-retry (>=2.9.1,<3.0.0)"]
+grpc = ["googleapis-common-protos (>=1.66.0)", "grpcio (>=1.44.0) ; python_version >= \"3.8\" and python_version < \"3.11\"", "grpcio (>=1.59.0) ; python_version >= \"3.11\" and python_version < \"4.0\"", "grpcio (>=1.68.0) ; python_version >= \"3.13\" and python_version < \"4.0\"", "lz4 (>=3.1.3)", "protobuf (>=5.29,<6.0)", "protoc-gen-openapiv2 (>=0.0.1,<0.0.2)"]
+
+[[package]]
+name = "pinecone-plugin-assistant"
+version = "1.7.0"
+description = "Assistant plugin for Pinecone SDK"
+optional = false
+python-versions = "<4.0,>=3.9"
+groups = ["main"]
+files = [
+ {file = "pinecone_plugin_assistant-1.7.0-py3-none-any.whl", hash = "sha256:864cb8e7930588e6c2da97c6d44f0240969195f43fa303c5db76cbc12bf903a5"},
+ {file = "pinecone_plugin_assistant-1.7.0.tar.gz", hash = "sha256:e26e3ba10a8b71c3da0d777cff407668022e82963c4913d0ffeb6c552721e482"},
+]
+
+[package.dependencies]
+packaging = ">=24.2,<25.0"
+requests = ">=2.32.3,<3.0.0"
+
+[[package]]
+name = "pinecone-plugin-interface"
+version = "0.0.7"
+description = "Plugin interface for the Pinecone python client"
+optional = false
+python-versions = "<4.0,>=3.8"
+groups = ["main"]
+files = [
+ {file = "pinecone_plugin_interface-0.0.7-py3-none-any.whl", hash = "sha256:875857ad9c9fc8bbc074dbe780d187a2afd21f5bfe0f3b08601924a61ef1bba8"},
+ {file = "pinecone_plugin_interface-0.0.7.tar.gz", hash = "sha256:b8e6675e41847333aa13923cc44daa3f85676d7157324682dc1640588a982846"},
+]
+
+[[package]]
+name = "pluggy"
+version = "1.6.0"
+description = "plugin and hook calling mechanisms for python"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"},
+ {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"},
+]
+
+[package.extras]
+dev = ["pre-commit", "tox"]
+testing = ["coverage", "pytest", "pytest-benchmark"]
+
+[[package]]
+name = "posthog"
+version = "3.25.0"
+description = "Integrate PostHog into any python application."
+optional = false
+python-versions = "*"
+groups = ["main"]
+files = [
+ {file = "posthog-3.25.0-py2.py3-none-any.whl", hash = "sha256:85db78c13d1ecb11aed06fad53759c4e8fb3633442c2f3d0336bc0ce8a585d30"},
+ {file = "posthog-3.25.0.tar.gz", hash = "sha256:9168f3e7a0a5571b6b1065c41b3c171fbc68bfe72c3ac0bfd6e3d2fcdb7df2ca"},
+]
+
+[package.dependencies]
+backoff = ">=1.10.0"
+distro = ">=1.5.0"
+monotonic = ">=1.5"
+python-dateutil = ">2.1"
+requests = ">=2.7,<3.0"
+six = ">=1.5"
+
+[package.extras]
+dev = ["black", "django-stubs", "flake8", "flake8-print", "isort", "lxml", "mypy", "mypy-baseline", "pre-commit", "pydantic", "types-mock", "types-python-dateutil", "types-requests", "types-setuptools", "types-six"]
+langchain = ["langchain (>=0.2.0)"]
+sentry = ["django", "sentry-sdk"]
+test = ["anthropic", "coverage", "django", "flake8", "freezegun (==1.5.1)", "langchain-anthropic (>=0.2.0)", "langchain-community (>=0.2.0)", "langchain-openai (>=0.2.0)", "langgraph", "mock (>=2.0.0)", "openai", "parameterized (>=0.8.1)", "pydantic", "pylint", "pytest", "pytest-asyncio", "pytest-timeout"]
+
+[[package]]
+name = "propcache"
+version = "0.3.2"
+description = "Accelerated property cache"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770"},
+ {file = "propcache-0.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d0fda578d1dc3f77b6b5a5dce3b9ad69a8250a891760a548df850a5e8da87f3"},
+ {file = "propcache-0.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3def3da3ac3ce41562d85db655d18ebac740cb3fa4367f11a52b3da9d03a5cc3"},
+ {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bec58347a5a6cebf239daba9bda37dffec5b8d2ce004d9fe4edef3d2815137e"},
+ {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55ffda449a507e9fbd4aca1a7d9aa6753b07d6166140e5a18d2ac9bc49eac220"},
+ {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a67fb39229a8a8491dd42f864e5e263155e729c2e7ff723d6e25f596b1e8cb"},
+ {file = "propcache-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da1cf97b92b51253d5b68cf5a2b9e0dafca095e36b7f2da335e27dc6172a614"},
+ {file = "propcache-0.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f559e127134b07425134b4065be45b166183fdcb433cb6c24c8e4149056ad50"},
+ {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aff2e4e06435d61f11a428360a932138d0ec288b0a31dd9bd78d200bd4a2b339"},
+ {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4927842833830942a5d0a56e6f4839bc484785b8e1ce8d287359794818633ba0"},
+ {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6107ddd08b02654a30fb8ad7a132021759d750a82578b94cd55ee2772b6ebea2"},
+ {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:70bd8b9cd6b519e12859c99f3fc9a93f375ebd22a50296c3a295028bea73b9e7"},
+ {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2183111651d710d3097338dd1893fcf09c9f54e27ff1a8795495a16a469cc90b"},
+ {file = "propcache-0.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fb075ad271405dcad8e2a7ffc9a750a3bf70e533bd86e89f0603e607b93aa64c"},
+ {file = "propcache-0.3.2-cp310-cp310-win32.whl", hash = "sha256:404d70768080d3d3bdb41d0771037da19d8340d50b08e104ca0e7f9ce55fce70"},
+ {file = "propcache-0.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:7435d766f978b4ede777002e6b3b6641dd229cd1da8d3d3106a45770365f9ad9"},
+ {file = "propcache-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0b8d2f607bd8f80ddc04088bc2a037fdd17884a6fcadc47a96e334d72f3717be"},
+ {file = "propcache-0.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06766d8f34733416e2e34f46fea488ad5d60726bb9481d3cddf89a6fa2d9603f"},
+ {file = "propcache-0.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2dc1f4a1df4fecf4e6f68013575ff4af84ef6f478fe5344317a65d38a8e6dc9"},
+ {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be29c4f4810c5789cf10ddf6af80b041c724e629fa51e308a7a0fb19ed1ef7bf"},
+ {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59d61f6970ecbd8ff2e9360304d5c8876a6abd4530cb752c06586849ac8a9dc9"},
+ {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62180e0b8dbb6b004baec00a7983e4cc52f5ada9cd11f48c3528d8cfa7b96a66"},
+ {file = "propcache-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c144ca294a204c470f18cf4c9d78887810d04a3e2fbb30eea903575a779159df"},
+ {file = "propcache-0.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5c2a784234c28854878d68978265617aa6dc0780e53d44b4d67f3651a17a9a2"},
+ {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5745bc7acdafa978ca1642891b82c19238eadc78ba2aaa293c6863b304e552d7"},
+ {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c0075bf773d66fa8c9d41f66cc132ecc75e5bb9dd7cce3cfd14adc5ca184cb95"},
+ {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5f57aa0847730daceff0497f417c9de353c575d8da3579162cc74ac294c5369e"},
+ {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:eef914c014bf72d18efb55619447e0aecd5fb7c2e3fa7441e2e5d6099bddff7e"},
+ {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2a4092e8549031e82facf3decdbc0883755d5bbcc62d3aea9d9e185549936dcf"},
+ {file = "propcache-0.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:85871b050f174bc0bfb437efbdb68aaf860611953ed12418e4361bc9c392749e"},
+ {file = "propcache-0.3.2-cp311-cp311-win32.whl", hash = "sha256:36c8d9b673ec57900c3554264e630d45980fd302458e4ac801802a7fd2ef7897"},
+ {file = "propcache-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53af8cb6a781b02d2ea079b5b853ba9430fcbe18a8e3ce647d5982a3ff69f39"},
+ {file = "propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10"},
+ {file = "propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154"},
+ {file = "propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615"},
+ {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db"},
+ {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1"},
+ {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c"},
+ {file = "propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67"},
+ {file = "propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b"},
+ {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8"},
+ {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251"},
+ {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474"},
+ {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535"},
+ {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06"},
+ {file = "propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1"},
+ {file = "propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1"},
+ {file = "propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c"},
+ {file = "propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945"},
+ {file = "propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252"},
+ {file = "propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f"},
+ {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33"},
+ {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e"},
+ {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1"},
+ {file = "propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3"},
+ {file = "propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1"},
+ {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6"},
+ {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387"},
+ {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4"},
+ {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88"},
+ {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206"},
+ {file = "propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43"},
+ {file = "propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02"},
+ {file = "propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05"},
+ {file = "propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b"},
+ {file = "propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0"},
+ {file = "propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e"},
+ {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28"},
+ {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a"},
+ {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c"},
+ {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725"},
+ {file = "propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892"},
+ {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44"},
+ {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe"},
+ {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81"},
+ {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba"},
+ {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770"},
+ {file = "propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330"},
+ {file = "propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394"},
+ {file = "propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198"},
+ {file = "propcache-0.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:a7fad897f14d92086d6b03fdd2eb844777b0c4d7ec5e3bac0fbae2ab0602bbe5"},
+ {file = "propcache-0.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1f43837d4ca000243fd7fd6301947d7cb93360d03cd08369969450cc6b2ce3b4"},
+ {file = "propcache-0.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:261df2e9474a5949c46e962065d88eb9b96ce0f2bd30e9d3136bcde84befd8f2"},
+ {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e514326b79e51f0a177daab1052bc164d9d9e54133797a3a58d24c9c87a3fe6d"},
+ {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d4a996adb6904f85894570301939afeee65f072b4fd265ed7e569e8d9058e4ec"},
+ {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:76cace5d6b2a54e55b137669b30f31aa15977eeed390c7cbfb1dafa8dfe9a701"},
+ {file = "propcache-0.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31248e44b81d59d6addbb182c4720f90b44e1efdc19f58112a3c3a1615fb47ef"},
+ {file = "propcache-0.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abb7fa19dbf88d3857363e0493b999b8011eea856b846305d8c0512dfdf8fbb1"},
+ {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d81ac3ae39d38588ad0549e321e6f773a4e7cc68e7751524a22885d5bbadf886"},
+ {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:cc2782eb0f7a16462285b6f8394bbbd0e1ee5f928034e941ffc444012224171b"},
+ {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:db429c19a6c7e8a1c320e6a13c99799450f411b02251fb1b75e6217cf4a14fcb"},
+ {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:21d8759141a9e00a681d35a1f160892a36fb6caa715ba0b832f7747da48fb6ea"},
+ {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2ca6d378f09adb13837614ad2754fa8afaee330254f404299611bce41a8438cb"},
+ {file = "propcache-0.3.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:34a624af06c048946709f4278b4176470073deda88d91342665d95f7c6270fbe"},
+ {file = "propcache-0.3.2-cp39-cp39-win32.whl", hash = "sha256:4ba3fef1c30f306b1c274ce0b8baaa2c3cdd91f645c48f06394068f37d3837a1"},
+ {file = "propcache-0.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:7a2368eed65fc69a7a7a40b27f22e85e7627b74216f0846b04ba5c116e191ec9"},
+ {file = "propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f"},
+ {file = "propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168"},
+]
+
+[[package]]
+name = "protobuf"
+version = "5.29.5"
+description = ""
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "protobuf-5.29.5-cp310-abi3-win32.whl", hash = "sha256:3f1c6468a2cfd102ff4703976138844f78ebd1fb45f49011afc5139e9e283079"},
+ {file = "protobuf-5.29.5-cp310-abi3-win_amd64.whl", hash = "sha256:3f76e3a3675b4a4d867b52e4a5f5b78a2ef9565549d4037e06cf7b0942b1d3fc"},
+ {file = "protobuf-5.29.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e38c5add5a311f2a6eb0340716ef9b039c1dfa428b28f25a7838ac329204a671"},
+ {file = "protobuf-5.29.5-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:fa18533a299d7ab6c55a238bf8629311439995f2e7eca5caaff08663606e9015"},
+ {file = "protobuf-5.29.5-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:63848923da3325e1bf7e9003d680ce6e14b07e55d0473253a690c3a8b8fd6e61"},
+ {file = "protobuf-5.29.5-cp38-cp38-win32.whl", hash = "sha256:ef91363ad4faba7b25d844ef1ada59ff1604184c0bcd8b39b8a6bef15e1af238"},
+ {file = "protobuf-5.29.5-cp38-cp38-win_amd64.whl", hash = "sha256:7318608d56b6402d2ea7704ff1e1e4597bee46d760e7e4dd42a3d45e24b87f2e"},
+ {file = "protobuf-5.29.5-cp39-cp39-win32.whl", hash = "sha256:6f642dc9a61782fa72b90878af134c5afe1917c89a568cd3476d758d3c3a0736"},
+ {file = "protobuf-5.29.5-cp39-cp39-win_amd64.whl", hash = "sha256:470f3af547ef17847a28e1f47200a1cbf0ba3ff57b7de50d22776607cd2ea353"},
+ {file = "protobuf-5.29.5-py3-none-any.whl", hash = "sha256:6cf42630262c59b2d8de33954443d94b746c952b01434fc58a417fdbd2e84bd5"},
+ {file = "protobuf-5.29.5.tar.gz", hash = "sha256:bc1463bafd4b0929216c35f437a8e28731a2b7fe3d98bb77a600efced5a15c84"},
+]
+
+[[package]]
+name = "py-cpuinfo"
+version = "9.0.0"
+description = "Get CPU info with pure Python"
+optional = false
+python-versions = "*"
+groups = ["main"]
+files = [
+ {file = "py-cpuinfo-9.0.0.tar.gz", hash = "sha256:3cdbbf3fac90dc6f118bfd64384f309edeadd902d7c8fb17f02ffa1fc3f49690"},
+ {file = "py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5"},
+]
+
+[[package]]
+name = "pycparser"
+version = "2.22"
+description = "C parser in Python"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
+ {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
+]
+
+[[package]]
+name = "pydantic"
+version = "2.11.7"
+description = "Data validation using Python type hints"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b"},
+ {file = "pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db"},
+]
+
+[package.dependencies]
+annotated-types = ">=0.6.0"
+pydantic-core = "2.33.2"
+typing-extensions = ">=4.12.2"
+typing-inspection = ">=0.4.0"
+
+[package.extras]
+email = ["email-validator (>=2.0.0)"]
+timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""]
+
+[[package]]
+name = "pydantic-core"
+version = "2.33.2"
+description = "Core functionality for Pydantic validation and serialization"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22"},
+ {file = "pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab"},
+ {file = "pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2"},
+ {file = "pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9"},
+ {file = "pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9"},
+ {file = "pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac"},
+ {file = "pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5"},
+ {file = "pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9"},
+ {file = "pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3"},
+ {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa"},
+ {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29"},
+ {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d"},
+ {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e"},
+ {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c"},
+ {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec"},
+ {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052"},
+ {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c"},
+ {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808"},
+ {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8"},
+ {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593"},
+ {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612"},
+ {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7"},
+ {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e"},
+ {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8"},
+ {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf"},
+ {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb"},
+ {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1"},
+ {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101"},
+ {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64"},
+ {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d"},
+ {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535"},
+ {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d"},
+ {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6"},
+ {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca"},
+ {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039"},
+ {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27"},
+ {file = "pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc"},
+]
+
+[package.dependencies]
+typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
+
+[[package]]
+name = "pydantic-settings"
+version = "2.10.1"
+description = "Settings management using Pydantic"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "pydantic_settings-2.10.1-py3-none-any.whl", hash = "sha256:a60952460b99cf661dc25c29c0ef171721f98bfcb52ef8d9ea4c943d7c8cc796"},
+ {file = "pydantic_settings-2.10.1.tar.gz", hash = "sha256:06f0062169818d0f5524420a360d632d5857b83cffd4d42fe29597807a1614ee"},
+]
+
+[package.dependencies]
+pydantic = ">=2.7.0"
+python-dotenv = ">=0.21.0"
+typing-inspection = ">=0.4.0"
+
+[package.extras]
+aws-secrets-manager = ["boto3 (>=1.35.0)", "boto3-stubs[secretsmanager]"]
+azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0)"]
+gcp-secret-manager = ["google-cloud-secret-manager (>=2.23.1)"]
+toml = ["tomli (>=2.0.1)"]
+yaml = ["pyyaml (>=6.0.1)"]
+
+[[package]]
+name = "pygments"
+version = "2.19.2"
+description = "Pygments is a syntax highlighting package written in Python."
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"},
+ {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"},
+]
+
+[package.extras]
+windows-terminal = ["colorama (>=0.4.6)"]
+
+[[package]]
+name = "pyjwt"
+version = "2.10.1"
+description = "JSON Web Token implementation in Python"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"},
+ {file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"},
+]
+
+[package.extras]
+crypto = ["cryptography (>=3.4.0)"]
+dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"]
+docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"]
+tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"]
+
+[[package]]
+name = "pyparsing"
+version = "3.2.3"
+description = "pyparsing module - Classes and methods to define and execute parsing grammars"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf"},
+ {file = "pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be"},
+]
+
+[package.extras]
+diagrams = ["jinja2", "railroad-diagrams"]
+
+[[package]]
+name = "pytest"
+version = "8.4.1"
+description = "pytest: simple powerful testing with Python"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7"},
+ {file = "pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c"},
+]
+
+[package.dependencies]
+colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""}
+iniconfig = ">=1"
+packaging = ">=20"
+pluggy = ">=1.5,<2"
+pygments = ">=2.7.2"
+
+[package.extras]
+dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"]
+
+[[package]]
+name = "pytest-asyncio"
+version = "0.26.0"
+description = "Pytest support for asyncio"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "pytest_asyncio-0.26.0-py3-none-any.whl", hash = "sha256:7b51ed894f4fbea1340262bdae5135797ebbe21d8638978e35d31c6d19f72fb0"},
+ {file = "pytest_asyncio-0.26.0.tar.gz", hash = "sha256:c4df2a697648241ff39e7f0e4a73050b03f123f760673956cf0d72a4990e312f"},
+]
+
+[package.dependencies]
+pytest = ">=8.2,<9"
+
+[package.extras]
+docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1)"]
+testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"]
+
+[[package]]
+name = "pytest-benchmark"
+version = "5.1.0"
+description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer."
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "pytest-benchmark-5.1.0.tar.gz", hash = "sha256:9ea661cdc292e8231f7cd4c10b0319e56a2118e2c09d9f50e1b3d150d2aca105"},
+ {file = "pytest_benchmark-5.1.0-py3-none-any.whl", hash = "sha256:922de2dfa3033c227c96da942d1878191afa135a29485fb942e85dff1c592c89"},
+]
+
+[package.dependencies]
+py-cpuinfo = "*"
+pytest = ">=8.1"
+
+[package.extras]
+aspect = ["aspectlib"]
+elasticsearch = ["elasticsearch"]
+histogram = ["pygal", "pygaljs", "setuptools"]
+
+[[package]]
+name = "pytest-codspeed"
+version = "3.2.0"
+description = "Pytest plugin to create CodSpeed benchmarks"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "pytest_codspeed-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c5165774424c7ab8db7e7acdb539763a0e5657996effefdf0664d7fd95158d34"},
+ {file = "pytest_codspeed-3.2.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9bd55f92d772592c04a55209950c50880413ae46876e66bd349ef157075ca26c"},
+ {file = "pytest_codspeed-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4cf6f56067538f4892baa8d7ab5ef4e45bb59033be1ef18759a2c7fc55b32035"},
+ {file = "pytest_codspeed-3.2.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:39a687b05c3d145642061b45ea78e47e12f13ce510104d1a2cda00eee0e36f58"},
+ {file = "pytest_codspeed-3.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46a1afaaa1ac4c2ca5b0700d31ac46d80a27612961d031067d73c6ccbd8d3c2b"},
+ {file = "pytest_codspeed-3.2.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c48ce3af3dfa78413ed3d69d1924043aa1519048dbff46edccf8f35a25dab3c2"},
+ {file = "pytest_codspeed-3.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:66692506d33453df48b36a84703448cb8b22953eea51f03fbb2eb758dc2bdc4f"},
+ {file = "pytest_codspeed-3.2.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:479774f80d0bdfafa16112700df4dbd31bf2a6757fac74795fd79c0a7b3c389b"},
+ {file = "pytest_codspeed-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:109f9f4dd1088019c3b3f887d003b7d65f98a7736ca1d457884f5aa293e8e81c"},
+ {file = "pytest_codspeed-3.2.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e2f69a03b52c9bb041aec1b8ee54b7b6c37a6d0a948786effa4c71157765b6da"},
+ {file = "pytest_codspeed-3.2.0-py3-none-any.whl", hash = "sha256:54b5c2e986d6a28e7b0af11d610ea57bd5531cec8326abe486f1b55b09d91c39"},
+ {file = "pytest_codspeed-3.2.0.tar.gz", hash = "sha256:f9d1b1a3b2c69cdc0490a1e8b1ced44bffbd0e8e21d81a7160cfdd923f6e8155"},
+]
+
+[package.dependencies]
+cffi = ">=1.17.1"
+pytest = ">=3.8"
+rich = ">=13.8.1"
+
+[package.extras]
+compat = ["pytest-benchmark (>=5.0.0,<5.1.0)", "pytest-xdist (>=3.6.1,<3.7.0)"]
+lint = ["mypy (>=1.11.2,<1.12.0)", "ruff (>=0.6.5,<0.7.0)"]
+test = ["pytest (>=7.0,<8.0)", "pytest-cov (>=4.0.0,<4.1.0)"]
+
+[[package]]
+name = "pytest-recording"
+version = "0.13.4"
+description = "A pytest plugin powered by VCR.py to record and replay HTTP traffic"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "pytest_recording-0.13.4-py3-none-any.whl", hash = "sha256:ad49a434b51b1c4f78e85b1e6b74fdcc2a0a581ca16e52c798c6ace971f7f439"},
+ {file = "pytest_recording-0.13.4.tar.gz", hash = "sha256:568d64b2a85992eec4ae0a419c855d5fd96782c5fb016784d86f18053792768c"},
+]
+
+[package.dependencies]
+pytest = ">=3.5.0"
+vcrpy = ">=2.0.1"
+
+[package.extras]
+dev = ["pytest-httpbin", "pytest-mock", "requests", "werkzeug (==3.1.3)"]
+tests = ["pytest-httpbin", "pytest-mock", "requests", "werkzeug (==3.1.3)"]
+
+[[package]]
+name = "pytest-socket"
+version = "0.7.0"
+description = "Pytest Plugin to disable socket calls during tests"
+optional = false
+python-versions = ">=3.8,<4.0"
+groups = ["main"]
+files = [
+ {file = "pytest_socket-0.7.0-py3-none-any.whl", hash = "sha256:7e0f4642177d55d317bbd58fc68c6bd9048d6eadb2d46a89307fa9221336ce45"},
+ {file = "pytest_socket-0.7.0.tar.gz", hash = "sha256:71ab048cbbcb085c15a4423b73b619a8b35d6a307f46f78ea46be51b1b7e11b3"},
+]
+
+[package.dependencies]
+pytest = ">=6.2.5"
+
+[[package]]
+name = "python-dateutil"
+version = "2.9.0.post0"
+description = "Extensions to the standard Python datetime module"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+groups = ["main"]
+files = [
+ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
+ {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
+]
+
+[package.dependencies]
+six = ">=1.5"
+
+[[package]]
+name = "python-dotenv"
+version = "1.1.1"
+description = "Read key-value pairs from a .env file and set them as environment variables"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc"},
+ {file = "python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab"},
+]
+
+[package.extras]
+cli = ["click (>=5.0)"]
+
+[[package]]
+name = "python-engineio"
+version = "4.12.2"
+description = "Engine.IO server and client for Python"
+optional = false
+python-versions = ">=3.6"
+groups = ["main"]
+files = [
+ {file = "python_engineio-4.12.2-py3-none-any.whl", hash = "sha256:8218ab66950e179dfec4b4bbb30aecf3f5d86f5e58e6fc1aa7fde2c698b2804f"},
+ {file = "python_engineio-4.12.2.tar.gz", hash = "sha256:e7e712ffe1be1f6a05ee5f951e72d434854a32fcfc7f6e4d9d3cae24ec70defa"},
+]
+
+[package.dependencies]
+simple-websocket = ">=0.10.0"
+
+[package.extras]
+asyncio-client = ["aiohttp (>=3.4)"]
+client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"]
+docs = ["sphinx"]
+
+[[package]]
+name = "python-multipart"
+version = "0.0.18"
+description = "A streaming multipart parser for Python"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "python_multipart-0.0.18-py3-none-any.whl", hash = "sha256:efe91480f485f6a361427a541db4796f9e1591afc0fb8e7a4ba06bfbc6708996"},
+ {file = "python_multipart-0.0.18.tar.gz", hash = "sha256:7a68db60c8bfb82e460637fa4750727b45af1d5e2ed215593f917f64694d34fe"},
+]
+
+[[package]]
+name = "python-socketio"
+version = "5.13.0"
+description = "Socket.IO server and client for Python"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "python_socketio-5.13.0-py3-none-any.whl", hash = "sha256:51f68d6499f2df8524668c24bcec13ba1414117cfb3a90115c559b601ab10caf"},
+ {file = "python_socketio-5.13.0.tar.gz", hash = "sha256:ac4e19a0302ae812e23b712ec8b6427ca0521f7c582d6abb096e36e24a263029"},
+]
+
+[package.dependencies]
+bidict = ">=0.21.0"
+python-engineio = ">=4.11.0"
+
+[package.extras]
+asyncio-client = ["aiohttp (>=3.4)"]
+client = ["requests (>=2.21.0)", "websocket-client (>=0.54.0)"]
+docs = ["sphinx"]
+
+[[package]]
+name = "pyyaml"
+version = "6.0.2"
+description = "YAML parser and emitter for Python"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"},
+ {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"},
+ {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"},
+ {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"},
+ {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"},
+ {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"},
+ {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"},
+ {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"},
+ {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"},
+ {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"},
+ {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"},
+ {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"},
+ {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"},
+ {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"},
+ {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"},
+ {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"},
+ {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"},
+ {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"},
+ {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"},
+ {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"},
+ {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"},
+ {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"},
+ {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"},
+ {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"},
+ {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"},
+ {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"},
+ {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"},
+ {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"},
+ {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"},
+ {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"},
+ {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"},
+ {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"},
+ {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"},
+ {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"},
+ {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"},
+ {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"},
+ {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"},
+ {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"},
+ {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"},
+ {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"},
+ {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"},
+ {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"},
+ {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"},
+ {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"},
+ {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"},
+ {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"},
+ {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"},
+ {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"},
+ {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"},
+ {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"},
+ {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"},
+ {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"},
+ {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"},
+]
+
+[[package]]
+name = "referencing"
+version = "0.36.2"
+description = "JSON Referencing + Python"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0"},
+ {file = "referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa"},
+]
+
+[package.dependencies]
+attrs = ">=22.2.0"
+rpds-py = ">=0.7.0"
+typing-extensions = {version = ">=4.4.0", markers = "python_version < \"3.13\""}
+
+[[package]]
+name = "regex"
+version = "2024.11.6"
+description = "Alternative regular expression module, to replace re."
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91"},
+ {file = "regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0"},
+ {file = "regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e"},
+ {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde"},
+ {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e"},
+ {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2"},
+ {file = "regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf"},
+ {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c"},
+ {file = "regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86"},
+ {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67"},
+ {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d"},
+ {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2"},
+ {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008"},
+ {file = "regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62"},
+ {file = "regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e"},
+ {file = "regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519"},
+ {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638"},
+ {file = "regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7"},
+ {file = "regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20"},
+ {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114"},
+ {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3"},
+ {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f"},
+ {file = "regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0"},
+ {file = "regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55"},
+ {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89"},
+ {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d"},
+ {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34"},
+ {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d"},
+ {file = "regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45"},
+ {file = "regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9"},
+ {file = "regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60"},
+ {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a"},
+ {file = "regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9"},
+ {file = "regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2"},
+ {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4"},
+ {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577"},
+ {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3"},
+ {file = "regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e"},
+ {file = "regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe"},
+ {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e"},
+ {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29"},
+ {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39"},
+ {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51"},
+ {file = "regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad"},
+ {file = "regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54"},
+ {file = "regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b"},
+ {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84"},
+ {file = "regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4"},
+ {file = "regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0"},
+ {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0"},
+ {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7"},
+ {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7"},
+ {file = "regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c"},
+ {file = "regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3"},
+ {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07"},
+ {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e"},
+ {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6"},
+ {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4"},
+ {file = "regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d"},
+ {file = "regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff"},
+ {file = "regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a"},
+ {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:3a51ccc315653ba012774efca4f23d1d2a8a8f278a6072e29c7147eee7da446b"},
+ {file = "regex-2024.11.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ad182d02e40de7459b73155deb8996bbd8e96852267879396fb274e8700190e3"},
+ {file = "regex-2024.11.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba9b72e5643641b7d41fa1f6d5abda2c9a263ae835b917348fc3c928182ad467"},
+ {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40291b1b89ca6ad8d3f2b82782cc33807f1406cf68c8d440861da6304d8ffbbd"},
+ {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cdf58d0e516ee426a48f7b2c03a332a4114420716d55769ff7108c37a09951bf"},
+ {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a36fdf2af13c2b14738f6e973aba563623cb77d753bbbd8d414d18bfaa3105dd"},
+ {file = "regex-2024.11.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1cee317bfc014c2419a76bcc87f071405e3966da434e03e13beb45f8aced1a6"},
+ {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50153825ee016b91549962f970d6a4442fa106832e14c918acd1c8e479916c4f"},
+ {file = "regex-2024.11.6-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea1bfda2f7162605f6e8178223576856b3d791109f15ea99a9f95c16a7636fb5"},
+ {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:df951c5f4a1b1910f1a99ff42c473ff60f8225baa1cdd3539fe2819d9543e9df"},
+ {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:072623554418a9911446278f16ecb398fb3b540147a7828c06e2011fa531e773"},
+ {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:f654882311409afb1d780b940234208a252322c24a93b442ca714d119e68086c"},
+ {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:89d75e7293d2b3e674db7d4d9b1bee7f8f3d1609428e293771d1a962617150cc"},
+ {file = "regex-2024.11.6-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:f65557897fc977a44ab205ea871b690adaef6b9da6afda4790a2484b04293a5f"},
+ {file = "regex-2024.11.6-cp38-cp38-win32.whl", hash = "sha256:6f44ec28b1f858c98d3036ad5d7d0bfc568bdd7a74f9c24e25f41ef1ebfd81a4"},
+ {file = "regex-2024.11.6-cp38-cp38-win_amd64.whl", hash = "sha256:bb8f74f2f10dbf13a0be8de623ba4f9491faf58c24064f32b65679b021ed0001"},
+ {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5704e174f8ccab2026bd2f1ab6c510345ae8eac818b613d7d73e785f1310f839"},
+ {file = "regex-2024.11.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:220902c3c5cc6af55d4fe19ead504de80eb91f786dc102fbd74894b1551f095e"},
+ {file = "regex-2024.11.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5e7e351589da0850c125f1600a4c4ba3c722efefe16b297de54300f08d734fbf"},
+ {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5056b185ca113c88e18223183aa1a50e66507769c9640a6ff75859619d73957b"},
+ {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e34b51b650b23ed3354b5a07aab37034d9f923db2a40519139af34f485f77d0"},
+ {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5670bce7b200273eee1840ef307bfa07cda90b38ae56e9a6ebcc9f50da9c469b"},
+ {file = "regex-2024.11.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:08986dce1339bc932923e7d1232ce9881499a0e02925f7402fb7c982515419ef"},
+ {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93c0b12d3d3bc25af4ebbf38f9ee780a487e8bf6954c115b9f015822d3bb8e48"},
+ {file = "regex-2024.11.6-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:764e71f22ab3b305e7f4c21f1a97e1526a25ebdd22513e251cf376760213da13"},
+ {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:f056bf21105c2515c32372bbc057f43eb02aae2fda61052e2f7622c801f0b4e2"},
+ {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:69ab78f848845569401469da20df3e081e6b5a11cb086de3eed1d48f5ed57c95"},
+ {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:86fddba590aad9208e2fa8b43b4c098bb0ec74f15718bb6a704e3c63e2cef3e9"},
+ {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:684d7a212682996d21ca12ef3c17353c021fe9de6049e19ac8481ec35574a70f"},
+ {file = "regex-2024.11.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a03e02f48cd1abbd9f3b7e3586d97c8f7a9721c436f51a5245b3b9483044480b"},
+ {file = "regex-2024.11.6-cp39-cp39-win32.whl", hash = "sha256:41758407fc32d5c3c5de163888068cfee69cb4c2be844e7ac517a52770f9af57"},
+ {file = "regex-2024.11.6-cp39-cp39-win_amd64.whl", hash = "sha256:b2837718570f95dd41675328e111345f9b7095d821bac435aac173ac80b19983"},
+ {file = "regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519"},
+]
+
+[[package]]
+name = "requests"
+version = "2.32.4"
+description = "Python HTTP for Humans."
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c"},
+ {file = "requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422"},
+]
+
+[package.dependencies]
+certifi = ">=2017.4.17"
+charset_normalizer = ">=2,<4"
+idna = ">=2.5,<4"
+urllib3 = ">=1.21.1,<3"
+
+[package.extras]
+socks = ["PySocks (>=1.5.6,!=1.5.7)"]
+use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
+
+[[package]]
+name = "requests-toolbelt"
+version = "1.0.0"
+description = "A utility belt for advanced users of python-requests"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+groups = ["main"]
+files = [
+ {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"},
+ {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"},
+]
+
+[package.dependencies]
+requests = ">=2.0.1,<3.0.0"
+
+[[package]]
+name = "rich"
+version = "14.0.0"
+description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
+optional = false
+python-versions = ">=3.8.0"
+groups = ["main"]
+files = [
+ {file = "rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0"},
+ {file = "rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725"},
+]
+
+[package.dependencies]
+markdown-it-py = ">=2.2.0"
+pygments = ">=2.13.0,<3.0.0"
+
+[package.extras]
+jupyter = ["ipywidgets (>=7.5.1,<9)"]
+
+[[package]]
+name = "rpds-py"
+version = "0.26.0"
+description = "Python bindings to Rust's persistent data structures (rpds)"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "rpds_py-0.26.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4c70c70f9169692b36307a95f3d8c0a9fcd79f7b4a383aad5eaa0e9718b79b37"},
+ {file = "rpds_py-0.26.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:777c62479d12395bfb932944e61e915741e364c843afc3196b694db3d669fcd0"},
+ {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec671691e72dff75817386aa02d81e708b5a7ec0dec6669ec05213ff6b77e1bd"},
+ {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6a1cb5d6ce81379401bbb7f6dbe3d56de537fb8235979843f0d53bc2e9815a79"},
+ {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f789e32fa1fb6a7bf890e0124e7b42d1e60d28ebff57fe806719abb75f0e9a3"},
+ {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c55b0a669976cf258afd718de3d9ad1b7d1fe0a91cd1ab36f38b03d4d4aeaaf"},
+ {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c70d9ec912802ecfd6cd390dadb34a9578b04f9bcb8e863d0a7598ba5e9e7ccc"},
+ {file = "rpds_py-0.26.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3021933c2cb7def39d927b9862292e0f4c75a13d7de70eb0ab06efed4c508c19"},
+ {file = "rpds_py-0.26.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8a7898b6ca3b7d6659e55cdac825a2e58c638cbf335cde41f4619e290dd0ad11"},
+ {file = "rpds_py-0.26.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:12bff2ad9447188377f1b2794772f91fe68bb4bbfa5a39d7941fbebdbf8c500f"},
+ {file = "rpds_py-0.26.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:191aa858f7d4902e975d4cf2f2d9243816c91e9605070aeb09c0a800d187e323"},
+ {file = "rpds_py-0.26.0-cp310-cp310-win32.whl", hash = "sha256:b37a04d9f52cb76b6b78f35109b513f6519efb481d8ca4c321f6a3b9580b3f45"},
+ {file = "rpds_py-0.26.0-cp310-cp310-win_amd64.whl", hash = "sha256:38721d4c9edd3eb6670437d8d5e2070063f305bfa2d5aa4278c51cedcd508a84"},
+ {file = "rpds_py-0.26.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9e8cb77286025bdb21be2941d64ac6ca016130bfdcd228739e8ab137eb4406ed"},
+ {file = "rpds_py-0.26.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5e09330b21d98adc8ccb2dbb9fc6cb434e8908d4c119aeaa772cb1caab5440a0"},
+ {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c9c1b92b774b2e68d11193dc39620d62fd8ab33f0a3c77ecdabe19c179cdbc1"},
+ {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:824e6d3503ab990d7090768e4dfd9e840837bae057f212ff9f4f05ec6d1975e7"},
+ {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ad7fd2258228bf288f2331f0a6148ad0186b2e3643055ed0db30990e59817a6"},
+ {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0dc23bbb3e06ec1ea72d515fb572c1fea59695aefbffb106501138762e1e915e"},
+ {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d80bf832ac7b1920ee29a426cdca335f96a2b5caa839811803e999b41ba9030d"},
+ {file = "rpds_py-0.26.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0919f38f5542c0a87e7b4afcafab6fd2c15386632d249e9a087498571250abe3"},
+ {file = "rpds_py-0.26.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d422b945683e409000c888e384546dbab9009bb92f7c0b456e217988cf316107"},
+ {file = "rpds_py-0.26.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:77a7711fa562ba2da1aa757e11024ad6d93bad6ad7ede5afb9af144623e5f76a"},
+ {file = "rpds_py-0.26.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:238e8c8610cb7c29460e37184f6799547f7e09e6a9bdbdab4e8edb90986a2318"},
+ {file = "rpds_py-0.26.0-cp311-cp311-win32.whl", hash = "sha256:893b022bfbdf26d7bedb083efeea624e8550ca6eb98bf7fea30211ce95b9201a"},
+ {file = "rpds_py-0.26.0-cp311-cp311-win_amd64.whl", hash = "sha256:87a5531de9f71aceb8af041d72fc4cab4943648d91875ed56d2e629bef6d4c03"},
+ {file = "rpds_py-0.26.0-cp311-cp311-win_arm64.whl", hash = "sha256:de2713f48c1ad57f89ac25b3cb7daed2156d8e822cf0eca9b96a6f990718cc41"},
+ {file = "rpds_py-0.26.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:894514d47e012e794f1350f076c427d2347ebf82f9b958d554d12819849a369d"},
+ {file = "rpds_py-0.26.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fc921b96fa95a097add244da36a1d9e4f3039160d1d30f1b35837bf108c21136"},
+ {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e1157659470aa42a75448b6e943c895be8c70531c43cb78b9ba990778955582"},
+ {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:521ccf56f45bb3a791182dc6b88ae5f8fa079dd705ee42138c76deb1238e554e"},
+ {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9def736773fd56b305c0eef698be5192c77bfa30d55a0e5885f80126c4831a15"},
+ {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cdad4ea3b4513b475e027be79e5a0ceac8ee1c113a1a11e5edc3c30c29f964d8"},
+ {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82b165b07f416bdccf5c84546a484cc8f15137ca38325403864bfdf2b5b72f6a"},
+ {file = "rpds_py-0.26.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d04cab0a54b9dba4d278fe955a1390da3cf71f57feb78ddc7cb67cbe0bd30323"},
+ {file = "rpds_py-0.26.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:79061ba1a11b6a12743a2b0f72a46aa2758613d454aa6ba4f5a265cc48850158"},
+ {file = "rpds_py-0.26.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f405c93675d8d4c5ac87364bb38d06c988e11028a64b52a47158a355079661f3"},
+ {file = "rpds_py-0.26.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dafd4c44b74aa4bed4b250f1aed165b8ef5de743bcca3b88fc9619b6087093d2"},
+ {file = "rpds_py-0.26.0-cp312-cp312-win32.whl", hash = "sha256:3da5852aad63fa0c6f836f3359647870e21ea96cf433eb393ffa45263a170d44"},
+ {file = "rpds_py-0.26.0-cp312-cp312-win_amd64.whl", hash = "sha256:cf47cfdabc2194a669dcf7a8dbba62e37a04c5041d2125fae0233b720da6f05c"},
+ {file = "rpds_py-0.26.0-cp312-cp312-win_arm64.whl", hash = "sha256:20ab1ae4fa534f73647aad289003f1104092890849e0266271351922ed5574f8"},
+ {file = "rpds_py-0.26.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:696764a5be111b036256c0b18cd29783fab22154690fc698062fc1b0084b511d"},
+ {file = "rpds_py-0.26.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1e6c15d2080a63aaed876e228efe4f814bc7889c63b1e112ad46fdc8b368b9e1"},
+ {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390e3170babf42462739a93321e657444f0862c6d722a291accc46f9d21ed04e"},
+ {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7da84c2c74c0f5bc97d853d9e17bb83e2dcafcff0dc48286916001cc114379a1"},
+ {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c5fe114a6dd480a510b6d3661d09d67d1622c4bf20660a474507aaee7eeeee9"},
+ {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3100b3090269f3a7ea727b06a6080d4eb7439dca4c0e91a07c5d133bb1727ea7"},
+ {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c03c9b0c64afd0320ae57de4c982801271c0c211aa2d37f3003ff5feb75bb04"},
+ {file = "rpds_py-0.26.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5963b72ccd199ade6ee493723d18a3f21ba7d5b957017607f815788cef50eaf1"},
+ {file = "rpds_py-0.26.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9da4e873860ad5bab3291438525cae80169daecbfafe5657f7f5fb4d6b3f96b9"},
+ {file = "rpds_py-0.26.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:5afaddaa8e8c7f1f7b4c5c725c0070b6eed0228f705b90a1732a48e84350f4e9"},
+ {file = "rpds_py-0.26.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4916dc96489616a6f9667e7526af8fa693c0fdb4f3acb0e5d9f4400eb06a47ba"},
+ {file = "rpds_py-0.26.0-cp313-cp313-win32.whl", hash = "sha256:2a343f91b17097c546b93f7999976fd6c9d5900617aa848c81d794e062ab302b"},
+ {file = "rpds_py-0.26.0-cp313-cp313-win_amd64.whl", hash = "sha256:0a0b60701f2300c81b2ac88a5fb893ccfa408e1c4a555a77f908a2596eb875a5"},
+ {file = "rpds_py-0.26.0-cp313-cp313-win_arm64.whl", hash = "sha256:257d011919f133a4746958257f2c75238e3ff54255acd5e3e11f3ff41fd14256"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:529c8156d7506fba5740e05da8795688f87119cce330c244519cf706a4a3d618"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f53ec51f9d24e9638a40cabb95078ade8c99251945dad8d57bf4aabe86ecee35"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab504c4d654e4a29558eaa5bb8cea5fdc1703ea60a8099ffd9c758472cf913f"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fd0641abca296bc1a00183fe44f7fced8807ed49d501f188faa642d0e4975b83"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69b312fecc1d017b5327afa81d4da1480f51c68810963a7336d92203dbb3d4f1"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c741107203954f6fc34d3066d213d0a0c40f7bb5aafd698fb39888af277c70d8"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc3e55a7db08dc9a6ed5fb7103019d2c1a38a349ac41901f9f66d7f95750942f"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9e851920caab2dbcae311fd28f4313c6953993893eb5c1bb367ec69d9a39e7ed"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:dfbf280da5f876d0b00c81f26bedce274e72a678c28845453885a9b3c22ae632"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1cc81d14ddfa53d7f3906694d35d54d9d3f850ef8e4e99ee68bc0d1e5fed9a9c"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dca83c498b4650a91efcf7b88d669b170256bf8017a5db6f3e06c2bf031f57e0"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-win32.whl", hash = "sha256:4d11382bcaf12f80b51d790dee295c56a159633a8e81e6323b16e55d81ae37e9"},
+ {file = "rpds_py-0.26.0-cp313-cp313t-win_amd64.whl", hash = "sha256:ff110acded3c22c033e637dd8896e411c7d3a11289b2edf041f86663dbc791e9"},
+ {file = "rpds_py-0.26.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:da619979df60a940cd434084355c514c25cf8eb4cf9a508510682f6c851a4f7a"},
+ {file = "rpds_py-0.26.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ea89a2458a1a75f87caabefe789c87539ea4e43b40f18cff526052e35bbb4fdf"},
+ {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feac1045b3327a45944e7dcbeb57530339f6b17baff154df51ef8b0da34c8c12"},
+ {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b818a592bd69bfe437ee8368603d4a2d928c34cffcdf77c2e761a759ffd17d20"},
+ {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a8b0dd8648709b62d9372fc00a57466f5fdeefed666afe3fea5a6c9539a0331"},
+ {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6d3498ad0df07d81112aa6ec6c95a7e7b1ae00929fb73e7ebee0f3faaeabad2f"},
+ {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24a4146ccb15be237fdef10f331c568e1b0e505f8c8c9ed5d67759dac58ac246"},
+ {file = "rpds_py-0.26.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a9a63785467b2d73635957d32a4f6e73d5e4df497a16a6392fa066b753e87387"},
+ {file = "rpds_py-0.26.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:de4ed93a8c91debfd5a047be327b7cc8b0cc6afe32a716bbbc4aedca9e2a83af"},
+ {file = "rpds_py-0.26.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:caf51943715b12af827696ec395bfa68f090a4c1a1d2509eb4e2cb69abbbdb33"},
+ {file = "rpds_py-0.26.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4a59e5bc386de021f56337f757301b337d7ab58baa40174fb150accd480bc953"},
+ {file = "rpds_py-0.26.0-cp314-cp314-win32.whl", hash = "sha256:92c8db839367ef16a662478f0a2fe13e15f2227da3c1430a782ad0f6ee009ec9"},
+ {file = "rpds_py-0.26.0-cp314-cp314-win_amd64.whl", hash = "sha256:b0afb8cdd034150d4d9f53926226ed27ad15b7f465e93d7468caaf5eafae0d37"},
+ {file = "rpds_py-0.26.0-cp314-cp314-win_arm64.whl", hash = "sha256:ca3f059f4ba485d90c8dc75cb5ca897e15325e4e609812ce57f896607c1c0867"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:5afea17ab3a126006dc2f293b14ffc7ef3c85336cf451564a0515ed7648033da"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:69f0c0a3df7fd3a7eec50a00396104bb9a843ea6d45fcc31c2d5243446ffd7a7"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:801a71f70f9813e82d2513c9a96532551fce1e278ec0c64610992c49c04c2dad"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:df52098cde6d5e02fa75c1f6244f07971773adb4a26625edd5c18fee906fa84d"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bc596b30f86dc6f0929499c9e574601679d0341a0108c25b9b358a042f51bca"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9dfbe56b299cf5875b68eb6f0ebaadc9cac520a1989cac0db0765abfb3709c19"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac64f4b2bdb4ea622175c9ab7cf09444e412e22c0e02e906978b3b488af5fde8"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:181ef9b6bbf9845a264f9aa45c31836e9f3c1f13be565d0d010e964c661d1e2b"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:49028aa684c144ea502a8e847d23aed5e4c2ef7cadfa7d5eaafcb40864844b7a"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:e5d524d68a474a9688336045bbf76cb0def88549c1b2ad9dbfec1fb7cfbe9170"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c1851f429b822831bd2edcbe0cfd12ee9ea77868f8d3daf267b189371671c80e"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-win32.whl", hash = "sha256:7bdb17009696214c3b66bb3590c6d62e14ac5935e53e929bcdbc5a495987a84f"},
+ {file = "rpds_py-0.26.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f14440b9573a6f76b4ee4770c13f0b5921f71dde3b6fcb8dabbefd13b7fe05d7"},
+ {file = "rpds_py-0.26.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:7a48af25d9b3c15684059d0d1fc0bc30e8eee5ca521030e2bffddcab5be40226"},
+ {file = "rpds_py-0.26.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0c71c2f6bf36e61ee5c47b2b9b5d47e4d1baad6426bfed9eea3e858fc6ee8806"},
+ {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d815d48b1804ed7867b539236b6dd62997850ca1c91cad187f2ddb1b7bbef19"},
+ {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:84cfbd4d4d2cdeb2be61a057a258d26b22877266dd905809e94172dff01a42ae"},
+ {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fbaa70553ca116c77717f513e08815aec458e6b69a028d4028d403b3bc84ff37"},
+ {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39bfea47c375f379d8e87ab4bb9eb2c836e4f2069f0f65731d85e55d74666387"},
+ {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1533b7eb683fb5f38c1d68a3c78f5fdd8f1412fa6b9bf03b40f450785a0ab915"},
+ {file = "rpds_py-0.26.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c5ab0ee51f560d179b057555b4f601b7df909ed31312d301b99f8b9fc6028284"},
+ {file = "rpds_py-0.26.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:e5162afc9e0d1f9cae3b577d9c29ddbab3505ab39012cb794d94a005825bde21"},
+ {file = "rpds_py-0.26.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:43f10b007033f359bc3fa9cd5e6c1e76723f056ffa9a6b5c117cc35720a80292"},
+ {file = "rpds_py-0.26.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e3730a48e5622e598293eee0762b09cff34dd3f271530f47b0894891281f051d"},
+ {file = "rpds_py-0.26.0-cp39-cp39-win32.whl", hash = "sha256:4b1f66eb81eab2e0ff5775a3a312e5e2e16bf758f7b06be82fb0d04078c7ac51"},
+ {file = "rpds_py-0.26.0-cp39-cp39-win_amd64.whl", hash = "sha256:519067e29f67b5c90e64fb1a6b6e9d2ec0ba28705c51956637bac23a2f4ddae1"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3c0909c5234543ada2515c05dc08595b08d621ba919629e94427e8e03539c958"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c1fb0cda2abcc0ac62f64e2ea4b4e64c57dfd6b885e693095460c61bde7bb18e"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:84d142d2d6cf9b31c12aa4878d82ed3b2324226270b89b676ac62ccd7df52d08"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a547e21c5610b7e9093d870be50682a6a6cf180d6da0f42c47c306073bfdbbf6"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35e9a70a0f335371275cdcd08bc5b8051ac494dd58bff3bbfb421038220dc871"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0dfa6115c6def37905344d56fb54c03afc49104e2ca473d5dedec0f6606913b4"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:313cfcd6af1a55a286a3c9a25f64af6d0e46cf60bc5798f1db152d97a216ff6f"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f7bf2496fa563c046d05e4d232d7b7fd61346e2402052064b773e5c378bf6f73"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:aa81873e2c8c5aa616ab8e017a481a96742fdf9313c40f14338ca7dbf50cb55f"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:68ffcf982715f5b5b7686bdd349ff75d422e8f22551000c24b30eaa1b7f7ae84"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6188de70e190847bb6db3dc3981cbadff87d27d6fe9b4f0e18726d55795cee9b"},
+ {file = "rpds_py-0.26.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1c962145c7473723df9722ba4c058de12eb5ebedcb4e27e7d902920aa3831ee8"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f61a9326f80ca59214d1cceb0a09bb2ece5b2563d4e0cd37bfd5515c28510674"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:183f857a53bcf4b1b42ef0f57ca553ab56bdd170e49d8091e96c51c3d69ca696"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:941c1cfdf4799d623cf3aa1d326a6b4fdb7a5799ee2687f3516738216d2262fb"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72a8d9564a717ee291f554eeb4bfeafe2309d5ec0aa6c475170bdab0f9ee8e88"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:511d15193cbe013619dd05414c35a7dedf2088fcee93c6bbb7c77859765bd4e8"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aea1f9741b603a8d8fedb0ed5502c2bc0accbc51f43e2ad1337fe7259c2b77a5"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4019a9d473c708cf2f16415688ef0b4639e07abaa569d72f74745bbeffafa2c7"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:093d63b4b0f52d98ebae33b8c50900d3d67e0666094b1be7a12fffd7f65de74b"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2abe21d8ba64cded53a2a677e149ceb76dcf44284202d737178afe7ba540c1eb"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:4feb7511c29f8442cbbc28149a92093d32e815a28aa2c50d333826ad2a20fdf0"},
+ {file = "rpds_py-0.26.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e99685fc95d386da368013e7fb4269dd39c30d99f812a8372d62f244f662709c"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a90a13408a7a856b87be8a9f008fff53c5080eea4e4180f6c2e546e4a972fb5d"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3ac51b65e8dc76cf4949419c54c5528adb24fc721df722fd452e5fbc236f5c40"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59b2093224a18c6508d95cfdeba8db9cbfd6f3494e94793b58972933fcee4c6d"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f01a5d6444a3258b00dc07b6ea4733e26f8072b788bef750baa37b370266137"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b6e2c12160c72aeda9d1283e612f68804621f448145a210f1bf1d79151c47090"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb28c1f569f8d33b2b5dcd05d0e6ef7005d8639c54c2f0be824f05aedf715255"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1766b5724c3f779317d5321664a343c07773c8c5fd1532e4039e6cc7d1a815be"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b6d9e5a2ed9c4988c8f9b28b3bc0e3e5b1aaa10c28d210a594ff3a8c02742daf"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:b5f7a446ddaf6ca0fad9a5535b56fbfc29998bf0e0b450d174bbec0d600e1d72"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:eed5ac260dd545fbc20da5f4f15e7efe36a55e0e7cf706e4ec005b491a9546a0"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:582462833ba7cee52e968b0341b85e392ae53d44c0f9af6a5927c80e539a8b67"},
+ {file = "rpds_py-0.26.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:69a607203441e07e9a8a529cff1d5b73f6a160f22db1097211e6212a68567d11"},
+ {file = "rpds_py-0.26.0.tar.gz", hash = "sha256:20dae58a859b0906f0685642e591056f1e787f3a8b39c8e8749a45dc7d26bdb0"},
+]
+
+[[package]]
+name = "simple-websocket"
+version = "1.1.0"
+description = "Simple WebSocket server and client for Python"
+optional = false
+python-versions = ">=3.6"
+groups = ["main"]
+files = [
+ {file = "simple_websocket-1.1.0-py3-none-any.whl", hash = "sha256:4af6069630a38ed6c561010f0e11a5bc0d4ca569b36306eb257cd9a192497c8c"},
+ {file = "simple_websocket-1.1.0.tar.gz", hash = "sha256:7939234e7aa067c534abdab3a9ed933ec9ce4691b0713c78acb195560aa52ae4"},
+]
+
+[package.dependencies]
+wsproto = "*"
+
+[package.extras]
+dev = ["flake8", "pytest", "pytest-cov", "tox"]
+docs = ["sphinx"]
+
+[[package]]
+name = "six"
+version = "1.17.0"
+description = "Python 2 and 3 compatibility utilities"
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
+groups = ["main"]
+files = [
+ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"},
+ {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"},
+]
+
+[[package]]
+name = "sniffio"
+version = "1.3.1"
+description = "Sniff out which async library your code is running under"
+optional = false
+python-versions = ">=3.7"
+groups = ["main"]
+files = [
+ {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"},
+ {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
+]
+
+[[package]]
+name = "sqlalchemy"
+version = "2.0.41"
+description = "Database Abstraction Library"
+optional = false
+python-versions = ">=3.7"
+groups = ["main"]
+files = [
+ {file = "SQLAlchemy-2.0.41-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6854175807af57bdb6425e47adbce7d20a4d79bbfd6f6d6519cd10bb7109a7f8"},
+ {file = "SQLAlchemy-2.0.41-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05132c906066142103b83d9c250b60508af556982a385d96c4eaa9fb9720ac2b"},
+ {file = "SQLAlchemy-2.0.41-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b4af17bda11e907c51d10686eda89049f9ce5669b08fbe71a29747f1e876036"},
+ {file = "SQLAlchemy-2.0.41-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:c0b0e5e1b5d9f3586601048dd68f392dc0cc99a59bb5faf18aab057ce00d00b2"},
+ {file = "SQLAlchemy-2.0.41-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0b3dbf1e7e9bc95f4bac5e2fb6d3fb2f083254c3fdd20a1789af965caf2d2348"},
+ {file = "SQLAlchemy-2.0.41-cp37-cp37m-win32.whl", hash = "sha256:1e3f196a0c59b0cae9a0cd332eb1a4bda4696e863f4f1cf84ab0347992c548c2"},
+ {file = "SQLAlchemy-2.0.41-cp37-cp37m-win_amd64.whl", hash = "sha256:6ab60a5089a8f02009f127806f777fca82581c49e127f08413a66056bd9166dd"},
+ {file = "sqlalchemy-2.0.41-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b1f09b6821406ea1f94053f346f28f8215e293344209129a9c0fcc3578598d7b"},
+ {file = "sqlalchemy-2.0.41-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1936af879e3db023601196a1684d28e12f19ccf93af01bf3280a3262c4b6b4e5"},
+ {file = "sqlalchemy-2.0.41-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2ac41acfc8d965fb0c464eb8f44995770239668956dc4cdf502d1b1ffe0d747"},
+ {file = "sqlalchemy-2.0.41-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81c24e0c0fde47a9723c81d5806569cddef103aebbf79dbc9fcbb617153dea30"},
+ {file = "sqlalchemy-2.0.41-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:23a8825495d8b195c4aa9ff1c430c28f2c821e8c5e2d98089228af887e5d7e29"},
+ {file = "sqlalchemy-2.0.41-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:60c578c45c949f909a4026b7807044e7e564adf793537fc762b2489d522f3d11"},
+ {file = "sqlalchemy-2.0.41-cp310-cp310-win32.whl", hash = "sha256:118c16cd3f1b00c76d69343e38602006c9cfb9998fa4f798606d28d63f23beda"},
+ {file = "sqlalchemy-2.0.41-cp310-cp310-win_amd64.whl", hash = "sha256:7492967c3386df69f80cf67efd665c0f667cee67032090fe01d7d74b0e19bb08"},
+ {file = "sqlalchemy-2.0.41-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6375cd674fe82d7aa9816d1cb96ec592bac1726c11e0cafbf40eeee9a4516b5f"},
+ {file = "sqlalchemy-2.0.41-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9f8c9fdd15a55d9465e590a402f42082705d66b05afc3ffd2d2eb3c6ba919560"},
+ {file = "sqlalchemy-2.0.41-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32f9dc8c44acdee06c8fc6440db9eae8b4af8b01e4b1aee7bdd7241c22edff4f"},
+ {file = "sqlalchemy-2.0.41-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90c11ceb9a1f482c752a71f203a81858625d8df5746d787a4786bca4ffdf71c6"},
+ {file = "sqlalchemy-2.0.41-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:911cc493ebd60de5f285bcae0491a60b4f2a9f0f5c270edd1c4dbaef7a38fc04"},
+ {file = "sqlalchemy-2.0.41-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03968a349db483936c249f4d9cd14ff2c296adfa1290b660ba6516f973139582"},
+ {file = "sqlalchemy-2.0.41-cp311-cp311-win32.whl", hash = "sha256:293cd444d82b18da48c9f71cd7005844dbbd06ca19be1ccf6779154439eec0b8"},
+ {file = "sqlalchemy-2.0.41-cp311-cp311-win_amd64.whl", hash = "sha256:3d3549fc3e40667ec7199033a4e40a2f669898a00a7b18a931d3efb4c7900504"},
+ {file = "sqlalchemy-2.0.41-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:81f413674d85cfd0dfcd6512e10e0f33c19c21860342a4890c3a2b59479929f9"},
+ {file = "sqlalchemy-2.0.41-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:598d9ebc1e796431bbd068e41e4de4dc34312b7aa3292571bb3674a0cb415dd1"},
+ {file = "sqlalchemy-2.0.41-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a104c5694dfd2d864a6f91b0956eb5d5883234119cb40010115fd45a16da5e70"},
+ {file = "sqlalchemy-2.0.41-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6145afea51ff0af7f2564a05fa95eb46f542919e6523729663a5d285ecb3cf5e"},
+ {file = "sqlalchemy-2.0.41-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b46fa6eae1cd1c20e6e6f44e19984d438b6b2d8616d21d783d150df714f44078"},
+ {file = "sqlalchemy-2.0.41-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:41836fe661cc98abfae476e14ba1906220f92c4e528771a8a3ae6a151242d2ae"},
+ {file = "sqlalchemy-2.0.41-cp312-cp312-win32.whl", hash = "sha256:a8808d5cf866c781150d36a3c8eb3adccfa41a8105d031bf27e92c251e3969d6"},
+ {file = "sqlalchemy-2.0.41-cp312-cp312-win_amd64.whl", hash = "sha256:5b14e97886199c1f52c14629c11d90c11fbb09e9334fa7bb5f6d068d9ced0ce0"},
+ {file = "sqlalchemy-2.0.41-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4eeb195cdedaf17aab6b247894ff2734dcead6c08f748e617bfe05bd5a218443"},
+ {file = "sqlalchemy-2.0.41-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d4ae769b9c1c7757e4ccce94b0641bc203bbdf43ba7a2413ab2523d8d047d8dc"},
+ {file = "sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a62448526dd9ed3e3beedc93df9bb6b55a436ed1474db31a2af13b313a70a7e1"},
+ {file = "sqlalchemy-2.0.41-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc56c9788617b8964ad02e8fcfeed4001c1f8ba91a9e1f31483c0dffb207002a"},
+ {file = "sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c153265408d18de4cc5ded1941dcd8315894572cddd3c58df5d5b5705b3fa28d"},
+ {file = "sqlalchemy-2.0.41-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f67766965996e63bb46cfbf2ce5355fc32d9dd3b8ad7e536a920ff9ee422e23"},
+ {file = "sqlalchemy-2.0.41-cp313-cp313-win32.whl", hash = "sha256:bfc9064f6658a3d1cadeaa0ba07570b83ce6801a1314985bf98ec9b95d74e15f"},
+ {file = "sqlalchemy-2.0.41-cp313-cp313-win_amd64.whl", hash = "sha256:82ca366a844eb551daff9d2e6e7a9e5e76d2612c8564f58db6c19a726869c1df"},
+ {file = "sqlalchemy-2.0.41-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:90144d3b0c8b139408da50196c5cad2a6909b51b23df1f0538411cd23ffa45d3"},
+ {file = "sqlalchemy-2.0.41-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:023b3ee6169969beea3bb72312e44d8b7c27c75b347942d943cf49397b7edeb5"},
+ {file = "sqlalchemy-2.0.41-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:725875a63abf7c399d4548e686debb65cdc2549e1825437096a0af1f7e374814"},
+ {file = "sqlalchemy-2.0.41-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81965cc20848ab06583506ef54e37cf15c83c7e619df2ad16807c03100745dea"},
+ {file = "sqlalchemy-2.0.41-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dd5ec3aa6ae6e4d5b5de9357d2133c07be1aff6405b136dad753a16afb6717dd"},
+ {file = "sqlalchemy-2.0.41-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ff8e80c4c4932c10493ff97028decfdb622de69cae87e0f127a7ebe32b4069c6"},
+ {file = "sqlalchemy-2.0.41-cp38-cp38-win32.whl", hash = "sha256:4d44522480e0bf34c3d63167b8cfa7289c1c54264c2950cc5fc26e7850967e45"},
+ {file = "sqlalchemy-2.0.41-cp38-cp38-win_amd64.whl", hash = "sha256:81eedafa609917040d39aa9332e25881a8e7a0862495fcdf2023a9667209deda"},
+ {file = "sqlalchemy-2.0.41-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9a420a91913092d1e20c86a2f5f1fc85c1a8924dbcaf5e0586df8aceb09c9cc2"},
+ {file = "sqlalchemy-2.0.41-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:906e6b0d7d452e9a98e5ab8507c0da791856b2380fdee61b765632bb8698026f"},
+ {file = "sqlalchemy-2.0.41-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a373a400f3e9bac95ba2a06372c4fd1412a7cee53c37fc6c05f829bf672b8769"},
+ {file = "sqlalchemy-2.0.41-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:087b6b52de812741c27231b5a3586384d60c353fbd0e2f81405a814b5591dc8b"},
+ {file = "sqlalchemy-2.0.41-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:34ea30ab3ec98355235972dadc497bb659cc75f8292b760394824fab9cf39826"},
+ {file = "sqlalchemy-2.0.41-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8280856dd7c6a68ab3a164b4a4b1c51f7691f6d04af4d4ca23d6ecf2261b7923"},
+ {file = "sqlalchemy-2.0.41-cp39-cp39-win32.whl", hash = "sha256:b50eab9994d64f4a823ff99a0ed28a6903224ddbe7fef56a6dd865eec9243440"},
+ {file = "sqlalchemy-2.0.41-cp39-cp39-win_amd64.whl", hash = "sha256:5e22575d169529ac3e0a120cf050ec9daa94b6a9597993d1702884f6954a7d71"},
+ {file = "sqlalchemy-2.0.41-py3-none-any.whl", hash = "sha256:57df5dc6fdb5ed1a88a1ed2195fd31927e705cad62dedd86b46972752a80f576"},
+ {file = "sqlalchemy-2.0.41.tar.gz", hash = "sha256:edba70118c4be3c2b1f90754d308d0b79c6fe2c0fdc52d8ddf603916f83f4db9"},
+]
+
+[package.dependencies]
+greenlet = {version = ">=1", markers = "python_version < \"3.14\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"}
+typing-extensions = ">=4.6.0"
+
+[package.extras]
+aiomysql = ["aiomysql (>=0.2.0)", "greenlet (>=1)"]
+aioodbc = ["aioodbc", "greenlet (>=1)"]
+aiosqlite = ["aiosqlite", "greenlet (>=1)", "typing_extensions (!=3.10.0.1)"]
+asyncio = ["greenlet (>=1)"]
+asyncmy = ["asyncmy (>=0.2.3,!=0.2.4,!=0.2.6)", "greenlet (>=1)"]
+mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2,!=1.1.5,!=1.1.10)"]
+mssql = ["pyodbc"]
+mssql-pymssql = ["pymssql"]
+mssql-pyodbc = ["pyodbc"]
+mypy = ["mypy (>=0.910)"]
+mysql = ["mysqlclient (>=1.4.0)"]
+mysql-connector = ["mysql-connector-python"]
+oracle = ["cx_oracle (>=8)"]
+oracle-oracledb = ["oracledb (>=1.0.1)"]
+postgresql = ["psycopg2 (>=2.7)"]
+postgresql-asyncpg = ["asyncpg", "greenlet (>=1)"]
+postgresql-pg8000 = ["pg8000 (>=1.29.1)"]
+postgresql-psycopg = ["psycopg (>=3.0.7)"]
+postgresql-psycopg2binary = ["psycopg2-binary"]
+postgresql-psycopg2cffi = ["psycopg2cffi"]
+postgresql-psycopgbinary = ["psycopg[binary] (>=3.0.7)"]
+pymysql = ["pymysql"]
+sqlcipher = ["sqlcipher3_binary"]
+
+[[package]]
+name = "sse-starlette"
+version = "2.4.1"
+description = "SSE plugin for Starlette"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "sse_starlette-2.4.1-py3-none-any.whl", hash = "sha256:08b77ea898ab1a13a428b2b6f73cfe6d0e607a7b4e15b9bb23e4a37b087fd39a"},
+ {file = "sse_starlette-2.4.1.tar.gz", hash = "sha256:7c8a800a1ca343e9165fc06bbda45c78e4c6166320707ae30b416c42da070926"},
+]
+
+[package.dependencies]
+anyio = ">=4.7.0"
+
+[package.extras]
+daphne = ["daphne (>=4.2.0)"]
+examples = ["aiosqlite (>=0.21.0)", "fastapi (>=0.115.12)", "sqlalchemy[asyncio,examples] (>=2.0.41)", "starlette (>=0.41.3)", "uvicorn (>=0.34.0)"]
+granian = ["granian (>=2.3.1)"]
+uvicorn = ["uvicorn (>=0.34.0)"]
+
+[[package]]
+name = "starlette"
+version = "0.41.3"
+description = "The little ASGI library that shines."
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "starlette-0.41.3-py3-none-any.whl", hash = "sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7"},
+ {file = "starlette-0.41.3.tar.gz", hash = "sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835"},
+]
+
+[package.dependencies]
+anyio = ">=3.4.0,<5"
+
+[package.extras]
+full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"]
+
+[[package]]
+name = "syncer"
+version = "2.0.3"
+description = "Async to sync converter"
+optional = false
+python-versions = "*"
+groups = ["main"]
+files = [
+ {file = "syncer-2.0.3.tar.gz", hash = "sha256:4340eb54b54368724a78c5c0763824470201804fe9180129daf3635cb500550f"},
+]
+
+[[package]]
+name = "syrupy"
+version = "4.9.1"
+description = "Pytest Snapshot Test Utility"
+optional = false
+python-versions = ">=3.8.1"
+groups = ["main"]
+files = [
+ {file = "syrupy-4.9.1-py3-none-any.whl", hash = "sha256:b94cc12ed0e5e75b448255430af642516842a2374a46936dd2650cfb6dd20eda"},
+ {file = "syrupy-4.9.1.tar.gz", hash = "sha256:b7d0fcadad80a7d2f6c4c71917918e8ebe2483e8c703dfc8d49cdbb01081f9a4"},
+]
+
+[package.dependencies]
+pytest = ">=7.0.0,<9.0.0"
+
+[[package]]
+name = "tenacity"
+version = "9.1.2"
+description = "Retry code until it succeeds"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138"},
+ {file = "tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb"},
+]
+
+[package.extras]
+doc = ["reno", "sphinx"]
+test = ["pytest", "tornado (>=4.5)", "typeguard"]
+
+[[package]]
+name = "tiktoken"
+version = "0.9.0"
+description = "tiktoken is a fast BPE tokeniser for use with OpenAI's models"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "tiktoken-0.9.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:586c16358138b96ea804c034b8acf3f5d3f0258bd2bc3b0227af4af5d622e382"},
+ {file = "tiktoken-0.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d9c59ccc528c6c5dd51820b3474402f69d9a9e1d656226848ad68a8d5b2e5108"},
+ {file = "tiktoken-0.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0968d5beeafbca2a72c595e8385a1a1f8af58feaebb02b227229b69ca5357fd"},
+ {file = "tiktoken-0.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92a5fb085a6a3b7350b8fc838baf493317ca0e17bd95e8642f95fc69ecfed1de"},
+ {file = "tiktoken-0.9.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15a2752dea63d93b0332fb0ddb05dd909371ededa145fe6a3242f46724fa7990"},
+ {file = "tiktoken-0.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:26113fec3bd7a352e4b33dbaf1bd8948de2507e30bd95a44e2b1156647bc01b4"},
+ {file = "tiktoken-0.9.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f32cc56168eac4851109e9b5d327637f15fd662aa30dd79f964b7c39fbadd26e"},
+ {file = "tiktoken-0.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:45556bc41241e5294063508caf901bf92ba52d8ef9222023f83d2483a3055348"},
+ {file = "tiktoken-0.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03935988a91d6d3216e2ec7c645afbb3d870b37bcb67ada1943ec48678e7ee33"},
+ {file = "tiktoken-0.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b3d80aad8d2c6b9238fc1a5524542087c52b860b10cbf952429ffb714bc1136"},
+ {file = "tiktoken-0.9.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b2a21133be05dc116b1d0372af051cd2c6aa1d2188250c9b553f9fa49301b336"},
+ {file = "tiktoken-0.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:11a20e67fdf58b0e2dea7b8654a288e481bb4fc0289d3ad21291f8d0849915fb"},
+ {file = "tiktoken-0.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e88f121c1c22b726649ce67c089b90ddda8b9662545a8aeb03cfef15967ddd03"},
+ {file = "tiktoken-0.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a6600660f2f72369acb13a57fb3e212434ed38b045fd8cc6cdd74947b4b5d210"},
+ {file = "tiktoken-0.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95e811743b5dfa74f4b227927ed86cbc57cad4df859cb3b643be797914e41794"},
+ {file = "tiktoken-0.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99376e1370d59bcf6935c933cb9ba64adc29033b7e73f5f7569f3aad86552b22"},
+ {file = "tiktoken-0.9.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:badb947c32739fb6ddde173e14885fb3de4d32ab9d8c591cbd013c22b4c31dd2"},
+ {file = "tiktoken-0.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:5a62d7a25225bafed786a524c1b9f0910a1128f4232615bf3f8257a73aaa3b16"},
+ {file = "tiktoken-0.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2b0e8e05a26eda1249e824156d537015480af7ae222ccb798e5234ae0285dbdb"},
+ {file = "tiktoken-0.9.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:27d457f096f87685195eea0165a1807fae87b97b2161fe8c9b1df5bd74ca6f63"},
+ {file = "tiktoken-0.9.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cf8ded49cddf825390e36dd1ad35cd49589e8161fdcb52aa25f0583e90a3e01"},
+ {file = "tiktoken-0.9.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc156cb314119a8bb9748257a2eaebd5cc0753b6cb491d26694ed42fc7cb3139"},
+ {file = "tiktoken-0.9.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cd69372e8c9dd761f0ab873112aba55a0e3e506332dd9f7522ca466e817b1b7a"},
+ {file = "tiktoken-0.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:5ea0edb6f83dc56d794723286215918c1cde03712cbbafa0348b33448faf5b95"},
+ {file = "tiktoken-0.9.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c6386ca815e7d96ef5b4ac61e0048cd32ca5a92d5781255e13b31381d28667dc"},
+ {file = "tiktoken-0.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:75f6d5db5bc2c6274b674ceab1615c1778e6416b14705827d19b40e6355f03e0"},
+ {file = "tiktoken-0.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e15b16f61e6f4625a57a36496d28dd182a8a60ec20a534c5343ba3cafa156ac7"},
+ {file = "tiktoken-0.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebcec91babf21297022882344c3f7d9eed855931466c3311b1ad6b64befb3df"},
+ {file = "tiktoken-0.9.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e5fd49e7799579240f03913447c0cdfa1129625ebd5ac440787afc4345990427"},
+ {file = "tiktoken-0.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:26242ca9dc8b58e875ff4ca078b9a94d2f0813e6a535dcd2205df5d49d927cc7"},
+ {file = "tiktoken-0.9.0.tar.gz", hash = "sha256:d02a5ca6a938e0490e1ff957bc48c8b078c88cb83977be1625b1fd8aac792c5d"},
+]
+
+[package.dependencies]
+regex = ">=2022.1.18"
+requests = ">=2.26.0"
+
+[package.extras]
+blobfile = ["blobfile (>=2)"]
+
+[[package]]
+name = "tokenizers"
+version = "0.21.2"
+description = ""
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "tokenizers-0.21.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:342b5dfb75009f2255ab8dec0041287260fed5ce00c323eb6bab639066fef8ec"},
+ {file = "tokenizers-0.21.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:126df3205d6f3a93fea80c7a8a266a78c1bd8dd2fe043386bafdd7736a23e45f"},
+ {file = "tokenizers-0.21.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a32cd81be21168bd0d6a0f0962d60177c447a1aa1b1e48fa6ec9fc728ee0b12"},
+ {file = "tokenizers-0.21.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8bd8999538c405133c2ab999b83b17c08b7fc1b48c1ada2469964605a709ef91"},
+ {file = "tokenizers-0.21.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e9944e61239b083a41cf8fc42802f855e1dca0f499196df37a8ce219abac6eb"},
+ {file = "tokenizers-0.21.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:514cd43045c5d546f01142ff9c79a96ea69e4b5cda09e3027708cb2e6d5762ab"},
+ {file = "tokenizers-0.21.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1b9405822527ec1e0f7d8d2fdb287a5730c3a6518189c968254a8441b21faae"},
+ {file = "tokenizers-0.21.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fed9a4d51c395103ad24f8e7eb976811c57fbec2af9f133df471afcd922e5020"},
+ {file = "tokenizers-0.21.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2c41862df3d873665ec78b6be36fcc30a26e3d4902e9dd8608ed61d49a48bc19"},
+ {file = "tokenizers-0.21.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:ed21dc7e624e4220e21758b2e62893be7101453525e3d23264081c9ef9a6d00d"},
+ {file = "tokenizers-0.21.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:0e73770507e65a0e0e2a1affd6b03c36e3bc4377bd10c9ccf51a82c77c0fe365"},
+ {file = "tokenizers-0.21.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:106746e8aa9014a12109e58d540ad5465b4c183768ea96c03cbc24c44d329958"},
+ {file = "tokenizers-0.21.2-cp39-abi3-win32.whl", hash = "sha256:cabda5a6d15d620b6dfe711e1af52205266d05b379ea85a8a301b3593c60e962"},
+ {file = "tokenizers-0.21.2-cp39-abi3-win_amd64.whl", hash = "sha256:58747bb898acdb1007f37a7bbe614346e98dc28708ffb66a3fd50ce169ac6c98"},
+ {file = "tokenizers-0.21.2.tar.gz", hash = "sha256:fdc7cffde3e2113ba0e6cc7318c40e3438a4d74bbc62bf04bcc63bdfb082ac77"},
+]
+
+[package.dependencies]
+huggingface-hub = ">=0.16.4,<1.0"
+
+[package.extras]
+dev = ["tokenizers[testing]"]
+docs = ["setuptools-rust", "sphinx", "sphinx-rtd-theme"]
+testing = ["black (==22.3)", "datasets", "numpy", "pytest", "requests", "ruff"]
+
+[[package]]
+name = "tomli"
+version = "2.2.1"
+description = "A lil' TOML parser"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
+ {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
+ {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"},
+ {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"},
+ {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"},
+ {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"},
+ {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"},
+ {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"},
+ {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"},
+ {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"},
+ {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"},
+ {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"},
+ {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"},
+ {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"},
+ {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"},
+ {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"},
+ {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"},
+ {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"},
+ {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"},
+ {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"},
+ {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"},
+ {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"},
+ {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"},
+ {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"},
+ {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"},
+ {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"},
+ {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"},
+ {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"},
+ {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"},
+ {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"},
+ {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"},
+ {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"},
+]
+
+[[package]]
+name = "tqdm"
+version = "4.67.1"
+description = "Fast, Extensible Progress Meter"
+optional = false
+python-versions = ">=3.7"
+groups = ["main"]
+files = [
+ {file = "tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2"},
+ {file = "tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2"},
+]
+
+[package.dependencies]
+colorama = {version = "*", markers = "platform_system == \"Windows\""}
+
+[package.extras]
+dev = ["nbval", "pytest (>=6)", "pytest-asyncio (>=0.24)", "pytest-cov", "pytest-timeout"]
+discord = ["requests"]
+notebook = ["ipywidgets (>=6)"]
+slack = ["slack-sdk"]
+telegram = ["requests"]
+
+[[package]]
+name = "traceloop-sdk"
+version = "0.40.14"
+description = "Traceloop Software Development Kit (SDK) for Python"
+optional = false
+python-versions = "<4,>=3.10"
+groups = ["main"]
+files = [
+ {file = "traceloop_sdk-0.40.14-py3-none-any.whl", hash = "sha256:35f84563fb6ec4100d33e98082bdbbf5cf59adbbde409112a4fec6bc5e2e7950"},
+ {file = "traceloop_sdk-0.40.14.tar.gz", hash = "sha256:8d4a069890eaf2969067b939192092fee5bf7b5d47c567256208663dc9a49083"},
+]
+
+[package.dependencies]
+aiohttp = ">=3.11.11,<4.0.0"
+colorama = ">=0.4.6,<0.5.0"
+deprecated = ">=1.2.14,<2.0.0"
+jinja2 = ">=3.1.5,<4.0.0"
+opentelemetry-api = ">=1.28.0,<2.0.0"
+opentelemetry-exporter-otlp-proto-grpc = ">=1.28.0,<2.0.0"
+opentelemetry-exporter-otlp-proto-http = ">=1.28.0,<2.0.0"
+opentelemetry-instrumentation-alephalpha = "0.40.14"
+opentelemetry-instrumentation-anthropic = "0.40.14"
+opentelemetry-instrumentation-bedrock = "0.40.14"
+opentelemetry-instrumentation-chromadb = "0.40.14"
+opentelemetry-instrumentation-cohere = "0.40.14"
+opentelemetry-instrumentation-crewai = "0.40.14"
+opentelemetry-instrumentation-google-generativeai = "0.40.14"
+opentelemetry-instrumentation-groq = "0.40.14"
+opentelemetry-instrumentation-haystack = "0.40.14"
+opentelemetry-instrumentation-lancedb = "0.40.14"
+opentelemetry-instrumentation-langchain = "0.40.14"
+opentelemetry-instrumentation-llamaindex = "0.40.14"
+opentelemetry-instrumentation-logging = ">=0.50b0"
+opentelemetry-instrumentation-marqo = "0.40.14"
+opentelemetry-instrumentation-mcp = "0.40.14"
+opentelemetry-instrumentation-milvus = "0.40.14"
+opentelemetry-instrumentation-mistralai = "0.40.14"
+opentelemetry-instrumentation-ollama = "0.40.14"
+opentelemetry-instrumentation-openai = "0.40.14"
+opentelemetry-instrumentation-pinecone = "0.40.14"
+opentelemetry-instrumentation-qdrant = "0.40.14"
+opentelemetry-instrumentation-redis = ">=0.50b0"
+opentelemetry-instrumentation-replicate = "0.40.14"
+opentelemetry-instrumentation-requests = ">=0.50b0"
+opentelemetry-instrumentation-sagemaker = "0.40.14"
+opentelemetry-instrumentation-sqlalchemy = ">=0.50b0"
+opentelemetry-instrumentation-threading = ">=0.50b0"
+opentelemetry-instrumentation-together = "0.40.14"
+opentelemetry-instrumentation-transformers = "0.40.14"
+opentelemetry-instrumentation-urllib3 = ">=0.50b0"
+opentelemetry-instrumentation-vertexai = "0.40.14"
+opentelemetry-instrumentation-watsonx = "0.40.14"
+opentelemetry-instrumentation-weaviate = "0.40.14"
+opentelemetry-sdk = ">=1.28.0,<2.0.0"
+opentelemetry-semantic-conventions-ai = "0.4.9"
+posthog = ">3.0.2,<4"
+pydantic = ">=1"
+tenacity = ">=8.2.3,<10.0"
+
+[[package]]
+name = "typing-extensions"
+version = "4.14.1"
+description = "Backported and Experimental Type Hints for Python 3.10+"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76"},
+ {file = "typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36"},
+]
+
+[[package]]
+name = "typing-inspect"
+version = "0.9.0"
+description = "Runtime inspection utilities for typing module."
+optional = false
+python-versions = "*"
+groups = ["main"]
+files = [
+ {file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"},
+ {file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"},
+]
+
+[package.dependencies]
+mypy-extensions = ">=0.3.0"
+typing-extensions = ">=3.7.4"
+
+[[package]]
+name = "typing-inspection"
+version = "0.4.1"
+description = "Runtime typing introspection tools"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51"},
+ {file = "typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28"},
+]
+
+[package.dependencies]
+typing-extensions = ">=4.12.0"
+
+[[package]]
+name = "uptrace"
+version = "1.34.0"
+description = "OpenTelemetry Python distribution for Uptrace"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "uptrace-1.34.0-py3-none-any.whl", hash = "sha256:8b23676d094fcdbbd148ef1eb68ea7146d53c8261b17e723abc103885ef650c4"},
+ {file = "uptrace-1.34.0.tar.gz", hash = "sha256:5f30f51966c4a92f42b060e785e09dd02fb923846abb6450f25514f20275a1a8"},
+]
+
+[package.dependencies]
+opentelemetry-api = ">=1.34.1,<1.35.0"
+opentelemetry-exporter-otlp = ">=1.34.1,<1.35.0"
+opentelemetry-instrumentation = ">=0.55b1,<1.0"
+opentelemetry-sdk = ">=1.34.1,<1.35.0"
+
+[[package]]
+name = "urllib3"
+version = "1.26.20"
+description = "HTTP library with thread-safe connection pooling, file post, and more."
+optional = false
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
+groups = ["main"]
+markers = "platform_python_implementation == \"PyPy\""
+files = [
+ {file = "urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e"},
+ {file = "urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32"},
+]
+
+[package.extras]
+brotli = ["brotli (==1.0.9) ; os_name != \"nt\" and python_version < \"3\" and platform_python_implementation == \"CPython\"", "brotli (>=1.0.9) ; python_version >= \"3\" and platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; (os_name != \"nt\" or python_version >= \"3\") and platform_python_implementation != \"CPython\"", "brotlipy (>=0.6.0) ; os_name == \"nt\" and python_version < \"3\""]
+secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress ; python_version == \"2.7\"", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
+socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
+
+[[package]]
+name = "urllib3"
+version = "2.5.0"
+description = "HTTP library with thread-safe connection pooling, file post, and more."
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+markers = "platform_python_implementation != \"PyPy\""
+files = [
+ {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"},
+ {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"},
+]
+
+[package.extras]
+brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""]
+h2 = ["h2 (>=4,<5)"]
+socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
+zstd = ["zstandard (>=0.18.0)"]
+
+[[package]]
+name = "uvicorn"
+version = "0.35.0"
+description = "The lightning-fast ASGI server."
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "uvicorn-0.35.0-py3-none-any.whl", hash = "sha256:197535216b25ff9b785e29a0b79199f55222193d47f820816e7da751e9bc8d4a"},
+ {file = "uvicorn-0.35.0.tar.gz", hash = "sha256:bc662f087f7cf2ce11a1d7fd70b90c9f98ef2e2831556dd078d131b96cc94a01"},
+]
+
+[package.dependencies]
+click = ">=7.0"
+h11 = ">=0.8"
+
+[package.extras]
+standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"]
+
+[[package]]
+name = "vcrpy"
+version = "7.0.0"
+description = "Automatically mock your HTTP interactions to simplify and speed up testing"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "vcrpy-7.0.0-py2.py3-none-any.whl", hash = "sha256:55791e26c18daa363435054d8b35bd41a4ac441b6676167635d1b37a71dbe124"},
+ {file = "vcrpy-7.0.0.tar.gz", hash = "sha256:176391ad0425edde1680c5b20738ea3dc7fb942520a48d2993448050986b3a50"},
+]
+
+[package.dependencies]
+PyYAML = "*"
+urllib3 = [
+ {version = "<2", markers = "platform_python_implementation == \"PyPy\""},
+ {version = "*", markers = "platform_python_implementation != \"PyPy\" and python_version >= \"3.10\""},
+]
+wrapt = "*"
+yarl = "*"
+
+[package.extras]
+tests = ["Werkzeug (==2.0.3)", "aiohttp", "boto3", "httplib2", "httpx", "pytest", "pytest-aiohttp", "pytest-asyncio", "pytest-cov", "pytest-httpbin", "requests (>=2.22.0)", "tornado", "urllib3"]
+
+[[package]]
+name = "watchfiles"
+version = "0.20.0"
+description = "Simple, modern and high performance file watching and code reload in python."
+optional = false
+python-versions = ">=3.7"
+groups = ["main"]
+files = [
+ {file = "watchfiles-0.20.0-cp37-abi3-macosx_10_7_x86_64.whl", hash = "sha256:3796312bd3587e14926013612b23066912cf45a14af71cf2b20db1c12dadf4e9"},
+ {file = "watchfiles-0.20.0-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:d0002d81c89a662b595645fb684a371b98ff90a9c7d8f8630c82f0fde8310458"},
+ {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:570848706440373b4cd8017f3e850ae17f76dbdf1e9045fc79023b11e1afe490"},
+ {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a0351d20d03c6f7ad6b2e8a226a5efafb924c7755ee1e34f04c77c3682417fa"},
+ {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:007dcc4a401093010b389c044e81172c8a2520dba257c88f8828b3d460c6bb38"},
+ {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0d82dbc1832da83e441d112069833eedd4cf583d983fb8dd666fbefbea9d99c0"},
+ {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99f4c65fd2fce61a571b2a6fcf747d6868db0bef8a934e8ca235cc8533944d95"},
+ {file = "watchfiles-0.20.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5392dd327a05f538c56edb1c6ebba6af91afc81b40822452342f6da54907bbdf"},
+ {file = "watchfiles-0.20.0-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:08dc702529bb06a2b23859110c214db245455532da5eaea602921687cfcd23db"},
+ {file = "watchfiles-0.20.0-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:7d4e66a857621584869cfbad87039e65dadd7119f0d9bb9dbc957e089e32c164"},
+ {file = "watchfiles-0.20.0-cp37-abi3-win32.whl", hash = "sha256:a03d1e6feb7966b417f43c3e3783188167fd69c2063e86bad31e62c4ea794cc5"},
+ {file = "watchfiles-0.20.0-cp37-abi3-win_amd64.whl", hash = "sha256:eccc8942bcdc7d638a01435d915b913255bbd66f018f1af051cd8afddb339ea3"},
+ {file = "watchfiles-0.20.0-cp37-abi3-win_arm64.whl", hash = "sha256:b17d4176c49d207865630da5b59a91779468dd3e08692fe943064da260de2c7c"},
+ {file = "watchfiles-0.20.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d97db179f7566dcf145c5179ddb2ae2a4450e3a634eb864b09ea04e68c252e8e"},
+ {file = "watchfiles-0.20.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:835df2da7a5df5464c4a23b2d963e1a9d35afa422c83bf4ff4380b3114603644"},
+ {file = "watchfiles-0.20.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:608cd94a8767f49521901aff9ae0c92cc8f5a24d528db7d6b0295290f9d41193"},
+ {file = "watchfiles-0.20.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89d1de8218874925bce7bb2ae9657efc504411528930d7a83f98b1749864f2ef"},
+ {file = "watchfiles-0.20.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:13f995d5152a8ba4ed7c2bbbaeee4e11a5944defc7cacd0ccb4dcbdcfd78029a"},
+ {file = "watchfiles-0.20.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:9b5c8d3be7b502f8c43a33c63166ada8828dbb0c6d49c8f9ce990a96de2f5a49"},
+ {file = "watchfiles-0.20.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e43af4464daa08723c04b43cf978ab86cc55c684c16172622bdac64b34e36af0"},
+ {file = "watchfiles-0.20.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87d9e1f75c4f86c93d73b5bd1ebe667558357548f11b4f8af4e0e272f79413ce"},
+ {file = "watchfiles-0.20.0.tar.gz", hash = "sha256:728575b6b94c90dd531514677201e8851708e6e4b5fe7028ac506a200b622019"},
+]
+
+[package.dependencies]
+anyio = ">=3.0.0"
+
+[[package]]
+name = "wrapt"
+version = "1.17.2"
+description = "Module for decorators, wrappers and monkey patching."
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3d57c572081fed831ad2d26fd430d565b76aa277ed1d30ff4d40670b1c0dd984"},
+ {file = "wrapt-1.17.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5e251054542ae57ac7f3fba5d10bfff615b6c2fb09abeb37d2f1463f841ae22"},
+ {file = "wrapt-1.17.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:80dd7db6a7cb57ffbc279c4394246414ec99537ae81ffd702443335a61dbf3a7"},
+ {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a6e821770cf99cc586d33833b2ff32faebdbe886bd6322395606cf55153246c"},
+ {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b60fb58b90c6d63779cb0c0c54eeb38941bae3ecf7a73c764c52c88c2dcb9d72"},
+ {file = "wrapt-1.17.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b870b5df5b71d8c3359d21be8f0d6c485fa0ebdb6477dda51a1ea54a9b558061"},
+ {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4011d137b9955791f9084749cba9a367c68d50ab8d11d64c50ba1688c9b457f2"},
+ {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1473400e5b2733e58b396a04eb7f35f541e1fb976d0c0724d0223dd607e0f74c"},
+ {file = "wrapt-1.17.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3cedbfa9c940fdad3e6e941db7138e26ce8aad38ab5fe9dcfadfed9db7a54e62"},
+ {file = "wrapt-1.17.2-cp310-cp310-win32.whl", hash = "sha256:582530701bff1dec6779efa00c516496968edd851fba224fbd86e46cc6b73563"},
+ {file = "wrapt-1.17.2-cp310-cp310-win_amd64.whl", hash = "sha256:58705da316756681ad3c9c73fd15499aa4d8c69f9fd38dc8a35e06c12468582f"},
+ {file = "wrapt-1.17.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ff04ef6eec3eee8a5efef2401495967a916feaa353643defcc03fc74fe213b58"},
+ {file = "wrapt-1.17.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4db983e7bca53819efdbd64590ee96c9213894272c776966ca6306b73e4affda"},
+ {file = "wrapt-1.17.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9abc77a4ce4c6f2a3168ff34b1da9b0f311a8f1cfd694ec96b0603dff1c79438"},
+ {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b929ac182f5ace000d459c59c2c9c33047e20e935f8e39371fa6e3b85d56f4a"},
+ {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f09b286faeff3c750a879d336fb6d8713206fc97af3adc14def0cdd349df6000"},
+ {file = "wrapt-1.17.2-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a7ed2d9d039bd41e889f6fb9364554052ca21ce823580f6a07c4ec245c1f5d6"},
+ {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:129a150f5c445165ff941fc02ee27df65940fcb8a22a61828b1853c98763a64b"},
+ {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1fb5699e4464afe5c7e65fa51d4f99e0b2eadcc176e4aa33600a3df7801d6662"},
+ {file = "wrapt-1.17.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9a2bce789a5ea90e51a02dfcc39e31b7f1e662bc3317979aa7e5538e3a034f72"},
+ {file = "wrapt-1.17.2-cp311-cp311-win32.whl", hash = "sha256:4afd5814270fdf6380616b321fd31435a462019d834f83c8611a0ce7484c7317"},
+ {file = "wrapt-1.17.2-cp311-cp311-win_amd64.whl", hash = "sha256:acc130bc0375999da18e3d19e5a86403667ac0c4042a094fefb7eec8ebac7cf3"},
+ {file = "wrapt-1.17.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d5e2439eecc762cd85e7bd37161d4714aa03a33c5ba884e26c81559817ca0925"},
+ {file = "wrapt-1.17.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fc7cb4c1c744f8c05cd5f9438a3caa6ab94ce8344e952d7c45a8ed59dd88392"},
+ {file = "wrapt-1.17.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fdbdb757d5390f7c675e558fd3186d590973244fab0c5fe63d373ade3e99d40"},
+ {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb1d0dbf99411f3d871deb6faa9aabb9d4e744d67dcaaa05399af89d847a91d"},
+ {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d18a4865f46b8579d44e4fe1e2bcbc6472ad83d98e22a26c963d46e4c125ef0b"},
+ {file = "wrapt-1.17.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc570b5f14a79734437cb7b0500376b6b791153314986074486e0b0fa8d71d98"},
+ {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6d9187b01bebc3875bac9b087948a2bccefe464a7d8f627cf6e48b1bbae30f82"},
+ {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9e8659775f1adf02eb1e6f109751268e493c73716ca5761f8acb695e52a756ae"},
+ {file = "wrapt-1.17.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8b2816ebef96d83657b56306152a93909a83f23994f4b30ad4573b00bd11bb9"},
+ {file = "wrapt-1.17.2-cp312-cp312-win32.whl", hash = "sha256:468090021f391fe0056ad3e807e3d9034e0fd01adcd3bdfba977b6fdf4213ea9"},
+ {file = "wrapt-1.17.2-cp312-cp312-win_amd64.whl", hash = "sha256:ec89ed91f2fa8e3f52ae53cd3cf640d6feff92ba90d62236a81e4e563ac0e991"},
+ {file = "wrapt-1.17.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6ed6ffac43aecfe6d86ec5b74b06a5be33d5bb9243d055141e8cabb12aa08125"},
+ {file = "wrapt-1.17.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:35621ae4c00e056adb0009f8e86e28eb4a41a4bfa8f9bfa9fca7d343fe94f998"},
+ {file = "wrapt-1.17.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a604bf7a053f8362d27eb9fefd2097f82600b856d5abe996d623babd067b1ab5"},
+ {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cbabee4f083b6b4cd282f5b817a867cf0b1028c54d445b7ec7cfe6505057cf8"},
+ {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:49703ce2ddc220df165bd2962f8e03b84c89fee2d65e1c24a7defff6f988f4d6"},
+ {file = "wrapt-1.17.2-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8112e52c5822fc4253f3901b676c55ddf288614dc7011634e2719718eaa187dc"},
+ {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9fee687dce376205d9a494e9c121e27183b2a3df18037f89d69bd7b35bcf59e2"},
+ {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:18983c537e04d11cf027fbb60a1e8dfd5190e2b60cc27bc0808e653e7b218d1b"},
+ {file = "wrapt-1.17.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:703919b1633412ab54bcf920ab388735832fdcb9f9a00ae49387f0fe67dad504"},
+ {file = "wrapt-1.17.2-cp313-cp313-win32.whl", hash = "sha256:abbb9e76177c35d4e8568e58650aa6926040d6a9f6f03435b7a522bf1c487f9a"},
+ {file = "wrapt-1.17.2-cp313-cp313-win_amd64.whl", hash = "sha256:69606d7bb691b50a4240ce6b22ebb319c1cfb164e5f6569835058196e0f3a845"},
+ {file = "wrapt-1.17.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:4a721d3c943dae44f8e243b380cb645a709ba5bd35d3ad27bc2ed947e9c68192"},
+ {file = "wrapt-1.17.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:766d8bbefcb9e00c3ac3b000d9acc51f1b399513f44d77dfe0eb026ad7c9a19b"},
+ {file = "wrapt-1.17.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e496a8ce2c256da1eb98bd15803a79bee00fc351f5dfb9ea82594a3f058309e0"},
+ {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d615e4fe22f4ad3528448c193b218e077656ca9ccb22ce2cb20db730f8d306"},
+ {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a5aaeff38654462bc4b09023918b7f21790efb807f54c000a39d41d69cf552cb"},
+ {file = "wrapt-1.17.2-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a7d15bbd2bc99e92e39f49a04653062ee6085c0e18b3b7512a4f2fe91f2d681"},
+ {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e3890b508a23299083e065f435a492b5435eba6e304a7114d2f919d400888cc6"},
+ {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8c8b293cd65ad716d13d8dd3624e42e5a19cc2a2f1acc74b30c2c13f15cb61a6"},
+ {file = "wrapt-1.17.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c82b8785d98cdd9fed4cac84d765d234ed3251bd6afe34cb7ac523cb93e8b4f"},
+ {file = "wrapt-1.17.2-cp313-cp313t-win32.whl", hash = "sha256:13e6afb7fe71fe7485a4550a8844cc9ffbe263c0f1a1eea569bc7091d4898555"},
+ {file = "wrapt-1.17.2-cp313-cp313t-win_amd64.whl", hash = "sha256:eaf675418ed6b3b31c7a989fd007fa7c3be66ce14e5c3b27336383604c9da85c"},
+ {file = "wrapt-1.17.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5c803c401ea1c1c18de70a06a6f79fcc9c5acfc79133e9869e730ad7f8ad8ef9"},
+ {file = "wrapt-1.17.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f917c1180fdb8623c2b75a99192f4025e412597c50b2ac870f156de8fb101119"},
+ {file = "wrapt-1.17.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ecc840861360ba9d176d413a5489b9a0aff6d6303d7e733e2c4623cfa26904a6"},
+ {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb87745b2e6dc56361bfde481d5a378dc314b252a98d7dd19a651a3fa58f24a9"},
+ {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58455b79ec2661c3600e65c0a716955adc2410f7383755d537584b0de41b1d8a"},
+ {file = "wrapt-1.17.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b4e42a40a5e164cbfdb7b386c966a588b1047558a990981ace551ed7e12ca9c2"},
+ {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:91bd7d1773e64019f9288b7a5101f3ae50d3d8e6b1de7edee9c2ccc1d32f0c0a"},
+ {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:bb90fb8bda722a1b9d48ac1e6c38f923ea757b3baf8ebd0c82e09c5c1a0e7a04"},
+ {file = "wrapt-1.17.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:08e7ce672e35efa54c5024936e559469436f8b8096253404faeb54d2a878416f"},
+ {file = "wrapt-1.17.2-cp38-cp38-win32.whl", hash = "sha256:410a92fefd2e0e10d26210e1dfb4a876ddaf8439ef60d6434f21ef8d87efc5b7"},
+ {file = "wrapt-1.17.2-cp38-cp38-win_amd64.whl", hash = "sha256:95c658736ec15602da0ed73f312d410117723914a5c91a14ee4cdd72f1d790b3"},
+ {file = "wrapt-1.17.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99039fa9e6306880572915728d7f6c24a86ec57b0a83f6b2491e1d8ab0235b9a"},
+ {file = "wrapt-1.17.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2696993ee1eebd20b8e4ee4356483c4cb696066ddc24bd70bcbb80fa56ff9061"},
+ {file = "wrapt-1.17.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:612dff5db80beef9e649c6d803a8d50c409082f1fedc9dbcdfde2983b2025b82"},
+ {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62c2caa1585c82b3f7a7ab56afef7b3602021d6da34fbc1cf234ff139fed3cd9"},
+ {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c958bcfd59bacc2d0249dcfe575e71da54f9dcf4a8bdf89c4cb9a68a1170d73f"},
+ {file = "wrapt-1.17.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc78a84e2dfbc27afe4b2bd7c80c8db9bca75cc5b85df52bfe634596a1da846b"},
+ {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ba0f0eb61ef00ea10e00eb53a9129501f52385c44853dbd6c4ad3f403603083f"},
+ {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1e1fe0e6ab7775fd842bc39e86f6dcfc4507ab0ffe206093e76d61cde37225c8"},
+ {file = "wrapt-1.17.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c86563182421896d73858e08e1db93afdd2b947a70064b813d515d66549e15f9"},
+ {file = "wrapt-1.17.2-cp39-cp39-win32.whl", hash = "sha256:f393cda562f79828f38a819f4788641ac7c4085f30f1ce1a68672baa686482bb"},
+ {file = "wrapt-1.17.2-cp39-cp39-win_amd64.whl", hash = "sha256:36ccae62f64235cf8ddb682073a60519426fdd4725524ae38874adf72b5f2aeb"},
+ {file = "wrapt-1.17.2-py3-none-any.whl", hash = "sha256:b18f2d1533a71f069c7f82d524a52599053d4c7166e9dd374ae2136b7f40f7c8"},
+ {file = "wrapt-1.17.2.tar.gz", hash = "sha256:41388e9d4d1522446fe79d3213196bd9e3b301a336965b9e27ca2788ebd122f3"},
+]
+
+[[package]]
+name = "wsproto"
+version = "1.2.0"
+description = "WebSockets state-machine based protocol implementation"
+optional = false
+python-versions = ">=3.7.0"
+groups = ["main"]
+files = [
+ {file = "wsproto-1.2.0-py3-none-any.whl", hash = "sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"},
+ {file = "wsproto-1.2.0.tar.gz", hash = "sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065"},
+]
+
+[package.dependencies]
+h11 = ">=0.9.0,<1"
+
+[[package]]
+name = "xxhash"
+version = "3.5.0"
+description = "Python binding for xxHash"
+optional = false
+python-versions = ">=3.7"
+groups = ["main"]
+files = [
+ {file = "xxhash-3.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ece616532c499ee9afbb83078b1b952beffef121d989841f7f4b3dc5ac0fd212"},
+ {file = "xxhash-3.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3171f693dbc2cef6477054a665dc255d996646b4023fe56cb4db80e26f4cc520"},
+ {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c5d3e570ef46adaf93fc81b44aca6002b5a4d8ca11bd0580c07eac537f36680"},
+ {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7cb29a034301e2982df8b1fe6328a84f4b676106a13e9135a0d7e0c3e9f806da"},
+ {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d0d307d27099bb0cbeea7260eb39ed4fdb99c5542e21e94bb6fd29e49c57a23"},
+ {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0342aafd421795d740e514bc9858ebddfc705a75a8c5046ac56d85fe97bf196"},
+ {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dbbd9892c5ebffeca1ed620cf0ade13eb55a0d8c84e0751a6653adc6ac40d0c"},
+ {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4cc2d67fdb4d057730c75a64c5923abfa17775ae234a71b0200346bfb0a7f482"},
+ {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ec28adb204b759306a3d64358a5e5c07d7b1dd0ccbce04aa76cb9377b7b70296"},
+ {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:1328f6d8cca2b86acb14104e381225a3d7b42c92c4b86ceae814e5c400dbb415"},
+ {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8d47ebd9f5d9607fd039c1fbf4994e3b071ea23eff42f4ecef246ab2b7334198"},
+ {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b96d559e0fcddd3343c510a0fe2b127fbff16bf346dd76280b82292567523442"},
+ {file = "xxhash-3.5.0-cp310-cp310-win32.whl", hash = "sha256:61c722ed8d49ac9bc26c7071eeaa1f6ff24053d553146d5df031802deffd03da"},
+ {file = "xxhash-3.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:9bed5144c6923cc902cd14bb8963f2d5e034def4486ab0bbe1f58f03f042f9a9"},
+ {file = "xxhash-3.5.0-cp310-cp310-win_arm64.whl", hash = "sha256:893074d651cf25c1cc14e3bea4fceefd67f2921b1bb8e40fcfeba56820de80c6"},
+ {file = "xxhash-3.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02c2e816896dc6f85922ced60097bcf6f008dedfc5073dcba32f9c8dd786f3c1"},
+ {file = "xxhash-3.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6027dcd885e21581e46d3c7f682cfb2b870942feeed58a21c29583512c3f09f8"},
+ {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1308fa542bbdbf2fa85e9e66b1077eea3a88bef38ee8a06270b4298a7a62a166"},
+ {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c28b2fdcee797e1c1961cd3bcd3d545cab22ad202c846235197935e1df2f8ef7"},
+ {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:924361811732ddad75ff23e90efd9ccfda4f664132feecb90895bade6a1b4623"},
+ {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89997aa1c4b6a5b1e5b588979d1da048a3c6f15e55c11d117a56b75c84531f5a"},
+ {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:685c4f4e8c59837de103344eb1c8a3851f670309eb5c361f746805c5471b8c88"},
+ {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dbd2ecfbfee70bc1a4acb7461fa6af7748ec2ab08ac0fa298f281c51518f982c"},
+ {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:25b5a51dc3dfb20a10833c8eee25903fd2e14059e9afcd329c9da20609a307b2"},
+ {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a8fb786fb754ef6ff8c120cb96629fb518f8eb5a61a16aac3a979a9dbd40a084"},
+ {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a905ad00ad1e1c34fe4e9d7c1d949ab09c6fa90c919860c1534ff479f40fd12d"},
+ {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:963be41bcd49f53af6d795f65c0da9b4cc518c0dd9c47145c98f61cb464f4839"},
+ {file = "xxhash-3.5.0-cp311-cp311-win32.whl", hash = "sha256:109b436096d0a2dd039c355fa3414160ec4d843dfecc64a14077332a00aeb7da"},
+ {file = "xxhash-3.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:b702f806693201ad6c0a05ddbbe4c8f359626d0b3305f766077d51388a6bac58"},
+ {file = "xxhash-3.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:c4dcb4120d0cc3cc448624147dba64e9021b278c63e34a38789b688fd0da9bf3"},
+ {file = "xxhash-3.5.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:14470ace8bd3b5d51318782cd94e6f94431974f16cb3b8dc15d52f3b69df8e00"},
+ {file = "xxhash-3.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:59aa1203de1cb96dbeab595ded0ad0c0056bb2245ae11fac11c0ceea861382b9"},
+ {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08424f6648526076e28fae6ea2806c0a7d504b9ef05ae61d196d571e5c879c84"},
+ {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:61a1ff00674879725b194695e17f23d3248998b843eb5e933007ca743310f793"},
+ {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2f2c61bee5844d41c3eb015ac652a0229e901074951ae48581d58bfb2ba01be"},
+ {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d32a592cac88d18cc09a89172e1c32d7f2a6e516c3dfde1b9adb90ab5df54a6"},
+ {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70dabf941dede727cca579e8c205e61121afc9b28516752fd65724be1355cc90"},
+ {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e5d0ddaca65ecca9c10dcf01730165fd858533d0be84c75c327487c37a906a27"},
+ {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e5b5e16c5a480fe5f59f56c30abdeba09ffd75da8d13f6b9b6fd224d0b4d0a2"},
+ {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149b7914451eb154b3dfaa721315117ea1dac2cc55a01bfbd4df7c68c5dd683d"},
+ {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:eade977f5c96c677035ff39c56ac74d851b1cca7d607ab3d8f23c6b859379cab"},
+ {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fa9f547bd98f5553d03160967866a71056a60960be00356a15ecc44efb40ba8e"},
+ {file = "xxhash-3.5.0-cp312-cp312-win32.whl", hash = "sha256:f7b58d1fd3551b8c80a971199543379be1cee3d0d409e1f6d8b01c1a2eebf1f8"},
+ {file = "xxhash-3.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:fa0cafd3a2af231b4e113fba24a65d7922af91aeb23774a8b78228e6cd785e3e"},
+ {file = "xxhash-3.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:586886c7e89cb9828bcd8a5686b12e161368e0064d040e225e72607b43858ba2"},
+ {file = "xxhash-3.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:37889a0d13b0b7d739cfc128b1c902f04e32de17b33d74b637ad42f1c55101f6"},
+ {file = "xxhash-3.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:97a662338797c660178e682f3bc180277b9569a59abfb5925e8620fba00b9fc5"},
+ {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f85e0108d51092bdda90672476c7d909c04ada6923c14ff9d913c4f7dc8a3bc"},
+ {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2fd827b0ba763ac919440042302315c564fdb797294d86e8cdd4578e3bc7f3"},
+ {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:82085c2abec437abebf457c1d12fccb30cc8b3774a0814872511f0f0562c768c"},
+ {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07fda5de378626e502b42b311b049848c2ef38784d0d67b6f30bb5008642f8eb"},
+ {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c279f0d2b34ef15f922b77966640ade58b4ccdfef1c4d94b20f2a364617a493f"},
+ {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:89e66ceed67b213dec5a773e2f7a9e8c58f64daeb38c7859d8815d2c89f39ad7"},
+ {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bcd51708a633410737111e998ceb3b45d3dbc98c0931f743d9bb0a209033a326"},
+ {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ff2c0a34eae7df88c868be53a8dd56fbdf592109e21d4bfa092a27b0bf4a7bf"},
+ {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4e28503dccc7d32e0b9817aa0cbfc1f45f563b2c995b7a66c4c8a0d232e840c7"},
+ {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a6c50017518329ed65a9e4829154626f008916d36295b6a3ba336e2458824c8c"},
+ {file = "xxhash-3.5.0-cp313-cp313-win32.whl", hash = "sha256:53a068fe70301ec30d868ece566ac90d873e3bb059cf83c32e76012c889b8637"},
+ {file = "xxhash-3.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:80babcc30e7a1a484eab952d76a4f4673ff601f54d5142c26826502740e70b43"},
+ {file = "xxhash-3.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:4811336f1ce11cac89dcbd18f3a25c527c16311709a89313c3acaf771def2d4b"},
+ {file = "xxhash-3.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6e5f70f6dca1d3b09bccb7daf4e087075ff776e3da9ac870f86ca316736bb4aa"},
+ {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e76e83efc7b443052dd1e585a76201e40b3411fe3da7af4fe434ec51b2f163b"},
+ {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33eac61d0796ca0591f94548dcfe37bb193671e0c9bcf065789b5792f2eda644"},
+ {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ec70a89be933ea49222fafc3999987d7899fc676f688dd12252509434636622"},
+ {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86b8e7f703ec6ff4f351cfdb9f428955859537125904aa8c963604f2e9d3e7"},
+ {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0adfbd36003d9f86c8c97110039f7539b379f28656a04097e7434d3eaf9aa131"},
+ {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:63107013578c8a730419adc05608756c3fa640bdc6abe806c3123a49fb829f43"},
+ {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:683b94dbd1ca67557850b86423318a2e323511648f9f3f7b1840408a02b9a48c"},
+ {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:5d2a01dcce81789cf4b12d478b5464632204f4c834dc2d064902ee27d2d1f0ee"},
+ {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:a9d360a792cbcce2fe7b66b8d51274ec297c53cbc423401480e53b26161a290d"},
+ {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:f0b48edbebea1b7421a9c687c304f7b44d0677c46498a046079d445454504737"},
+ {file = "xxhash-3.5.0-cp37-cp37m-win32.whl", hash = "sha256:7ccb800c9418e438b44b060a32adeb8393764da7441eb52aa2aa195448935306"},
+ {file = "xxhash-3.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c3bc7bf8cb8806f8d1c9bf149c18708cb1c406520097d6b0a73977460ea03602"},
+ {file = "xxhash-3.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:74752ecaa544657d88b1d1c94ae68031e364a4d47005a90288f3bab3da3c970f"},
+ {file = "xxhash-3.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:dee1316133c9b463aa81aca676bc506d3f80d8f65aeb0bba2b78d0b30c51d7bd"},
+ {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:602d339548d35a8579c6b013339fb34aee2df9b4e105f985443d2860e4d7ffaa"},
+ {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:695735deeddfb35da1677dbc16a083445360e37ff46d8ac5c6fcd64917ff9ade"},
+ {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1030a39ba01b0c519b1a82f80e8802630d16ab95dc3f2b2386a0b5c8ed5cbb10"},
+ {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5bc08f33c4966f4eb6590d6ff3ceae76151ad744576b5fc6c4ba8edd459fdec"},
+ {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:160e0c19ee500482ddfb5d5570a0415f565d8ae2b3fd69c5dcfce8a58107b1c3"},
+ {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f1abffa122452481a61c3551ab3c89d72238e279e517705b8b03847b1d93d738"},
+ {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:d5e9db7ef3ecbfc0b4733579cea45713a76852b002cf605420b12ef3ef1ec148"},
+ {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:23241ff6423378a731d84864bf923a41649dc67b144debd1077f02e6249a0d54"},
+ {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:82b833d5563fefd6fceafb1aed2f3f3ebe19f84760fdd289f8b926731c2e6e91"},
+ {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0a80ad0ffd78bef9509eee27b4a29e56f5414b87fb01a888353e3d5bda7038bd"},
+ {file = "xxhash-3.5.0-cp38-cp38-win32.whl", hash = "sha256:50ac2184ffb1b999e11e27c7e3e70cc1139047e7ebc1aa95ed12f4269abe98d4"},
+ {file = "xxhash-3.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:392f52ebbb932db566973693de48f15ce787cabd15cf6334e855ed22ea0be5b3"},
+ {file = "xxhash-3.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bfc8cdd7f33d57f0468b0614ae634cc38ab9202c6957a60e31d285a71ebe0301"},
+ {file = "xxhash-3.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e0c48b6300cd0b0106bf49169c3e0536408dfbeb1ccb53180068a18b03c662ab"},
+ {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe1a92cfbaa0a1253e339ccec42dbe6db262615e52df591b68726ab10338003f"},
+ {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33513d6cc3ed3b559134fb307aae9bdd94d7e7c02907b37896a6c45ff9ce51bd"},
+ {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eefc37f6138f522e771ac6db71a6d4838ec7933939676f3753eafd7d3f4c40bc"},
+ {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a606c8070ada8aa2a88e181773fa1ef17ba65ce5dd168b9d08038e2a61b33754"},
+ {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:42eca420c8fa072cc1dd62597635d140e78e384a79bb4944f825fbef8bfeeef6"},
+ {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:604253b2143e13218ff1ef0b59ce67f18b8bd1c4205d2ffda22b09b426386898"},
+ {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6e93a5ad22f434d7876665444a97e713a8f60b5b1a3521e8df11b98309bff833"},
+ {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:7a46e1d6d2817ba8024de44c4fd79913a90e5f7265434cef97026215b7d30df6"},
+ {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:30eb2efe6503c379b7ab99c81ba4a779748e3830241f032ab46bd182bf5873af"},
+ {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c8aa771ff2c13dd9cda8166d685d7333d389fae30a4d2bb39d63ab5775de8606"},
+ {file = "xxhash-3.5.0-cp39-cp39-win32.whl", hash = "sha256:5ed9ebc46f24cf91034544b26b131241b699edbfc99ec5e7f8f3d02d6eb7fba4"},
+ {file = "xxhash-3.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:220f3f896c6b8d0316f63f16c077d52c412619e475f9372333474ee15133a558"},
+ {file = "xxhash-3.5.0-cp39-cp39-win_arm64.whl", hash = "sha256:a7b1d8315d9b5e9f89eb2933b73afae6ec9597a258d52190944437158b49d38e"},
+ {file = "xxhash-3.5.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:2014c5b3ff15e64feecb6b713af12093f75b7926049e26a580e94dcad3c73d8c"},
+ {file = "xxhash-3.5.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fab81ef75003eda96239a23eda4e4543cedc22e34c373edcaf744e721a163986"},
+ {file = "xxhash-3.5.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2febf914ace002132aa09169cc572e0d8959d0f305f93d5828c4836f9bc5a6"},
+ {file = "xxhash-3.5.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5d3a10609c51da2a1c0ea0293fc3968ca0a18bd73838455b5bca3069d7f8e32b"},
+ {file = "xxhash-3.5.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5a74f23335b9689b66eb6dbe2a931a88fcd7a4c2cc4b1cb0edba8ce381c7a1da"},
+ {file = "xxhash-3.5.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2b4154c00eb22e4d543f472cfca430e7962a0f1d0f3778334f2e08a7ba59363c"},
+ {file = "xxhash-3.5.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d30bbc1644f726b825b3278764240f449d75f1a8bdda892e641d4a688b1494ae"},
+ {file = "xxhash-3.5.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fa0b72f2423e2aa53077e54a61c28e181d23effeaafd73fcb9c494e60930c8e"},
+ {file = "xxhash-3.5.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13de2b76c1835399b2e419a296d5b38dc4855385d9e96916299170085ef72f57"},
+ {file = "xxhash-3.5.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:0691bfcc4f9c656bcb96cc5db94b4d75980b9d5589f2e59de790091028580837"},
+ {file = "xxhash-3.5.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:297595fe6138d4da2c8ce9e72a04d73e58725bb60f3a19048bc96ab2ff31c692"},
+ {file = "xxhash-3.5.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc1276d369452040cbb943300dc8abeedab14245ea44056a2943183822513a18"},
+ {file = "xxhash-3.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2061188a1ba352fc699c82bff722f4baacb4b4b8b2f0c745d2001e56d0dfb514"},
+ {file = "xxhash-3.5.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38c384c434021e4f62b8d9ba0bc9467e14d394893077e2c66d826243025e1f81"},
+ {file = "xxhash-3.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e6a4dd644d72ab316b580a1c120b375890e4c52ec392d4aef3c63361ec4d77d1"},
+ {file = "xxhash-3.5.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:531af8845aaadcadf951b7e0c1345c6b9c68a990eeb74ff9acd8501a0ad6a1c9"},
+ {file = "xxhash-3.5.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ce379bcaa9fcc00f19affa7773084dd09f5b59947b3fb47a1ceb0179f91aaa1"},
+ {file = "xxhash-3.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd1b2281d01723f076df3c8188f43f2472248a6b63118b036e641243656b1b0f"},
+ {file = "xxhash-3.5.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c770750cc80e8694492244bca7251385188bc5597b6a39d98a9f30e8da984e0"},
+ {file = "xxhash-3.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b150b8467852e1bd844387459aa6fbe11d7f38b56e901f9f3b3e6aba0d660240"},
+ {file = "xxhash-3.5.0.tar.gz", hash = "sha256:84f2caddf951c9cbf8dc2e22a89d4ccf5d86391ac6418fe81e3c67d0cf60b45f"},
+]
+
+[[package]]
+name = "yarl"
+version = "1.20.1"
+description = "Yet another URL library"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "yarl-1.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6032e6da6abd41e4acda34d75a816012717000fa6839f37124a47fcefc49bec4"},
+ {file = "yarl-1.20.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2c7b34d804b8cf9b214f05015c4fee2ebe7ed05cf581e7192c06555c71f4446a"},
+ {file = "yarl-1.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c869f2651cc77465f6cd01d938d91a11d9ea5d798738c1dc077f3de0b5e5fed"},
+ {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62915e6688eb4d180d93840cda4110995ad50c459bf931b8b3775b37c264af1e"},
+ {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:41ebd28167bc6af8abb97fec1a399f412eec5fd61a3ccbe2305a18b84fb4ca73"},
+ {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21242b4288a6d56f04ea193adde174b7e347ac46ce6bc84989ff7c1b1ecea84e"},
+ {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bea21cdae6c7eb02ba02a475f37463abfe0a01f5d7200121b03e605d6a0439f8"},
+ {file = "yarl-1.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f8a891e4a22a89f5dde7862994485e19db246b70bb288d3ce73a34422e55b23"},
+ {file = "yarl-1.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd803820d44c8853a109a34e3660e5a61beae12970da479cf44aa2954019bf70"},
+ {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b982fa7f74c80d5c0c7b5b38f908971e513380a10fecea528091405f519b9ebb"},
+ {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:33f29ecfe0330c570d997bcf1afd304377f2e48f61447f37e846a6058a4d33b2"},
+ {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:835ab2cfc74d5eb4a6a528c57f05688099da41cf4957cf08cad38647e4a83b30"},
+ {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:46b5e0ccf1943a9a6e766b2c2b8c732c55b34e28be57d8daa2b3c1d1d4009309"},
+ {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:df47c55f7d74127d1b11251fe6397d84afdde0d53b90bedb46a23c0e534f9d24"},
+ {file = "yarl-1.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76d12524d05841276b0e22573f28d5fbcb67589836772ae9244d90dd7d66aa13"},
+ {file = "yarl-1.20.1-cp310-cp310-win32.whl", hash = "sha256:6c4fbf6b02d70e512d7ade4b1f998f237137f1417ab07ec06358ea04f69134f8"},
+ {file = "yarl-1.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:aef6c4d69554d44b7f9d923245f8ad9a707d971e6209d51279196d8e8fe1ae16"},
+ {file = "yarl-1.20.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47ee6188fea634bdfaeb2cc420f5b3b17332e6225ce88149a17c413c77ff269e"},
+ {file = "yarl-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0f6500f69e8402d513e5eedb77a4e1818691e8f45e6b687147963514d84b44b"},
+ {file = "yarl-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a8900a42fcdaad568de58887c7b2f602962356908eedb7628eaf6021a6e435b"},
+ {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bad6d131fda8ef508b36be3ece16d0902e80b88ea7200f030a0f6c11d9e508d4"},
+ {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:df018d92fe22aaebb679a7f89fe0c0f368ec497e3dda6cb81a567610f04501f1"},
+ {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f969afbb0a9b63c18d0feecf0db09d164b7a44a053e78a7d05f5df163e43833"},
+ {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:812303eb4aa98e302886ccda58d6b099e3576b1b9276161469c25803a8db277d"},
+ {file = "yarl-1.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98c4a7d166635147924aa0bf9bfe8d8abad6fffa6102de9c99ea04a1376f91e8"},
+ {file = "yarl-1.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12e768f966538e81e6e7550f9086a6236b16e26cd964cf4df35349970f3551cf"},
+ {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe41919b9d899661c5c28a8b4b0acf704510b88f27f0934ac7a7bebdd8938d5e"},
+ {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8601bc010d1d7780592f3fc1bdc6c72e2b6466ea34569778422943e1a1f3c389"},
+ {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:daadbdc1f2a9033a2399c42646fbd46da7992e868a5fe9513860122d7fe7a73f"},
+ {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:03aa1e041727cb438ca762628109ef1333498b122e4c76dd858d186a37cec845"},
+ {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:642980ef5e0fa1de5fa96d905c7e00cb2c47cb468bfcac5a18c58e27dbf8d8d1"},
+ {file = "yarl-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:86971e2795584fe8c002356d3b97ef6c61862720eeff03db2a7c86b678d85b3e"},
+ {file = "yarl-1.20.1-cp311-cp311-win32.whl", hash = "sha256:597f40615b8d25812f14562699e287f0dcc035d25eb74da72cae043bb884d773"},
+ {file = "yarl-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:26ef53a9e726e61e9cd1cda6b478f17e350fb5800b4bd1cd9fe81c4d91cfeb2e"},
+ {file = "yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9"},
+ {file = "yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a"},
+ {file = "yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2"},
+ {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee"},
+ {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819"},
+ {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16"},
+ {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6"},
+ {file = "yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd"},
+ {file = "yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a"},
+ {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38"},
+ {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef"},
+ {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f"},
+ {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8"},
+ {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a"},
+ {file = "yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004"},
+ {file = "yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5"},
+ {file = "yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698"},
+ {file = "yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a"},
+ {file = "yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3"},
+ {file = "yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7"},
+ {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691"},
+ {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31"},
+ {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28"},
+ {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653"},
+ {file = "yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5"},
+ {file = "yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02"},
+ {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53"},
+ {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc"},
+ {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04"},
+ {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4"},
+ {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b"},
+ {file = "yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1"},
+ {file = "yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7"},
+ {file = "yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c"},
+ {file = "yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d"},
+ {file = "yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf"},
+ {file = "yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3"},
+ {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d"},
+ {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c"},
+ {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1"},
+ {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce"},
+ {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3"},
+ {file = "yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be"},
+ {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16"},
+ {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513"},
+ {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f"},
+ {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390"},
+ {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458"},
+ {file = "yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e"},
+ {file = "yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d"},
+ {file = "yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f"},
+ {file = "yarl-1.20.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e42ba79e2efb6845ebab49c7bf20306c4edf74a0b20fc6b2ccdd1a219d12fad3"},
+ {file = "yarl-1.20.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:41493b9b7c312ac448b7f0a42a089dffe1d6e6e981a2d76205801a023ed26a2b"},
+ {file = "yarl-1.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f5a5928ff5eb13408c62a968ac90d43f8322fd56d87008b8f9dabf3c0f6ee983"},
+ {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30c41ad5d717b3961b2dd785593b67d386b73feca30522048d37298fee981805"},
+ {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:59febc3969b0781682b469d4aca1a5cab7505a4f7b85acf6db01fa500fa3f6ba"},
+ {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d2b6fb3622b7e5bf7a6e5b679a69326b4279e805ed1699d749739a61d242449e"},
+ {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:749d73611db8d26a6281086f859ea7ec08f9c4c56cec864e52028c8b328db723"},
+ {file = "yarl-1.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9427925776096e664c39e131447aa20ec738bdd77c049c48ea5200db2237e000"},
+ {file = "yarl-1.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff70f32aa316393eaf8222d518ce9118148eddb8a53073c2403863b41033eed5"},
+ {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c7ddf7a09f38667aea38801da8b8d6bfe81df767d9dfc8c88eb45827b195cd1c"},
+ {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:57edc88517d7fc62b174fcfb2e939fbc486a68315d648d7e74d07fac42cec240"},
+ {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:dab096ce479d5894d62c26ff4f699ec9072269d514b4edd630a393223f45a0ee"},
+ {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:14a85f3bd2d7bb255be7183e5d7d6e70add151a98edf56a770d6140f5d5f4010"},
+ {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:2c89b5c792685dd9cd3fa9761c1b9f46fc240c2a3265483acc1565769996a3f8"},
+ {file = "yarl-1.20.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:69e9b141de5511021942a6866990aea6d111c9042235de90e08f94cf972ca03d"},
+ {file = "yarl-1.20.1-cp39-cp39-win32.whl", hash = "sha256:b5f307337819cdfdbb40193cad84978a029f847b0a357fbe49f712063cfc4f06"},
+ {file = "yarl-1.20.1-cp39-cp39-win_amd64.whl", hash = "sha256:eae7bfe2069f9c1c5b05fc7fe5d612e5bbc089a39309904ee8b829e322dcad00"},
+ {file = "yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77"},
+ {file = "yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac"},
+]
+
+[package.dependencies]
+idna = ">=2.0"
+multidict = ">=4.0"
+propcache = ">=0.2.1"
+
+[[package]]
+name = "zipp"
+version = "3.23.0"
+description = "Backport of pathlib-compatible object wrapper for zip files"
+optional = false
+python-versions = ">=3.9"
+groups = ["main"]
+files = [
+ {file = "zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e"},
+ {file = "zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166"},
+]
+
+[package.extras]
+check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""]
+cover = ["pytest-cov"]
+doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
+enabler = ["pytest-enabler (>=2.2)"]
+test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more_itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"]
+type = ["pytest-mypy"]
+
+[[package]]
+name = "zstandard"
+version = "0.23.0"
+description = "Zstandard bindings for Python"
+optional = false
+python-versions = ">=3.8"
+groups = ["main"]
+files = [
+ {file = "zstandard-0.23.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bf0a05b6059c0528477fba9054d09179beb63744355cab9f38059548fedd46a9"},
+ {file = "zstandard-0.23.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fc9ca1c9718cb3b06634c7c8dec57d24e9438b2aa9a0f02b8bb36bf478538880"},
+ {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77da4c6bfa20dd5ea25cbf12c76f181a8e8cd7ea231c673828d0386b1740b8dc"},
+ {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2170c7e0367dde86a2647ed5b6f57394ea7f53545746104c6b09fc1f4223573"},
+ {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c16842b846a8d2a145223f520b7e18b57c8f476924bda92aeee3a88d11cfc391"},
+ {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:157e89ceb4054029a289fb504c98c6a9fe8010f1680de0201b3eb5dc20aa6d9e"},
+ {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:203d236f4c94cd8379d1ea61db2fce20730b4c38d7f1c34506a31b34edc87bdd"},
+ {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:dc5d1a49d3f8262be192589a4b72f0d03b72dcf46c51ad5852a4fdc67be7b9e4"},
+ {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:752bf8a74412b9892f4e5b58f2f890a039f57037f52c89a740757ebd807f33ea"},
+ {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80080816b4f52a9d886e67f1f96912891074903238fe54f2de8b786f86baded2"},
+ {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:84433dddea68571a6d6bd4fbf8ff398236031149116a7fff6f777ff95cad3df9"},
+ {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ab19a2d91963ed9e42b4e8d77cd847ae8381576585bad79dbd0a8837a9f6620a"},
+ {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:59556bf80a7094d0cfb9f5e50bb2db27fefb75d5138bb16fb052b61b0e0eeeb0"},
+ {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:27d3ef2252d2e62476389ca8f9b0cf2bbafb082a3b6bfe9d90cbcbb5529ecf7c"},
+ {file = "zstandard-0.23.0-cp310-cp310-win32.whl", hash = "sha256:5d41d5e025f1e0bccae4928981e71b2334c60f580bdc8345f824e7c0a4c2a813"},
+ {file = "zstandard-0.23.0-cp310-cp310-win_amd64.whl", hash = "sha256:519fbf169dfac1222a76ba8861ef4ac7f0530c35dd79ba5727014613f91613d4"},
+ {file = "zstandard-0.23.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:34895a41273ad33347b2fc70e1bff4240556de3c46c6ea430a7ed91f9042aa4e"},
+ {file = "zstandard-0.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:77ea385f7dd5b5676d7fd943292ffa18fbf5c72ba98f7d09fc1fb9e819b34c23"},
+ {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:983b6efd649723474f29ed42e1467f90a35a74793437d0bc64a5bf482bedfa0a"},
+ {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80a539906390591dd39ebb8d773771dc4db82ace6372c4d41e2d293f8e32b8db"},
+ {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:445e4cb5048b04e90ce96a79b4b63140e3f4ab5f662321975679b5f6360b90e2"},
+ {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd30d9c67d13d891f2360b2a120186729c111238ac63b43dbd37a5a40670b8ca"},
+ {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d20fd853fbb5807c8e84c136c278827b6167ded66c72ec6f9a14b863d809211c"},
+ {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed1708dbf4d2e3a1c5c69110ba2b4eb6678262028afd6c6fbcc5a8dac9cda68e"},
+ {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:be9b5b8659dff1f913039c2feee1aca499cfbc19e98fa12bc85e037c17ec6ca5"},
+ {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:65308f4b4890aa12d9b6ad9f2844b7ee42c7f7a4fd3390425b242ffc57498f48"},
+ {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:98da17ce9cbf3bfe4617e836d561e433f871129e3a7ac16d6ef4c680f13a839c"},
+ {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:8ed7d27cb56b3e058d3cf684d7200703bcae623e1dcc06ed1e18ecda39fee003"},
+ {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:b69bb4f51daf461b15e7b3db033160937d3ff88303a7bc808c67bbc1eaf98c78"},
+ {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:034b88913ecc1b097f528e42b539453fa82c3557e414b3de9d5632c80439a473"},
+ {file = "zstandard-0.23.0-cp311-cp311-win32.whl", hash = "sha256:f2d4380bf5f62daabd7b751ea2339c1a21d1c9463f1feb7fc2bdcea2c29c3160"},
+ {file = "zstandard-0.23.0-cp311-cp311-win_amd64.whl", hash = "sha256:62136da96a973bd2557f06ddd4e8e807f9e13cbb0bfb9cc06cfe6d98ea90dfe0"},
+ {file = "zstandard-0.23.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b4567955a6bc1b20e9c31612e615af6b53733491aeaa19a6b3b37f3b65477094"},
+ {file = "zstandard-0.23.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e172f57cd78c20f13a3415cc8dfe24bf388614324d25539146594c16d78fcc8"},
+ {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0e166f698c5a3e914947388c162be2583e0c638a4703fc6a543e23a88dea3c1"},
+ {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12a289832e520c6bd4dcaad68e944b86da3bad0d339ef7989fb7e88f92e96072"},
+ {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d50d31bfedd53a928fed6707b15a8dbeef011bb6366297cc435accc888b27c20"},
+ {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72c68dda124a1a138340fb62fa21b9bf4848437d9ca60bd35db36f2d3345f373"},
+ {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53dd9d5e3d29f95acd5de6802e909ada8d8d8cfa37a3ac64836f3bc4bc5512db"},
+ {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6a41c120c3dbc0d81a8e8adc73312d668cd34acd7725f036992b1b72d22c1772"},
+ {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:40b33d93c6eddf02d2c19f5773196068d875c41ca25730e8288e9b672897c105"},
+ {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9206649ec587e6b02bd124fb7799b86cddec350f6f6c14bc82a2b70183e708ba"},
+ {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76e79bc28a65f467e0409098fa2c4376931fd3207fbeb6b956c7c476d53746dd"},
+ {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:66b689c107857eceabf2cf3d3fc699c3c0fe8ccd18df2219d978c0283e4c508a"},
+ {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9c236e635582742fee16603042553d276cca506e824fa2e6489db04039521e90"},
+ {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a8fffdbd9d1408006baaf02f1068d7dd1f016c6bcb7538682622c556e7b68e35"},
+ {file = "zstandard-0.23.0-cp312-cp312-win32.whl", hash = "sha256:dc1d33abb8a0d754ea4763bad944fd965d3d95b5baef6b121c0c9013eaf1907d"},
+ {file = "zstandard-0.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:64585e1dba664dc67c7cdabd56c1e5685233fbb1fc1966cfba2a340ec0dfff7b"},
+ {file = "zstandard-0.23.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:576856e8594e6649aee06ddbfc738fec6a834f7c85bf7cadd1c53d4a58186ef9"},
+ {file = "zstandard-0.23.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38302b78a850ff82656beaddeb0bb989a0322a8bbb1bf1ab10c17506681d772a"},
+ {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2240ddc86b74966c34554c49d00eaafa8200a18d3a5b6ffbf7da63b11d74ee2"},
+ {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ef230a8fd217a2015bc91b74f6b3b7d6522ba48be29ad4ea0ca3a3775bf7dd5"},
+ {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:774d45b1fac1461f48698a9d4b5fa19a69d47ece02fa469825b442263f04021f"},
+ {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f77fa49079891a4aab203d0b1744acc85577ed16d767b52fc089d83faf8d8ed"},
+ {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac184f87ff521f4840e6ea0b10c0ec90c6b1dcd0bad2f1e4a9a1b4fa177982ea"},
+ {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c363b53e257246a954ebc7c488304b5592b9c53fbe74d03bc1c64dda153fb847"},
+ {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e7792606d606c8df5277c32ccb58f29b9b8603bf83b48639b7aedf6df4fe8171"},
+ {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a0817825b900fcd43ac5d05b8b3079937073d2b1ff9cf89427590718b70dd840"},
+ {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9da6bc32faac9a293ddfdcb9108d4b20416219461e4ec64dfea8383cac186690"},
+ {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fd7699e8fd9969f455ef2926221e0233f81a2542921471382e77a9e2f2b57f4b"},
+ {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d477ed829077cd945b01fc3115edd132c47e6540ddcd96ca169facff28173057"},
+ {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa6ce8b52c5987b3e34d5674b0ab529a4602b632ebab0a93b07bfb4dfc8f8a33"},
+ {file = "zstandard-0.23.0-cp313-cp313-win32.whl", hash = "sha256:a9b07268d0c3ca5c170a385a0ab9fb7fdd9f5fd866be004c4ea39e44edce47dd"},
+ {file = "zstandard-0.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:f3513916e8c645d0610815c257cbfd3242adfd5c4cfa78be514e5a3ebb42a41b"},
+ {file = "zstandard-0.23.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2ef3775758346d9ac6214123887d25c7061c92afe1f2b354f9388e9e4d48acfc"},
+ {file = "zstandard-0.23.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4051e406288b8cdbb993798b9a45c59a4896b6ecee2f875424ec10276a895740"},
+ {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2d1a054f8f0a191004675755448d12be47fa9bebbcffa3cdf01db19f2d30a54"},
+ {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f83fa6cae3fff8e98691248c9320356971b59678a17f20656a9e59cd32cee6d8"},
+ {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32ba3b5ccde2d581b1e6aa952c836a6291e8435d788f656fe5976445865ae045"},
+ {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f146f50723defec2975fb7e388ae3a024eb7151542d1599527ec2aa9cacb152"},
+ {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1bfe8de1da6d104f15a60d4a8a768288f66aa953bbe00d027398b93fb9680b26"},
+ {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:29a2bc7c1b09b0af938b7a8343174b987ae021705acabcbae560166567f5a8db"},
+ {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:61f89436cbfede4bc4e91b4397eaa3e2108ebe96d05e93d6ccc95ab5714be512"},
+ {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:53ea7cdc96c6eb56e76bb06894bcfb5dfa93b7adcf59d61c6b92674e24e2dd5e"},
+ {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:a4ae99c57668ca1e78597d8b06d5af837f377f340f4cce993b551b2d7731778d"},
+ {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:379b378ae694ba78cef921581ebd420c938936a153ded602c4fea612b7eaa90d"},
+ {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:50a80baba0285386f97ea36239855f6020ce452456605f262b2d33ac35c7770b"},
+ {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:61062387ad820c654b6a6b5f0b94484fa19515e0c5116faf29f41a6bc91ded6e"},
+ {file = "zstandard-0.23.0-cp38-cp38-win32.whl", hash = "sha256:b8c0bd73aeac689beacd4e7667d48c299f61b959475cdbb91e7d3d88d27c56b9"},
+ {file = "zstandard-0.23.0-cp38-cp38-win_amd64.whl", hash = "sha256:a05e6d6218461eb1b4771d973728f0133b2a4613a6779995df557f70794fd60f"},
+ {file = "zstandard-0.23.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3aa014d55c3af933c1315eb4bb06dd0459661cc0b15cd61077afa6489bec63bb"},
+ {file = "zstandard-0.23.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7f0804bb3799414af278e9ad51be25edf67f78f916e08afdb983e74161b916"},
+ {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb2b1ecfef1e67897d336de3a0e3f52478182d6a47eda86cbd42504c5cbd009a"},
+ {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:837bb6764be6919963ef41235fd56a6486b132ea64afe5fafb4cb279ac44f259"},
+ {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1516c8c37d3a053b01c1c15b182f3b5f5eef19ced9b930b684a73bad121addf4"},
+ {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48ef6a43b1846f6025dde6ed9fee0c24e1149c1c25f7fb0a0585572b2f3adc58"},
+ {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11e3bf3c924853a2d5835b24f03eeba7fc9b07d8ca499e247e06ff5676461a15"},
+ {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2fb4535137de7e244c230e24f9d1ec194f61721c86ebea04e1581d9d06ea1269"},
+ {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8c24f21fa2af4bb9f2c492a86fe0c34e6d2c63812a839590edaf177b7398f700"},
+ {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a8c86881813a78a6f4508ef9daf9d4995b8ac2d147dcb1a450448941398091c9"},
+ {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fe3b385d996ee0822fd46528d9f0443b880d4d05528fd26a9119a54ec3f91c69"},
+ {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:82d17e94d735c99621bf8ebf9995f870a6b3e6d14543b99e201ae046dfe7de70"},
+ {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c7c517d74bea1a6afd39aa612fa025e6b8011982a0897768a2f7c8ab4ebb78a2"},
+ {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fd7e0f1cfb70eb2f95a19b472ee7ad6d9a0a992ec0ae53286870c104ca939e5"},
+ {file = "zstandard-0.23.0-cp39-cp39-win32.whl", hash = "sha256:43da0f0092281bf501f9c5f6f3b4c975a8a0ea82de49ba3f7100e64d422a1274"},
+ {file = "zstandard-0.23.0-cp39-cp39-win_amd64.whl", hash = "sha256:f8346bfa098532bc1fb6c7ef06783e969d87a99dd1d2a5a18a892c1d7a643c58"},
+ {file = "zstandard-0.23.0.tar.gz", hash = "sha256:b2d8c62d08e7255f68f7a740bae85b3c9b8e5466baa9cbf7f57f1cde0ac6bc09"},
+]
+
+[package.dependencies]
+cffi = {version = ">=1.11", markers = "platform_python_implementation == \"PyPy\""}
+
+[package.extras]
+cffi = ["cffi (>=1.11)"]
+
+[metadata]
+lock-version = "2.1"
+python-versions = "<3.14,>=3.11"
+content-hash = "dd4de913c59e0b11d32ceb330f2f37bbf721e629b12a4ac2b1336242f69b4552"
diff --git a/examples/agent/langgraph-fsi-agent/before/public/avatars/assistant.png b/examples/agent/langgraph-fsi-agent/before/public/avatars/assistant.png
new file mode 100644
index 00000000..114532c0
Binary files /dev/null and b/examples/agent/langgraph-fsi-agent/before/public/avatars/assistant.png differ
diff --git a/examples/agent/langgraph-fsi-agent/before/public/avatars/tool.png b/examples/agent/langgraph-fsi-agent/before/public/avatars/tool.png
new file mode 100644
index 00000000..e7c061e8
Binary files /dev/null and b/examples/agent/langgraph-fsi-agent/before/public/avatars/tool.png differ
diff --git a/examples/agent/langgraph-fsi-agent/before/public/logo_dark.png b/examples/agent/langgraph-fsi-agent/before/public/logo_dark.png
new file mode 100644
index 00000000..3a3417d2
Binary files /dev/null and b/examples/agent/langgraph-fsi-agent/before/public/logo_dark.png differ
diff --git a/examples/agent/langgraph-fsi-agent/before/public/logo_light.png b/examples/agent/langgraph-fsi-agent/before/public/logo_light.png
new file mode 100644
index 00000000..379ff554
Binary files /dev/null and b/examples/agent/langgraph-fsi-agent/before/public/logo_light.png differ
diff --git a/examples/agent/langgraph-fsi-agent/before/pyproject.toml b/examples/agent/langgraph-fsi-agent/before/pyproject.toml
new file mode 100644
index 00000000..ddc50432
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/pyproject.toml
@@ -0,0 +1,25 @@
+[project]
+name = "galileo-langgraph-fsi-agent"
+version = "0.1.0"
+description = "A demo langgraph Financial Services agent with Splunk AO evaluations"
+license = "MIT"
+requires-python = "<3.14,>=3.11"
+dependencies = [
+ "chainlit~=2.5.5",
+ "grandalf>=0.8",
+ "langchain-community>=0.3.24",
+ "langchain-pinecone>=0.2.6",
+ "langchain[openai]~=0.3.18",
+ "langgraph~=0.4.7",
+ "langgraph-supervisor>=0.0.26",
+ "pinecone[asyncio]>=6.0.2",
+ "python-dotenv>=1.1.0",
+]
+
+[dependency-groups]
+dev = [
+ "ruff>=0.11.11",
+]
+
+[tool.ruff]
+line-length = 120
diff --git a/examples/agent/langgraph-fsi-agent/before/scripts/setup_pinecone.py b/examples/agent/langgraph-fsi-agent/before/scripts/setup_pinecone.py
new file mode 100644
index 00000000..4f3b81fe
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/scripts/setup_pinecone.py
@@ -0,0 +1,172 @@
+"""
+This script sets up a Pinecone index for storing and retrieving documents using the documents in the `source-docs` folder.
+
+To use this, you will need to have the following environment variables set in the .env file:
+- `PINECONE_API_KEY`: Your Pinecone API key.
+- `OPENAI_API_KEY`: Your OpenAI API key (for embeddings).
+"""
+
+import asyncio
+import os
+
+from dotenv import load_dotenv
+
+from langchain.text_splitter import RecursiveCharacterTextSplitter
+
+from langchain_community.document_loaders import DirectoryLoader, TextLoader
+from langchain_openai import OpenAIEmbeddings
+from langchain_pinecone import PineconeVectorStore
+
+from pinecone import Pinecone
+
+load_dotenv()
+
+EMBEDDINGS = OpenAIEmbeddings()
+PINECONE_API_KEY = os.getenv("PINECONE_API_KEY")
+
+
+def load_documents(path):
+ """Load all markdown documents from source-docs folder"""
+ loader = DirectoryLoader(path, glob="*.md", loader_cls=TextLoader, loader_kwargs={"encoding": "utf-8"})
+ documents = loader.load()
+ return documents
+
+
+def chunk_documents(documents):
+ """Chunk documents semantically"""
+ text_splitter = RecursiveCharacterTextSplitter(
+ chunk_size=1000,
+ chunk_overlap=200,
+ length_function=len,
+ separators=[
+ "\n\n", # Double newlines (paragraphs)
+ "\n", # Single newlines
+ " ", # Spaces
+ ".", # Sentences
+ ",", # Clauses
+ "\u200b", # Zero-width space
+ "\uff0c", # Fullwidth comma
+ "\u3001", # Ideographic comma
+ "\uff0e", # Fullwidth full stop
+ "\u3002", # Ideographic full stop
+ "", # Character-level
+ ],
+ is_separator_regex=False,
+ )
+
+ chunked_docs = text_splitter.split_documents(documents)
+ return chunked_docs
+
+
+def setup_pinecone_index(index_name: str) -> None:
+ """Initialize Pinecone and create/connect to index"""
+ pc = Pinecone(api_key=PINECONE_API_KEY)
+
+ # Check if index exists, create if not
+ if index_name not in pc.list_indexes().names():
+ print(f"Creating new index: {index_name}")
+ pc.create_index(
+ name=index_name,
+ dimension=1536, # OpenAI embeddings dimension
+ metric="cosine",
+ spec={"serverless": {"cloud": "aws", "region": "us-east-1"}},
+ )
+ else:
+ print(f"Index {index_name} already exists")
+
+
+def check_index_has_data(index) -> bool:
+ """Check if the index already contains data"""
+ try:
+ stats = index.describe_index_stats()
+ total_vector_count = stats.get("total_vector_count", 0)
+ return total_vector_count > 0
+ except Exception as e:
+ print(f"Error checking index stats: {e}")
+ return False
+
+
+def upload_to_pinecone(chunked_docs, index_name: str, force_upload: bool = False) -> PineconeVectorStore:
+ """Upload chunked documents to Pinecone"""
+
+ # Check if index has data and we're not forcing upload
+ if not force_upload:
+ pc = Pinecone(api_key=PINECONE_API_KEY)
+ index = pc.Index(index_name)
+
+ if check_index_has_data(index):
+ print(f"Index {index_name} already contains data. Skipping upload.")
+ print("Use force_upload=True to overwrite existing data.")
+ return PineconeVectorStore(index_name=index_name, embedding=EMBEDDINGS)
+
+ # Create vector store and upload
+ print(f"Uploading {len(chunked_docs)} chunks to Pinecone...")
+ vector_store = PineconeVectorStore.from_documents(documents=chunked_docs, embedding=EMBEDDINGS, index_name=index_name)
+
+ print(f"Successfully uploaded {len(chunked_docs)} document chunks to Pinecone")
+ return vector_store
+
+
+def test_retrieval(index_name: str, query: str):
+ """Test document retrieval from Pinecone"""
+ vector_store = PineconeVectorStore(index_name=index_name, embedding=EMBEDDINGS)
+
+ # Test similarity search
+ results = vector_store.similarity_search(query, k=3)
+
+ print(f"\nTest query: '{query}'")
+ print(f"Found {len(results)} relevant chunks:")
+ for i, doc in enumerate(results, 1):
+ print(f"\n{i}. {doc.page_content[:200]}...")
+
+
+bank_documents = [
+ {
+ "index_name": "credit-card-information",
+ "path": "source-docs/credit-cards",
+ "test_query": "credit card",
+ }
+]
+
+
+async def main():
+ """
+ Main function to process and upload documents asynchronously
+ """
+
+ for doc in bank_documents:
+ index_name = doc["index_name"]
+ path = doc["path"]
+ test_query = doc["test_query"]
+
+ print(f"Loading documents for {index_name} folder...")
+ loaded_documents = load_documents(path)
+ print(f"Loaded {len(loaded_documents)} documents")
+
+ print(f"Chunking documents for {index_name}...")
+ chunked_docs = chunk_documents(loaded_documents)
+ print(f"Created {len(chunked_docs)} chunks")
+
+ print(f"Setting up Pinecone for {index_name}...")
+ setup_pinecone_index(index_name)
+
+ # Only upload if index is new or doesn't have data
+ print(f"Uploading to Pinecone for {index_name}...")
+ _ = upload_to_pinecone(chunked_docs, index_name=index_name)
+
+ # Wait for Pinecone to index the data
+ print("Waiting for Pinecone to index the data...")
+ await asyncio.sleep(30)
+
+ # Test retrieval for each index
+ for doc in bank_documents:
+ index_name = doc["index_name"]
+ test_query = doc["test_query"]
+ print(f"Testing retrieval for {index_name} with query: '{test_query}'")
+ test_retrieval(index_name=index_name, query=test_query)
+
+ print("✅ Document processing and upload complete!")
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/celestial-rewards-credit-card-faq.md b/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/celestial-rewards-credit-card-faq.md
new file mode 100644
index 00000000..8e84a61c
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/celestial-rewards-credit-card-faq.md
@@ -0,0 +1,24 @@
+# Frequently Asked Questions – Celestial Rewards Credit Card
+
+## Q1: How do I apply for the card?
+
+Apply online at [www.brahebank.com/creditcards](http://www.brahebank.com/creditcards) or visit a branch.
+
+## Q2: How can I earn Celestial Points?
+
+Earn 2 points for every $1 spent on purchases.
+
+## Q3: What can I redeem Celestial Points for?
+
+- Telescopes
+- Planetarium tickets
+- Astronomy accessories
+- Educational outreach donations
+
+## Q4: Are there blackout dates for redemptions?
+
+Yes, some planetarium venues may have blackout dates.
+
+## Q5: Can I transfer my points?
+
+No, points are non-transferable and tied to the primary cardholder account.
diff --git a/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/celestial-rewards-credit-card-overview.md b/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/celestial-rewards-credit-card-overview.md
new file mode 100644
index 00000000..9231d501
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/celestial-rewards-credit-card-overview.md
@@ -0,0 +1,43 @@
+# Brahe Bank Celestial Rewards Credit Card
+
+## Overview
+
+The Brahe Bank Celestial Rewards Credit Card is designed for stargazers, space enthusiasts, and everyday explorers. This premium credit card combines practical spending benefits with exclusive astronomy-themed rewards.
+
+## Key Features
+
+- **Interest Rate**:
+ - 26.9% APR on purchases
+ - 26.9% APR on cash advances
+ - 0.0% APR on balance transfers for 12 months
+
+- **Annual Fee**:
+ - $99 charged annually on the account anniversary
+
+- **Rewards Program – Celestial Points**:
+ - Earn 2 points per $1 spent on purchases
+ - Redeem points for:
+ - Telescopes
+ - Planetarium tickets
+ - Astronomy gear and experiences
+
+- **Additional Benefits**:
+ - Real-time fraud monitoring
+ - Zero liability on unauthorized purchases
+ - Invitations to exclusive stargazing events
+
+## Eligibility Requirements
+
+- Age 18+
+- U.S. resident with valid Social Security number
+- Satisfactory credit history, with a credit score over 600
+
+## Important Disclosures
+
+- Rates subject to change
+- Rewards and catalog availability may vary
+- Additional fees may apply for cash advances
+
+*Brahe Bank — Charting Your Financial Constellation.*
+
+Visit [www.brahebank.com/creditcards](http://www.brahebank.com/creditcards) for more details.
diff --git a/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/celestial-rewards-credit-card-rewards-summary.md b/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/celestial-rewards-credit-card-rewards-summary.md
new file mode 100644
index 00000000..04a8314d
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/celestial-rewards-credit-card-rewards-summary.md
@@ -0,0 +1,22 @@
+# Celestial Points Rewards Catalog – Summary
+
+## Telescope Rewards
+
+- **Beginner Refractor Telescope** – 25,000 points
+- **Intermediate Reflector Telescope** – 45,000 points
+- **Advanced Astrophotography Kit** – 80,000 points
+
+## Planetarium Tickets
+
+- **2 General Admission Tickets** – 5,000 points
+- **Family Pack (4 tickets + gift voucher)** – 12,000 points
+- **Exclusive Night Sky Tour** – 20,000 points
+
+## Accessories & Experiences
+
+- **Star Chart Kit** – 3,500 points
+- **Astronomy-Themed Blanket** – 6,000 points
+- **Private Observatory Session** – 50,000 points
+
+> Rewards availability and shipping timelines are subject to change.
+> See [www.brahebank.com/rewards](http://www.brahebank.com/rewards) for current listings.
diff --git a/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/celestial-rewards-credit-card-terms-and-conditions.md b/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/celestial-rewards-credit-card-terms-and-conditions.md
new file mode 100644
index 00000000..f945a217
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/celestial-rewards-credit-card-terms-and-conditions.md
@@ -0,0 +1,30 @@
+# Terms & Conditions – Celestial Rewards Credit Card
+
+## Interest Rates and Charges
+
+- **Purchase APR**: 26.9% (variable)
+- **Cash Advance APR**: 26.9% (variable)
+- **Balance Transfer APR**: 0.0% (for 12 months)
+- **Minimum Interest Charge**: $1.50
+- **Grace Period**: 21 days on purchases
+
+## Fees
+
+- **Annual Fee**: $99
+- **Foreign Transaction Fee**: 3%
+- **Late Payment Fee**: Up to $40
+- **Returned Payment Fee**: Up to $35
+- **Cash Advance Fee**: Greater of $10 or 5%
+
+## Billing Rights Summary
+
+To report errors or questions about your bill, contact us within 60 days. Write to:
+Brahe Bank
+P.O. Box 1400
+Observatory City, ST 00001
+
+## Reward Terms
+
+- Points are earned on net purchases only
+- Points expire after 36 months
+- Redemption options and values subject to change
diff --git a/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/orbit-credit-card-faq.md b/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/orbit-credit-card-faq.md
new file mode 100644
index 00000000..b4faeb9a
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/orbit-credit-card-faq.md
@@ -0,0 +1,21 @@
+# Frequently Asked Questions – Orbit Basic Credit Card
+
+## Q1: Does this card have an annual fee?
+
+No. Orbit Basic has no annual fee, ever.
+
+## Q2: Are there any rewards?
+
+No, this card does not offer points, miles, or cashback. It is intended for simple credit usage.
+
+## Q3: What are the interest rates?
+
+29.9% APR on purchases, 34.9% on cash advances. These are variable rates and may change.
+
+## Q4: Who should apply for this card?
+
+Those who want a simple credit card for essential purchases, with no annual fee or complicated reward systems.
+
+## Q5: Can I manage the card online?
+
+Yes. You can view transactions, pay bills, and manage your account via the Brahe Bank app or website.
diff --git a/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/orbit-credit-card-overview.md b/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/orbit-credit-card-overview.md
new file mode 100644
index 00000000..c7fb1aff
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/orbit-credit-card-overview.md
@@ -0,0 +1,39 @@
+# Brahe Bank Orbit Basic Credit Card
+
+## Overview
+
+The Brahe Bank Orbit Basic Credit Card is a no-annual-fee, no-rewards credit solution built for simplicity and flexibility. Designed for customers who want to keep things straightforward, this card offers a basic way to manage everyday expenses without the fuss.
+
+## Key Features
+
+- **Interest Rate**:
+ - 29.9% APR on purchases
+ - 34.9% APR on cash advances
+ - 0.0% APR on balance transfers for 12 months
+
+- **Annual Fee**:
+ - None — $0 forever
+
+- **Rewards Program**:
+ - This card does not include a rewards program
+
+- **Additional Benefits**:
+ - Standard fraud protection
+ - Digital card management tools via Brahe Bank mobile and web apps
+ - Contactless payment support
+
+## Eligibility Requirements
+
+- Must be 18 or older
+- Valid U.S. mailing address and SSN
+- Fair credit history, with a credit score over 500
+
+## Important Disclosures
+
+- APRs are variable and may adjust with market conditions
+- This card is best suited for those who pay off balances monthly
+- No annual fee, ever
+
+*Brahe Bank — Simplicity That Keeps You in Orbit.*
+
+Learn more at [www.brahebank.com/orbitbasic](http://www.brahebank.com/orbitbasic)
diff --git a/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/orbit-credit-card-rewards.md b/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/orbit-credit-card-rewards.md
new file mode 100644
index 00000000..59a395a1
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/orbit-credit-card-rewards.md
@@ -0,0 +1,13 @@
+# Rewards Catalog – Orbit Basic Credit Card
+
+The Orbit Basic Credit Card does **not** include a rewards program.
+
+This card is designed for customers who prefer:
+
+- No annual fees
+- No complex point systems
+- Straightforward credit access
+
+If you're looking for a card with astronomy-themed rewards, check out the [Celestial Rewards Credit Card](http://www.brahebank.com/creditcards) from Brahe Bank.
+
+*Orbit Basic: Credit that keeps you grounded.*
diff --git a/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/orbit-credit-card-terms-and-conditions.md b/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/orbit-credit-card-terms-and-conditions.md
new file mode 100644
index 00000000..bd5b6f2f
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/source-docs/credit-cards/orbit-credit-card-terms-and-conditions.md
@@ -0,0 +1,28 @@
+# Terms & Conditions – Orbit Basic Credit Card
+
+## Interest Rates and Charges
+
+- **Purchase APR**: 29.9% (variable)
+- **Cash Advance APR**: 34.9% (variable)
+- **Balance Transfer APR**: 0.0% (for 12 months)
+- **Minimum Interest Charge**: $1.50
+- **Grace Period**: 21 days on purchases if balance is paid in full
+
+## Fees
+
+- **Annual Fee**: None
+- **Foreign Transaction Fee**: 3% of each transaction
+- **Late Payment Fee**: Up to $40
+- **Returned Payment Fee**: Up to $35
+- **Cash Advance Fee**: Greater of $10 or 5% of the transaction
+
+## Billing Rights Summary
+
+If you believe there’s an error on your statement, notify us in writing within 60 days:
+Brahe Bank
+P.O. Box 1400
+Observatory City, ST 00001
+
+## Additional Disclosures
+
+This card does not accrue any points, miles, or cashback. It is intended for basic credit access with minimal complexity.
diff --git a/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/__init__.py b/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/agents/__init__.py b/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/agents/__init__.py
new file mode 100644
index 00000000..79bb19d5
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/agents/__init__.py
@@ -0,0 +1,7 @@
+"""Agents package for the Splunk AO LangGraph FSI Agent."""
+
+from .credit_card_information_agent import create_credit_card_information_agent
+from .credit_score_agent import create_credit_score_agent
+from .supervisor_agent import create_supervisor_agent
+
+__all__ = ["create_credit_card_information_agent", "create_credit_score_agent", "create_supervisor_agent"]
diff --git a/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/agents/credit_card_information_agent.py b/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/agents/credit_card_information_agent.py
new file mode 100644
index 00000000..e3c43802
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/agents/credit_card_information_agent.py
@@ -0,0 +1,43 @@
+"""
+Builds a graph using all the nodes and edges defined in the application.
+"""
+
+import os
+from langchain_openai import ChatOpenAI
+from langgraph.graph.graph import CompiledGraph
+from langgraph.prebuilt import create_react_agent
+
+from ..tools.pinecone_retrieval_tool import PineconeRetrievalTool
+
+# Create the tools
+credit_card_information_retrieval_tool = PineconeRetrievalTool("credit-card-information")
+
+
+def create_credit_card_information_agent() -> CompiledGraph:
+ """
+ Create an agent that can help with inquires about the available credit card options from the Brahe Bank.
+
+ returns: A compiled graph for this agent.
+ """
+
+ # Create an agent
+ agent = create_react_agent(
+ model=ChatOpenAI(model=os.environ["MODEL_NAME"], name="Credit Card Agent"),
+ tools=[credit_card_information_retrieval_tool],
+ prompt=(
+ """
+ You are an expert on Brahe Bank credit card products. Provide clear, accurate,
+ and concise information. Only answer with known facts from provided documentation,
+ and information about the requestor such as their credit score.
+ If unsure, state "I don't know."
+ """
+ ),
+ name="credit-card-agent",
+ )
+
+ # Uncomment the following lines to print the compiled graph to the console in Mermaid format
+ # print("Compiled Credit Card Agent Graph:")
+ # print(agent.get_graph().draw_mermaid())
+
+ # Return the compiled graph
+ return agent
diff --git a/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/agents/credit_score_agent.py b/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/agents/credit_score_agent.py
new file mode 100644
index 00000000..7009b98d
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/agents/credit_score_agent.py
@@ -0,0 +1,40 @@
+"""
+A credit score agent for the Brahe Bank application.
+"""
+
+import os
+from langchain_openai import ChatOpenAI
+from langgraph.graph.graph import CompiledGraph
+from langgraph.prebuilt import create_react_agent
+
+from ..tools.credit_score_tool import CreditScoreTool
+
+# Create the tools
+credit_score_tool = CreditScoreTool()
+
+
+def create_credit_score_agent() -> CompiledGraph:
+ """
+ Create an agent that can help with inquires about your credit score.
+
+ returns: A compiled graph for this agent.
+ """
+
+ # Create an agent
+ agent = create_react_agent(
+ model=ChatOpenAI(model=os.environ["MODEL_NAME"], name="Credit Score Agent"),
+ tools=[credit_score_tool],
+ prompt=(
+ """
+ You are an expert on credit score. Provide the user with their credit score from the credit_score_tool.
+ """
+ ),
+ name="credit-score-agent",
+ )
+
+ # Uncomment the following lines to print the compiled graph to the console in Mermaid format
+ # print("Compiled Credit Score Agent Graph:")
+ # print(agent.get_graph().draw_mermaid())
+
+ # Return the compiled graph
+ return agent
diff --git a/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/agents/supervisor_agent.py b/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/agents/supervisor_agent.py
new file mode 100644
index 00000000..262cdac5
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/agents/supervisor_agent.py
@@ -0,0 +1,42 @@
+"""
+Supervisor Agent for Brahe Bank Application
+"""
+
+import os
+from langchain_openai import ChatOpenAI
+from langgraph_supervisor import create_supervisor
+
+from .credit_score_agent import create_credit_score_agent
+from .credit_card_information_agent import create_credit_card_information_agent
+
+# Define the agents that the supervisor will manage
+credit_card_information_agent = create_credit_card_information_agent()
+credit_score_agent = create_credit_score_agent()
+
+
+def create_supervisor_agent():
+ """
+ Create a supervisor agent that manages all the agents in the Brahe Bank application.
+ """
+ bank_supervisor_agent = create_supervisor(
+ model=ChatOpenAI(model=os.environ["MODEL_NAME"], name="Supervisor"),
+ agents=[credit_card_information_agent, credit_score_agent],
+ prompt=(
+ """
+ You are a supervisor managing the following agents:
+ - a credit card information agent. Assign any tasks related to information about credit cards to this agent
+ Otherwise, only respond with 'I don't know' or 'I cannot answer that question'.
+ If you need to ask the user for more information, do so in a concise manner.
+ """
+ ),
+ add_handoff_back_messages=True,
+ output_mode="full_history",
+ supervisor_name="brahe-bank-supervisor-agent",
+ ).compile()
+ bank_supervisor_agent.name = "brahe-bank-supervisor-agent"
+
+ # Uncomment the following lines to print the compiled graph to the console in Mermaid format
+ # print("Compiled Bank Supervisor Agent Graph:")
+ # print(bank_supervisor_agent.get_graph().draw_mermaid())
+
+ return bank_supervisor_agent
diff --git a/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/tools/__init__.py b/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/tools/__init__.py
new file mode 100644
index 00000000..692862cf
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/tools/__init__.py
@@ -0,0 +1,6 @@
+"""Tools package for the Splunk AO LangGraph FSI Agent."""
+
+from .pinecone_retrieval_tool import PineconeRetrievalTool
+from .credit_score_tool import CreditScoreTool
+
+__all__ = ["PineconeRetrievalTool", "CreditScoreTool"]
diff --git a/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/tools/credit_score_tool.py b/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/tools/credit_score_tool.py
new file mode 100644
index 00000000..f4ffe135
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/tools/credit_score_tool.py
@@ -0,0 +1,23 @@
+"""
+A tool for retrieving information about credit scores from a financial services knowledge base.
+"""
+
+from typing_extensions import override
+
+from langchain.tools import BaseTool
+
+
+class CreditScoreTool(BaseTool):
+ """
+ CreditScoreTool is a tool for retrieving relevant information about credit scores from a financial services knowledge base.
+ """
+
+ name: str = "credit_score_retrieval"
+ description: str = "Retrieve relevant information about credit scores from the financial services knowledge base"
+
+ @override
+ def _run(self) -> str:
+ """
+ Always return a credit score of 550 for testing purposes.
+ """
+ return "Your credit score is 550"
diff --git a/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/tools/pinecone_retrieval_tool.py b/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/tools/pinecone_retrieval_tool.py
new file mode 100644
index 00000000..0b31bd70
--- /dev/null
+++ b/examples/agent/langgraph-fsi-agent/before/src/galileo_langgraph_fsi_agent/tools/pinecone_retrieval_tool.py
@@ -0,0 +1,58 @@
+"""
+A tool for retrieving information from the Pinecone vector database.
+"""
+
+from typing_extensions import override
+
+from langchain.tools import BaseTool
+from langchain_pinecone import PineconeVectorStore
+from langchain_openai import OpenAIEmbeddings
+from pydantic import BaseModel, Field
+
+
+class RetrievalInput(BaseModel):
+ """
+ RetrievalInput is a Pydantic model representing the input schema for a document retrieval operation.
+ Attributes:
+ query (str): The search query used to find relevant documents.
+ k (int, optional): The number of documents to retrieve. Defaults to 3.
+ """
+
+ query: str = Field(description="The search query to find relevant documents")
+ k: int = Field(default=3, description="Number of documents to retrieve")
+
+
+class PineconeRetrievalTool(BaseTool):
+ """
+ PineconeRetrievalTool is a tool for retrieving relevant information from a financial services knowledge base using Pinecone as a vector store.
+ """
+
+ name: str = "pinecone_retrieval"
+ description: str = "Retrieve relevant information from the financial services knowledge base"
+ args_schema: type[BaseModel] = RetrievalInput # type: ignore
+
+ def __init__(self, index_name: str):
+ super().__init__()
+ self._embeddings = OpenAIEmbeddings()
+ self._index_name = index_name
+ self._vector_store = PineconeVectorStore(index_name=self._index_name, embedding=self._embeddings)
+
+ @override
+ def _run(self, query: str, k: int = 3) -> str:
+ """Execute the retrieval"""
+ try:
+ # Perform similarity search
+ results = self._vector_store.similarity_search(query, k=k)
+
+ if not results:
+ return "No relevant information found in the knowledge base."
+
+ # Format the results
+ formatted_results = []
+ for i, doc in enumerate(results, 1):
+ formatted_results.append(f"Document {i}:\n{doc.page_content}\n")
+
+ return "\n".join(formatted_results)
+
+ except Exception as e:
+ return f"Error retrieving information: {str(e)}"
diff --git a/examples/agent/langgraph-open-telemetry/.env.example b/examples/agent/langgraph-open-telemetry/.env.example
new file mode 100644
index 00000000..397722a5
--- /dev/null
+++ b/examples/agent/langgraph-open-telemetry/.env.example
@@ -0,0 +1,12 @@
+# Galileo Environment Variables
+GALILEO_API_KEY=your-api-key-here # Your Galileo API key.
+GALILEO_PROJECT=your-galileo-project-name # Your Galileo project name.
+GALILEO_LOG_STREAM=your-log-stream-name # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# GALILEO_CONSOLE_URL= # Optional if you are using a hosted version of Galileo
+
+# AI services
+OPENAI_API_KEY= # Your OpenAI API key
+# OPENAI_BASE_URL= # Optional if you are not using the public OpenAI API.
+MODEL_NAME= # The name of the model you want to use.
diff --git a/examples/agent/langgraph-open-telemetry/.gitignore b/examples/agent/langgraph-open-telemetry/.gitignore
new file mode 100644
index 00000000..c66ba3a1
--- /dev/null
+++ b/examples/agent/langgraph-open-telemetry/.gitignore
@@ -0,0 +1,2 @@
+.env
+.venv
\ No newline at end of file
diff --git a/examples/agent/langgraph-open-telemetry/README.md b/examples/agent/langgraph-open-telemetry/README.md
new file mode 100644
index 00000000..3047f9d4
--- /dev/null
+++ b/examples/agent/langgraph-open-telemetry/README.md
@@ -0,0 +1,84 @@
+# LangGraph + OpenTelemetry + Splunk AO Integration
+
+This example demonstrates how to add comprehensive observability to your LangGraph AI workflows using OpenTelemetry and Splunk AO. You'll get detailed traces showing the complete execution flow, LLM calls, token usage, and input/output data.
+
+## What are these tools?
+
+**OpenTelemetry** is an observability framework that creates traces showing what functions ran, their timing, and data flow through your application. The **OpenTelemetry instrumentation libraries** automatically instrument AI frameworks like LangChain and OpenAI. **Splunk AO** provides a sophisticated platform for visualizing and analyzing your AI application traces.
+
+For detailed explanations and advanced patterns, see the [LangGraph OpenTelemetry cookbook](https://docs.galileo.ai/cookbooks/features/integrations/langgraph-otel-cookbook)
+
+## Quick start
+
+### Prerequisites
+
+- Python 3.12+
+- [UV package manager](https://docs.astral.sh/uv/getting-started/installation/)
+- [Splunk AO account](https://app.galileo.ai) (free)
+- OpenAI API key
+
+### Installation
+
+```bash
+# Clone and navigate
+git clone https://github.com/rungalileo/sdk-examples
+cd sdk-examples/python/agent/langgraph-open-telemetry
+
+# Install dependencies
+uv sync
+
+# Create environment file
+cp .env.example .env
+# Edit .env with your API keys (see below)
+```
+
+### Environment variables
+
+Create a `.env` file in the project root with the following variables:
+
+```bash
+# Your Splunk AO API key (get from https://app.galileo.ai/settings/api-keys)
+SPLUNK_AO_API_KEY=your_splunk_ao_api_key_here
+
+# Your Splunk AO project name
+SPLUNK_AO_PROJECT=your_project_name
+
+# Log stream for organizing traces
+SPLUNK_AO_LOG_STREAM=langgraph
+
+# Splunk AO console URL (if using a custom deployment is different than https://app.galileo.ai)
+SPLUNK_AO_CONSOLE_URL=https://app.galileo.ai
+
+# Your OpenAI API key
+OPENAI_API_KEY=your_openai_api_key_here
+```
+
+| Variable | Required | Description |
+| ------------------- | -------- | ------------------------------------------------------------------------------ |
+| `SPLUNK_AO_API_KEY` | Yes | Your Splunk AO API key from [settings](https://app.galileo.ai/settings/api-keys) |
+| `SPLUNK_AO_PROJECT` | Yes | Splunk AO project name (create one in your dashboard) |
+| `SPLUNK_AO_LOG_STREAM` | Yes | Log stream name for organizing traces (default: "default") |
+| `OPENAI_API_KEY` | Yes | Your OpenAI API key from [OpenAI](https://platform.openai.com/api-keys) |
+
+### Run
+
+```bash
+uv run python main.py
+```
+
+This runs a question-answering LangGraph workflow with comprehensive OpenTelemetry tracing. Check your Splunk AO project for detailed traces!
+
+## What's included
+
+- **`main.py`** - Complete LangGraph workflow with OpenTelemetry tracing
+- **`pyproject.toml`** - All dependencies managed via UV
+- **`.env.example`** - Example environment variables (copy to `.env` and add your API keys)
+- **`README.md`** - This comprehensive guide
+
+## Learn more
+
+- [LangGraph OpenTelemetry cookbook](https://docs.galileo.ai/cookbooks/features/integrations/langgraph-otel-cookbook)
+- [LangGraph Documentation](https://langchain-ai.github.io/langgraph/)
+- [OpenTelemetry Python](https://opentelemetry.io/docs/instrumentation/python/)
+- [Splunk AO Documentation](https://docs.galileo.ai/)
+- [UV Package Manager](https://docs.astral.sh/uv/)
diff --git a/examples/agent/langgraph-open-telemetry/main.py b/examples/agent/langgraph-open-telemetry/main.py
new file mode 100644
index 00000000..6d006482
--- /dev/null
+++ b/examples/agent/langgraph-open-telemetry/main.py
@@ -0,0 +1,155 @@
+import logging
+import os
+from typing import TypedDict
+
+import dotenv
+import openai
+from splunk_ao import otel
+
+# LangGraph imports - this is what we're actually instrumenting
+from langgraph.graph import END, StateGraph
+from opentelemetry import trace as trace_api # API for interacting with traces
+from opentelemetry.instrumentation.langchain import LangchainInstrumentor
+from opentelemetry.instrumentation.openai_v2 import OpenAIInstrumentor
+from opentelemetry.sdk import trace as trace_sdk # SDK for creating traces
+from opentelemetry.sdk.resources import Resource
+
+dotenv.load_dotenv()
+logging.basicConfig(level=logging.DEBUG)
+
+# Configure OpenAI API key
+openai_api_key = os.environ.get("OPENAI_API_KEY")
+if not openai_api_key:
+ raise ValueError("OPENAI_API_KEY environment variable is required")
+
+# Initialize OpenAI client
+client = openai.OpenAI(api_key=openai_api_key)
+print("✓ OpenAI client configured")
+
+galileo_span_processor = otel.SplunkAOSpanProcessor()
+
+
+resource = Resource.create(
+ {
+ "service.name": "LangGraph-OpenTelemetry-Demo",
+ "service.version": "1.0.0",
+ "deployment.environment": "development",
+ }
+)
+tracer_provider = trace_sdk.TracerProvider(resource=resource)
+
+
+# Add a span processor that sends traces to Splunk AO
+otel.add_splunk_ao_span_processor(tracer_provider, galileo_span_processor)
+
+# OPTIONAL: Console output disabled to reduce noise in Splunk AO
+# Uncomment the next 3 lines if you want local console debugging:
+# tracer_provider.add_span_processor(
+# BatchSpanProcessor(ConsoleSpanExporter())
+# )
+
+trace_api.set_tracer_provider(tracer_provider=tracer_provider)
+
+LangchainInstrumentor().instrument(tracer_provider=tracer_provider)
+OpenAIInstrumentor().instrument(tracer_provider=tracer_provider)
+print("✓ LangGraph instrumentation applied - automatic spans will be created")
+# Get a tracer for creating custom spans manually
+# We'll use this in our node functions below
+tracer = trace_api.get_tracer(__name__)
+
+
+class AgentState(TypedDict, total=False):
+ user_input: str # The user's input question
+ llm_response: str # The raw response from the LLM
+ parsed_answer: str # The processed/cleaned answer
+
+
+# Node 1: Input Validation
+# Validates and prepares the user input for processing
+def validate_input(state: AgentState):
+ user_input = state.get("user_input", "")
+ print(f"📥 Validating input: '{user_input}'")
+
+ return {"user_input": user_input}
+
+
+# Node 2: Generate Response
+# Calls OpenAI to generate a response to the user's question
+# OpenAI instrumentation will automatically create detailed spans
+def generate_response(state: AgentState):
+ user_input = state.get("user_input", "")
+
+ try:
+ print(f"⚙️ Calling OpenAI with: '{user_input}'")
+
+ # Make the OpenAI API call - OpenAI instrumentation handles tracing
+ response = client.chat.completions.create(
+ model="gpt-3.5-turbo",
+ messages=[{"role": "user", "content": user_input}],
+ max_tokens=300,
+ temperature=0.7,
+ )
+
+ # Extract the response content
+ llm_response = response.choices[0].message.content
+
+ if not llm_response:
+ print("❌ No response from OpenAI")
+ else:
+ print(f"✓ Received response: '{llm_response[:100]}...'")
+
+ return {"llm_response": llm_response}
+
+ except Exception as e:
+ print(f"❌ Error calling OpenAI: {e}")
+ return {"llm_response": f"Error: {str(e)}"}
+
+
+# Node 3: Format Answer
+# Extracts and formats a clean answer from the raw LLM response
+def format_answer(state: AgentState):
+ llm_response = state.get("llm_response", "")
+
+ # Simple parsing - extract first sentence for a concise answer
+ sentences = llm_response.split(". ")
+ parsed_answer = sentences[0] if sentences else llm_response
+
+ # Clean up the answer
+ parsed_answer = parsed_answer.strip()
+ if not parsed_answer.endswith(".") and parsed_answer:
+ parsed_answer += "."
+
+ print(f"✨ Parsed answer: '{parsed_answer}'")
+
+ return {"parsed_answer": parsed_answer}
+
+
+# ============================================================================
+# STEP 5: BUILD AND RUN THE LANGGRAPH WORKFLOW
+# ============================================================================
+workflow = StateGraph(AgentState)
+workflow.add_node("validate_input", validate_input)
+workflow.add_node("generate_response", generate_response)
+workflow.add_node("format_answer", format_answer)
+
+# Entry point and edges define the control flow of the graph
+workflow.set_entry_point("validate_input")
+workflow.add_edge("validate_input", "generate_response")
+workflow.add_edge("generate_response", "format_answer")
+workflow.add_edge("format_answer", END)
+
+# Compile builds the runnable app
+app = workflow.compile()
+
+# Run the app and observe traces in both console and Splunk AO
+if __name__ == "__main__":
+ inputs = {"user_input": "what moons did galileo discover"}
+
+ result = app.invoke(AgentState(**inputs))
+
+ print("\n=== FINAL RESULT ===")
+ print(f"Question: {result.get('user_input', 'N/A')}")
+ print(f"LLM Response: {result.get('llm_response', 'N/A')}")
+ print(f"Parsed Answer: {result.get('parsed_answer', 'N/A')}")
+
+ print("✓ Execution complete - check Splunk AO for traces in your project/log stream")
diff --git a/examples/agent/langgraph-open-telemetry/pyproject.toml b/examples/agent/langgraph-open-telemetry/pyproject.toml
new file mode 100644
index 00000000..58ff48e0
--- /dev/null
+++ b/examples/agent/langgraph-open-telemetry/pyproject.toml
@@ -0,0 +1,20 @@
+[project]
+name = "langgraph-open-telemetry"
+version = "0.1.0"
+description = "LangGraph + OpenTelemetry + Splunk AO Integration"
+readme = "README.md"
+requires-python = ">=3.12"
+dependencies = [
+ "langgraph>=0.6.0",
+ "langgraph-prebuilt>=0.6.0",
+ "openai",
+ "python-dotenv>=1.1.0",
+ "galileo[otel]>=1.32.1",
+ "opentelemetry-instrumentation-langchain>=0.48.1",
+ "opentelemetry-instrumentation-openai-v2>=2.1b0",
+]
+
+[dependency-groups]
+dev = [
+ "black>=25.1.0",
+]
diff --git a/examples/agent/langgraph-otel/.env.example b/examples/agent/langgraph-otel/.env.example
new file mode 100644
index 00000000..397722a5
--- /dev/null
+++ b/examples/agent/langgraph-otel/.env.example
@@ -0,0 +1,12 @@
+# Galileo Environment Variables
+GALILEO_API_KEY=your-api-key-here # Your Galileo API key.
+GALILEO_PROJECT=your-galileo-project-name # Your Galileo project name.
+GALILEO_LOG_STREAM=your-log-stream-name # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# GALILEO_CONSOLE_URL= # Optional if you are using a hosted version of Galileo
+
+# AI services
+OPENAI_API_KEY= # Your OpenAI API key
+# OPENAI_BASE_URL= # Optional if you are not using the public OpenAI API.
+MODEL_NAME= # The name of the model you want to use.
diff --git a/examples/agent/langgraph-otel/.gitignore b/examples/agent/langgraph-otel/.gitignore
new file mode 100644
index 00000000..c66ba3a1
--- /dev/null
+++ b/examples/agent/langgraph-otel/.gitignore
@@ -0,0 +1,2 @@
+.env
+.venv
\ No newline at end of file
diff --git a/examples/agent/langgraph-otel/README.md b/examples/agent/langgraph-otel/README.md
new file mode 100644
index 00000000..8edf489f
--- /dev/null
+++ b/examples/agent/langgraph-otel/README.md
@@ -0,0 +1,124 @@
+# LangGraph + OpenTelemetry + Splunk AO Integration
+
+This example demonstrates how to add comprehensive observability to your LangGraph AI workflows using OpenTelemetry and Splunk AO. You'll get detailed traces showing the complete execution flow, LLM calls, token usage, and input/output data.
+
+## What are these tools?
+
+**OpenTelemetry** is an observability framework that creates traces showing what functions ran, their timing, and data flow through your application. **OpenInference** automatically instruments AI frameworks like LangChain and OpenAI. **Splunk AO** provides a sophisticated platform for visualizing and analyzing your AI application traces.
+
+For detailed explanations and advanced patterns, see the [LangGraph OpenTelemetry cookbook](https://docs.galileo.ai/cookbooks/features/integrations/langgraph-otel-cookbook)
+
+## Quick start
+
+### Prerequisites
+
+- Python 3.10+
+- [UV package manager](https://docs.astral.sh/uv/getting-started/installation/)
+- [Splunk AO account](https://app.galileo.ai) (free)
+- OpenAI API key
+
+### Installation
+
+```bash
+# Clone and navigate
+git clone https://github.com/rungalileo/sdk-examples
+cd sdk-examples/python/agent/langgraph-otel
+
+# Install dependencies
+uv sync
+
+# Create environment file
+cp .env.example .env
+# Edit .env with your API keys (see below)
+```
+
+### Environment variables
+
+Create a `.env` file in the project root with the following variables:
+
+```bash
+# Your Splunk AO API key (get from https://app.galileo.ai/settings/api-keys)
+SPLUNK_AO_API_KEY=your_splunk_ao_api_key_here
+
+# Your Splunk AO project name
+SPLUNK_AO_PROJECT=your_project_name
+
+# Log stream for organizing traces
+SPLUNK_AO_LOG_STREAM=langgraph
+
+# Splunk AO console URL (if using a custom deployment is different than https://app.galileo.ai)
+SPLUNK_AO_CONSOLE_URL=https://app.galileo.ai
+
+# Your OpenAI API key
+OPENAI_API_KEY=your_openai_api_key_here
+```
+
+| Variable | Required | Description |
+| -------------------- | -------- | ------------------------------------------------------------------------------ |
+| `SPLUNK_AO_API_KEY` | Yes | Your Splunk AO API key from [settings](https://app.galileo.ai/settings/api-keys) |
+| `SPLUNK_AO_PROJECT` | Yes | Splunk AO project name (create one in your dashboard) |
+| `SPLUNK_AO_LOG_STREAM` | Yes | Log stream name for organizing traces (default: "default") |
+| `OPENAI_API_KEY` | Yes | Your OpenAI API key from [OpenAI](https://platform.openai.com/api-keys) |
+
+### Run
+
+```bash
+uv run python main.py
+```
+
+This runs a question-answering LangGraph workflow with comprehensive OpenTelemetry tracing. Check your Splunk AO project for detailed traces!
+
+## Workflow Overview
+
+The example implements a 3-step question-answering workflow:
+
+1. **Input Validation** (`validate_input`) - Validates and prepares the user's question
+2. **Response Generation** (`generate_response`) - Calls OpenAI GPT-3.5 to generate an answer
+3. **Answer Formatting** (`format_answer`) - Extracts and formats the final answer
+
+### Trace Hierarchy
+
+In Splunk AO, you'll see a clean trace structure:
+
+```
+└── astronomy_qa_session [Question → Final Answer]
+ ├── LangGraph [Workflow execution]
+ │ ├── validate_input [Input validation]
+ │ ├── generate_response [LLM processing]
+ │ └── format_answer [Answer formatting]
+ └── gpt-3.5-turbo-0125 [Detailed OpenAI API call]
+ ├── Token usage (prompt/completion/total)
+ ├── Model parameters (temperature, max_tokens)
+ └── Input/output messages
+```
+
+### Key Observability Benefits
+
+- **Complete Input/Output Visibility** - See data flowing through each step
+- **LLM Call Details** - Token usage, model parameters, and timing
+- **Session Context** - Grouped operations with meaningful metadata
+- **Error Tracking** - Automatic error capture and status tracking
+- **Performance Insights** - Timing for each workflow step
+
+### Trace Attributes
+
+Each span includes rich metadata:
+
+- **Session Level**: Question, answer, domain (astronomy), type (Q&A)
+- **Node Level**: Input/output values, node type, processing details
+- **LLM Level**: Model name, tokens, temperature, messages, vendor
+
+## What's included
+
+- **`main.py`** - Complete LangGraph workflow with OpenTelemetry tracing
+- **`pyproject.toml`** - All dependencies managed via UV
+- **`.env`** - Environment variables (you'll need to add your API keys)
+- **`README.md`** - This comprehensive guide
+
+## Learn more
+
+- [LangGraph OpenTelemetry cookbook](https://docs.galileo.ai/cookbooks/features/integrations/langgraph-otel-cookbook)
+- [LangGraph Documentation](https://langchain-ai.github.io/langgraph/)
+- [OpenTelemetry Python](https://opentelemetry.io/docs/instrumentation/python/)
+- [Splunk AO Documentation](https://docs.galileo.ai/)
+- [UV Package Manager](https://docs.astral.sh/uv/)
diff --git a/examples/agent/langgraph-otel/main.py b/examples/agent/langgraph-otel/main.py
new file mode 100644
index 00000000..df508bc5
--- /dev/null
+++ b/examples/agent/langgraph-otel/main.py
@@ -0,0 +1,260 @@
+import os
+from typing import TypedDict
+
+# Load environment variables first (contains API keys and project settings)
+import dotenv
+
+dotenv.load_dotenv()
+
+# ============================================================================
+# OPENTELEMETRY & GALILEO IMPORTS
+# ============================================================================
+# OpenTelemetry (OTel) is an observability framework that helps you collect
+# traces, metrics, and logs from your applications. Think of it as a way to
+# "instrument" your code so you can see exactly what's happening during execution.
+
+# Core OpenTelemetry imports
+from opentelemetry.sdk import trace as trace_sdk # SDK for creating traces
+from opentelemetry import trace as trace_api # API for interacting with traces
+from opentelemetry.sdk.trace.export import (
+ BatchSpanProcessor,
+) # Efficiently batches spans before export
+from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
+ OTLPSpanExporter,
+) # Sends traces via HTTP
+
+# OpenInference is a specialized instrumentation library that understands AI frameworks
+# It automatically creates meaningful spans for LangChain/LangGraph operations
+from openinference.instrumentation.langchain import LangChainInstrumentor
+from openinference.instrumentation.openai import OpenAIInstrumentor
+
+# LangGraph imports - this is what we're actually instrumenting
+from langgraph.graph import StateGraph, END
+
+# OpenAI imports for LLM integration
+import openai
+
+# ============================================================================
+# STEP 1: CONFIGURE API AUTHENTICATION
+# ============================================================================
+# Configure OpenAI API key
+openai_api_key = os.environ.get("OPENAI_API_KEY")
+if not openai_api_key:
+ raise ValueError("OPENAI_API_KEY environment variable is required")
+
+# Initialize OpenAI client
+client = openai.OpenAI(api_key=openai_api_key)
+print("✓ OpenAI client configured")
+
+# Splunk AO is an AI observability platform that helps you monitor and debug
+# AI applications. It receives and visualizes the traces we'll generate.
+
+# Set up authentication headers for Splunk AO
+# These tell Splunk AO who you are and which project to store traces in
+headers = {
+ "Galileo-API-Key": os.environ.get("SPLUNK_AO_API_KEY"), # Your unique API key
+ "project": os.environ.get("SPLUNK_AO_PROJECT"), # Which Splunk AO project to use
+ "logstream": os.environ.get("SPLUNK_AO_LOG_STREAM", "default"), # Organize traces within the project
+}
+
+# OpenTelemetry requires headers in a specific format: "key1=value1,key2=value2"
+# This converts our dictionary to that format
+os.environ["OTEL_EXPORTER_OTLP_TRACES_HEADERS"] = ",".join([f"{k}={v}" for k, v in headers.items()])
+
+# Debug: Print the formatted headers to verify they're correct
+print(f"OTEL Headers: {os.environ['OTEL_EXPORTER_OTLP_TRACES_HEADERS']}")
+
+# ============================================================================
+# STEP 2: CONFIGURE OPENTELEMETRY TRACING
+# ============================================================================
+# OpenTelemetry works by creating "spans" - units of work that represent operations
+# in your application. Spans are organized into "traces" that show the full flow
+# of a request through your system.
+
+# Define where to send the traces - Splunk AO's OpenTelemetry endpoint.
+# Splunk AO's OTel ingest lives on the `api.` subdomain (not the `console.`/`app.`
+# one you log into). We derive it from SPLUNK_AO_CONSOLE_URL so custom deployments
+# (e.g. https://console.demo-v2.galileocloud.io/) route to their own ingest
+# (https://api.demo-v2.galileocloud.io/otel/traces) instead of app.galileo.ai.
+console_url = os.environ.get("SPLUNK_AO_CONSOLE_URL", "https://app.galileo.ai").rstrip("/")
+api_url = console_url.replace("://console.", "://api.").replace("://app.", "://api.")
+endpoint = f"{api_url}/otel/traces"
+print(f"OTEL endpoint: {endpoint}")
+
+# Create a TracerProvider with descriptive resource information
+# This helps identify these traces as coming from OpenTelemetry in Splunk AO
+from opentelemetry.sdk.resources import Resource
+
+resource = Resource.create(
+ {
+ "service.name": "LangGraph-OpenTelemetry-Demo",
+ "service.version": "1.0.0",
+ "deployment.environment": "development",
+ }
+)
+tracer_provider = trace_sdk.TracerProvider(resource=resource)
+
+# Add a span processor that sends traces to Splunk AO
+# BatchSpanProcessor is more efficient than SimpleSpanProcessor for production
+# because it batches multiple spans together before sending
+tracer_provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(endpoint))) # OTLP = OpenTelemetry Protocol
+
+# OPTIONAL: Console output disabled to reduce noise in Splunk AO
+# Uncomment the next 3 lines if you want local console debugging:
+# tracer_provider.add_span_processor(
+# BatchSpanProcessor(ConsoleSpanExporter())
+# )
+
+# Register our tracer provider as the global one
+# This means all OpenTelemetry operations will use our configuration
+trace_api.set_tracer_provider(tracer_provider=tracer_provider)
+
+# ============================================================================
+# STEP 3: APPLY OPENINFERENCE INSTRUMENTATION
+# ============================================================================
+# OpenInference automatically instruments LangChain/LangGraph to create spans
+# for AI operations. This gives us detailed visibility into:
+# - LangGraph workflow execution
+# - Individual node processing
+# - State transitions
+# - Input/output data
+LangChainInstrumentor().instrument(tracer_provider=tracer_provider)
+print("✓ LangGraph instrumentation applied - automatic spans will be created")
+
+# Also instrument OpenAI calls to capture LLM input/output
+OpenAIInstrumentor().instrument(tracer_provider=tracer_provider)
+print("✓ OpenAI instrumentation applied - LLM calls will be traced")
+
+# Get a tracer for creating custom spans manually
+# We'll use this in our node functions below
+tracer = trace_api.get_tracer(__name__)
+
+
+# ============================================================================
+# STEP 4: DEFINE THE LANGGRAPH STATE AND NODES
+# ============================================================================
+# LangGraph uses a shared state object (a dict) that flows through nodes. Each
+# node reads from the state and can write updates back to it.
+class AgentState(TypedDict, total=False):
+ user_input: str # The user's input question
+ llm_response: str # The raw response from the LLM
+ parsed_answer: str # The processed/cleaned answer
+
+
+# Node 1: Input Validation
+# Validates and prepares the user input for processing
+def validate_input(state: AgentState):
+ user_input = state.get("user_input", "")
+ print(f"📥 Validating input: '{user_input}'")
+
+ # Add span attributes for better observability
+ current_span = trace_api.get_current_span()
+ if current_span:
+ current_span.set_attribute("input.value", str(state))
+ current_span.set_attribute("output.value", user_input)
+ current_span.set_attribute("node.type", "validation")
+
+ return {"user_input": user_input}
+
+
+# Node 2: Generate Response
+# Calls OpenAI to generate a response to the user's question
+# OpenAI instrumentation will automatically create detailed spans
+def generate_response(state: AgentState):
+ user_input = state["user_input"]
+
+ try:
+ print(f"⚙️ Calling OpenAI with: '{user_input}'")
+
+ # Make the OpenAI API call - OpenAI instrumentation handles tracing
+ response = client.chat.completions.create(
+ model="gpt-3.5-turbo",
+ messages=[{"role": "user", "content": user_input}],
+ max_tokens=300,
+ temperature=0.7,
+ )
+
+ # Extract the response content
+ llm_response = response.choices[0].message.content
+
+ print(f"✓ Received response: '{llm_response[:100]}...'")
+
+ return {"llm_response": llm_response}
+
+ except Exception as e:
+ print(f"❌ Error calling OpenAI: {e}")
+ return {"llm_response": f"Error: {str(e)}"}
+
+
+# Node 3: Format Answer
+# Extracts and formats a clean answer from the raw LLM response
+def format_answer(state: AgentState):
+ llm_response = state.get("llm_response", "")
+
+ # Simple parsing - extract first sentence for a concise answer
+ sentences = llm_response.split(". ")
+ parsed_answer = sentences[0] if sentences else llm_response
+
+ # Clean up the answer
+ parsed_answer = parsed_answer.strip()
+ if not parsed_answer.endswith(".") and parsed_answer:
+ parsed_answer += "."
+
+ print(f"✨ Parsed answer: '{parsed_answer}'")
+
+ # Add span attributes for better observability
+ current_span = trace_api.get_current_span()
+ if current_span:
+ current_span.set_attribute("input.value", llm_response)
+ current_span.set_attribute("output.value", parsed_answer)
+ current_span.set_attribute("node.type", "formatting")
+
+ return {"parsed_answer": parsed_answer}
+
+
+# ============================================================================
+# STEP 5: BUILD AND RUN THE LANGGRAPH WORKFLOW
+# ============================================================================
+workflow = StateGraph(AgentState)
+workflow.add_node("validate_input", validate_input)
+workflow.add_node("generate_response", generate_response)
+workflow.add_node("format_answer", format_answer)
+
+# Entry point and edges define the control flow of the graph
+workflow.set_entry_point("validate_input")
+workflow.add_edge("validate_input", "generate_response")
+workflow.add_edge("generate_response", "format_answer")
+workflow.add_edge("format_answer", END)
+
+# Compile builds the runnable app
+app = workflow.compile()
+
+# Run the app and observe traces in both console and Splunk AO
+if __name__ == "__main__":
+ # Create a session-level span to group all operations
+ with tracer.start_as_current_span("astronomy_qa_session") as session_span:
+ inputs = {"user_input": "what moons did galileo discover"}
+
+ # Add OpenInference-compatible attributes for proper input/output display
+ session_span.set_attribute("input.value", inputs["user_input"])
+ session_span.set_attribute("input.mime_type", "text/plain")
+ session_span.set_attribute("session.type", "question_answering")
+ session_span.set_attribute("session.domain", "astronomy")
+
+ result = app.invoke(inputs)
+
+ # Add result attributes with OpenInference-compatible format
+ if result.get("llm_response"):
+ final_answer = result.get("parsed_answer", result.get("llm_response"))
+ session_span.set_attribute("output.value", final_answer)
+ session_span.set_attribute("output.mime_type", "text/plain")
+ session_span.set_status(trace_api.Status(trace_api.StatusCode.OK))
+ else:
+ session_span.set_status(trace_api.Status(trace_api.StatusCode.ERROR, "No response generated"))
+
+ print("\n=== FINAL RESULT ===")
+ print(f"Question: {result.get('user_input', 'N/A')}")
+ print(f"LLM Response: {result.get('llm_response', 'N/A')}")
+ print(f"Parsed Answer: {result.get('parsed_answer', 'N/A')}")
+
+ print("✓ Execution complete - check Splunk AO for traces in your project/log stream")
diff --git a/examples/agent/langgraph-otel/pyproject.toml b/examples/agent/langgraph-otel/pyproject.toml
new file mode 100644
index 00000000..4b125015
--- /dev/null
+++ b/examples/agent/langgraph-otel/pyproject.toml
@@ -0,0 +1,24 @@
+[project]
+name = "langgraph-otel"
+version = "0.1.0"
+description = "Add your description here"
+readme = "README.md"
+requires-python = ">=3.12"
+dependencies = [
+ "langgraph>=0.6.0",
+ "langgraph-prebuilt>=0.6.0",
+ "openai",
+ "opentelemetry-api>=1.36.0",
+ "opentelemetry-sdk>=1.36.0",
+ "opentelemetry-exporter-otlp>=1.36.0",
+ "opentelemetry-exporter-otlp-proto-grpc>=1.36.0",
+ "opentelemetry-exporter-otlp-proto-http>=1.36.0",
+ "openinference-instrumentation-langchain>=0.1.0",
+ "python-dotenv>=1.1.0",
+ "openinference-instrumentation-openai>=0.1.32",
+]
+
+[dependency-groups]
+dev = [
+ "black>=25.1.0",
+]
diff --git a/examples/agent/langgraph-telecom-agent/.env.example b/examples/agent/langgraph-telecom-agent/.env.example
new file mode 100644
index 00000000..b3e4a437
--- /dev/null
+++ b/examples/agent/langgraph-telecom-agent/.env.example
@@ -0,0 +1,16 @@
+# Galileo Environment Variables
+GALILEO_API_KEY= # Your Galileo API key.
+GALILEO_PROJECT=Multi-Agent Telecom Chatbot # Your Galileo project name.
+GALILEO_LOG_STREAM=prod # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# GALILEO_CONSOLE_URL= # Optional if you are using a hosted version of Galileo
+
+# AI services
+OPENAI_API_KEY= # Your OpenAI API key
+# OPENAI_BASE_URL= # Optional if you are not using the public OpenAI API.
+MODEL_NAME_WORKER=gpt-4.1-nano # The name of the model you want to use for worker agents
+MODEL_NAME_SUPERVISOR=gpt-4.1-mini # The name of the model you want to use for supervisor agents
+
+# The API key for Pinecone
+PINECONE_API_KEY= # Your Pinecone API key.
diff --git a/examples/agent/langgraph-telecom-agent/.gitignore b/examples/agent/langgraph-telecom-agent/.gitignore
new file mode 100644
index 00000000..af23953c
--- /dev/null
+++ b/examples/agent/langgraph-telecom-agent/.gitignore
@@ -0,0 +1,124 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a PyInstaller build script
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+.python-version
+
+# celery beat schedule file
+celerybeat-schedule
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# VS Code
+.vscode/*
+
+# macOS
+.DS_Store
+
+# ruff
+.ruff_cache
+
+.chainlit/
\ No newline at end of file
diff --git a/examples/agent/langgraph-telecom-agent/README.md b/examples/agent/langgraph-telecom-agent/README.md
new file mode 100644
index 00000000..b65672aa
--- /dev/null
+++ b/examples/agent/langgraph-telecom-agent/README.md
@@ -0,0 +1,187 @@
+# ConnectTel Telecom Multi-Agent System
+
+This is a telecom customer service multi-agent system built with LangGraph and Chainlit. It demonstrates how AI agents can handle various telecom support scenarios including network issues, billing inquiries, technical support, and service management. Read our [blog](https://galileo.ai/blog/evaluate-langgraph-multi-agent-telecom) for implementation details, metrics and how to use Splunk AO in the console.
+
+## Overview
+
+This app is a customer service chatbot for the fictional telecom provider, **ConnectTel**. The system uses multiple specialized agents to handle different aspects of telecom customer support, all orchestrated by a supervisor agent.
+
+### Key Features
+
+- **Multi-Agent Architecture**: Specialized agents for different telecom domains
+- **Mock Data System**: No live APIs required except Pinecone - perfect for demos and testing
+- **Realistic Scenarios**: Simulates real telecom support interactions
+- **Comprehensive Coverage**: Handles network, billing, technical, and service issues
+
+## What You Can Do
+
+Ask the bot about:
+
+- 💰 **Billing & Usage**: Review bills, track data usage, understand charges
+- 🔧 **Technical Support**: Troubleshoot connectivity issues, configure devices
+- 📊 **Plan Recommendations**: Get personalized plan suggestions based on usage
+
+## System Architecture
+
+### Tech Stack
+
+- **LangGraph**: Agent orchestration and workflow management
+- **Chainlit**: User interface for chat interactions
+- **Pinecone**: Vector database for knowledge retrieval
+- **Splunk AO**: Monitoring and evaluation platform
+
+### Agents
+
+The system consists of three specialized agents, all coordinated by a supervisor:
+
+
+#### 1. Billing & Account Agent
+Handles all billing-related inquiries, usage tracking, and account management.
+
+**Tools**: `BillingTool`
+- Check account balance and due dates
+- Track data, voice, and text usage
+- Review billing history
+- Suggest plan optimizations
+
+#### 2. Technical Support Agent
+Provides troubleshooting assistance and device configuration support.
+
+**Tools**: `TechnicalSupportTool`
+- Step-by-step troubleshooting guides
+- Device configuration (APN, WiFi calling)
+- Service resets and escalations
+- Diagnostic codes
+
+#### 3. Plan Advisor Agent
+Analyzes customer needs and recommends suitable plans and services.
+
+**Tools**: `PineconeRetrievalTool`
+- Compare plan features
+- Identify savings opportunities
+- Recommend add-ons and bundles
+- Explain plan benefits
+
+### Supervisor Agent Architecture
+
+```mermaid
+graph TD
+ Start([User Query]) --> Supervisor{Supervisor Agent}
+ Supervisor --> Billing[Billing & Account Agent]
+ Supervisor --> TechSupport[Technical Support Agent]
+ Supervisor --> PlanAdvisor[Plan Advisor Agent]
+
+ Billing --> Response
+ TechSupport --> Response
+ PlanAdvisor --> Response
+```
+
+## Mock Data System
+
+Since this is a demo system without live telecom APIs, all tools use mock data generators that provide:
+
+- **Realistic Responses**: Coherent, context-aware information
+- **Dynamic Values**: Randomized metrics (signal strength, speeds, etc.)
+- **Consistent State**: Maintains session context
+- **Multiple Scenarios**: Simulates various support situations
+
+### Example Mock Data
+
+- **Customer Accounts**: Multiple customer profiles with different plans
+- **Troubleshooting Guides**: Common issues and solutions
+- **Plan Catalog**: Various individual, family, and business plans
+
+## Setup Instructions
+
+### Prerequisites
+
+- Python 3.10+
+- [OpenAI API Key](https://platform.openai.com/api-keys)
+- [Pinecone Account](https://www.pinecone.io)
+- [Splunk AO Account](https://app.galileo.ai/sign-up)
+
+### Installation
+
+1. **Clone the repository**
+```bash
+git clone https://github.com/rungalileo/sdk-examples
+cd sdk-examples/python/agent/langgraph-telecom-agent
+```
+
+2. **Set up environment variables**
+```bash
+cp .env.example .env
+# Edit .env with your API keys
+```
+
+3. **Install dependencies**
+```bash
+# Using uv (recommended)
+uv sync --dev
+
+# Or using pip with pyproject.toml
+pip install -e .
+```
+
+4. **Set up vector database (optional - only needed for Plan Advisor Agent)**
+```bash
+# Upload telecom documentation to Pinecone
+# This will create a "telecom" index with plan information and troubleshooting guides
+python ./scripts/setup_pinecone.py
+```
+
+### Running the Application
+
+**Start the Chainlit UI**
+```bash
+chainlit run app.py -w
+```
+
+The application will be available at [http://localhost:8000](http://localhost:8000)
+
+**Test the tools directly**
+```bash
+python test_tools.py
+```
+
+## Example Interactions
+
+### Billing Inquiry
+**User**: "What's my current data usage?"
+**Bot**: Shows data consumption, remaining allowance, and average daily usage
+
+### Technical Support
+**User**: "My internet is really slow"
+**Bot**: Provides troubleshooting steps, checks network congestion, suggests optimizations
+
+### Plan Advice
+**User**: "I need a plan with international calling"
+**Bot**: Recommends suitable plans with international features, compares options
+
+
+## Project Structure
+
+```
+langgraph-telecom-agent/
+├── app.py # Main Chainlit application
+├── src/
+│ └── galileo_langgraph_fsi_agent/
+│ ├── agents/ # Agent implementations
+│ │ ├── supervisor_agent.py # Orchestrator
+│ │ ├── billing_account_agent.py
+│ │ ├── technical_support_agent.py
+│ │ └── plan_advisor_agent.py
+│ └── tools/ # Mock tool implementations
+│ ├── billing_tool.py
+│ ├── technical_support_tool.py
+│ └── pinecone_retrieval_tool.py
+└── source-docs/ # Telecom knowledge base
+ ├── telecom-plans.md # Plan catalog
+ └── network-troubleshooting.md # Support guides
+```
+
+## Monitoring with Splunk AO
+- View traces at [app.galileo.ai](https://app.galileo.ai) after running conversations.
+- Setup agent metrics like Action Completion, Tool Selection Quality and Tool Error Rate
+- You can also add a [custom metric](https://galileo.ai/blog/evaluate-langgraph-multi-agent-telecom#performance-benchmarks-for-production) as per your bespoke requirements
+- Read our [blog](https://galileo.ai/blog/evaluate-langgraph-multi-agent-telecom) for a detailed guide on metrics and debugging agent with the insights.
\ No newline at end of file
diff --git a/examples/agent/langgraph-telecom-agent/app.py b/examples/agent/langgraph-telecom-agent/app.py
new file mode 100644
index 00000000..f54c6c55
--- /dev/null
+++ b/examples/agent/langgraph-telecom-agent/app.py
@@ -0,0 +1,187 @@
+"""
+A demo Telecom Customer Service Agent using Chainlit and LangGraph, with Splunk AO as the evaluation platform.
+"""
+
+from typing import Any
+import chainlit as cl
+
+from langchain.schema.runnable.config import RunnableConfig
+from langchain_core.callbacks import Callbacks
+from langchain_core.messages import HumanMessage, AIMessage
+
+from dotenv import load_dotenv
+
+from splunk_ao import splunk_ao_context
+from splunk_ao.handlers.langchain import SplunkAOAsyncCallback
+
+from src.agents.supervisor_agent import (
+ create_supervisor_agent,
+)
+
+# Load environment variables from .env file
+load_dotenv()
+
+
+# Build the agent graph
+supervisor_agent = create_supervisor_agent()
+
+
+@cl.on_chat_start
+async def on_chat_start() -> None:
+ """
+ Handle the start of a chat session.
+
+ This function is called when a new chat session starts.
+ It initializes the chat with a welcome message.
+ """
+ create_galileo_session()
+
+
+def create_galileo_session():
+ """
+ Create a new Splunk AO session for tracking user interactions.
+
+ This session is then stored in the Chainlit user session for later use.
+ """
+ try:
+ # Start Splunk AO session with unique session name
+ splunk_ao_context.start_session(name="Telecom Agent", external_id=cl.context.session.id)
+
+ # Create the callback. This needs to be created in the same thread as the session
+ # so that it uses the same session context.
+ galileo_callback = SplunkAOAsyncCallback()
+ cl.user_session.set("galileo_callback", galileo_callback)
+
+ # Store session info in user session for later use
+ cl.user_session.set("galileo_session_started", True)
+
+ except Exception as e:
+ print(f"❌ Failed to start Splunk AO session: {str(e)}")
+ # Continue without Splunk AO rather than failing completely
+ cl.user_session.set("galileo_session_started", False)
+
+
+@cl.on_message
+async def main(msg: cl.Message) -> None:
+ """
+ Handle the message from the user.
+
+ param message: The message object containing user input.
+ """
+ # Create a config using the current Chainlit session ID. This is linked to the memory saver in the graph
+ # to allow you to continue the conversation with the same context.
+ config: dict[str, Any] = {"configurable": {"thread_id": cl.context.session.id}}
+
+ # Prepare the final answer message to stream the response back to the user
+ final_answer = cl.Message(content="")
+
+ # Build the messages dictionary with the user's message
+ messages: dict[str, Any] = {"messages": [HumanMessage(content=msg.content)]}
+
+ # Create a callback handler to log the response to Splunk AO
+ callbacks: Callbacks = []
+ if cl.user_session.get("galileo_session_started", False):
+ galileo_callback = cl.user_session.get("galileo_callback")
+ callbacks: Callbacks = [galileo_callback] # type: ignore
+ else:
+ print("Splunk AO session not started, using default callbacks.")
+
+ # Set up the config for the streaming response
+ runnable_config = RunnableConfig(callbacks=callbacks, **config)
+
+ # Track agent steps for visibility
+ current_agent = None
+ current_step = None
+ step_counter = 0
+
+ # Debug: Log that we're starting
+ print(f"Starting to process message: {msg.content[:50]}...")
+
+ # Create main processing step
+ async with cl.Step(name="🎯 Processing Request", type="run", show_input=True) as main_step:
+ main_step.input = msg.content
+
+ # Call the graph with the user's message and stream the response back to the user
+ async for response_msg in supervisor_agent.astream(input=messages, stream_mode="updates", config=runnable_config):
+ # Debug: Log the response structure
+ print(f"Response keys: {response_msg.keys()}")
+
+ # Detect which agent is being called
+ for agent_name in response_msg.keys():
+ # Skip system nodes
+ if agent_name in ["__start__", "__end__", supervisor_agent.name]:
+ continue
+
+ # New agent detected - create a step for it
+ if agent_name and agent_name != current_agent:
+ # Close previous step if exists
+ if current_step:
+ current_step.output = "✅ Completed"
+ await current_step.update()
+
+ # Create new step for this agent
+ step_counter += 1
+ agent_display_name = agent_name.replace("-", " ").replace("_", " ").title()
+
+ current_step = cl.Step(name=f"Step {step_counter}: {agent_display_name}", type="tool")
+ current_step.input = "Processing..."
+ await current_step.send()
+ current_agent = agent_name
+
+ # Show what the agent is doing
+ if "messages" in response_msg[agent_name]:
+ agent_messages = response_msg[agent_name]["messages"]
+ if agent_messages:
+ last_msg = agent_messages[-1]
+ if hasattr(last_msg, "content") and last_msg.content:
+ current_step.output = f"Working: {last_msg.content[:100]}..."
+ await current_step.update()
+
+ # Check for supervisor's routing decision
+ if supervisor_agent.name in response_msg:
+ if "next" in response_msg[supervisor_agent.name]:
+ next_agent = response_msg[supervisor_agent.name]["next"]
+ if next_agent and next_agent != "__end__":
+ # Show routing decision
+ routing_step = cl.Step(
+ name=f"🔀 Routing to {next_agent.replace('-', ' ').title()}",
+ type="llm",
+ )
+ routing_step.input = "Analyzing request and routing..."
+ routing_step.output = f"Selected: {next_agent}"
+ await routing_step.send()
+
+ # Check for a response from the supervisor agent with the final message
+ if supervisor_agent.name in response_msg and "messages" in response_msg[supervisor_agent.name]:
+ # Get the last message from the supervisor's response
+ message = response_msg[supervisor_agent.name]["messages"][-1]
+ # If it is an AI message, then it is the final answer
+ if isinstance(message, AIMessage) and message.content:
+ # Close any open step
+ if current_step:
+ current_step.output = "✅ Completed"
+ await current_step.update()
+
+ # Create final response step
+ response_step = cl.Step(name="📝 Final Response", type="llm")
+ response_step.input = "Generating response..."
+ await response_step.send()
+
+ # Stream the response
+ await final_answer.stream_token(message.content) # type: ignore
+
+ response_step.output = "Response delivered"
+ await response_step.update()
+
+ main_step.output = "✅ Request completed"
+
+ # Send the final answer message to the user
+ await final_answer.send()
+
+
+# This is the entry point for running the Chainlit application used for debugging
+# Otherwise to run this with hot reload, use `chainlit run app.py -w`
+if __name__ == "__main__":
+ from chainlit.cli import run_chainlit
+
+ run_chainlit(__file__)
diff --git a/examples/agent/langgraph-telecom-agent/chainlit.md b/examples/agent/langgraph-telecom-agent/chainlit.md
new file mode 100644
index 00000000..4507ac46
--- /dev/null
+++ b/examples/agent/langgraph-telecom-agent/chainlit.md
@@ -0,0 +1,14 @@
+# Welcome to Chainlit! 🚀🤖
+
+Hi there, Developer! 👋 We're excited to have you on board. Chainlit is a powerful tool designed to help you prototype, debug and share applications built on top of LLMs.
+
+## Useful Links 🔗
+
+- **Documentation:** Get started with our comprehensive [Chainlit Documentation](https://docs.chainlit.io) 📚
+- **Discord Community:** Join our friendly [Chainlit Discord](https://discord.gg/k73SQ3FyUh) to ask questions, share your projects, and connect with other developers! 💬
+
+We can't wait to see what you create with Chainlit! Happy coding! 💻😊
+
+## Welcome screen
+
+To modify the welcome screen, edit the `chainlit.md` file at the root of your project. If you do not want a welcome screen, just leave this file empty.
diff --git a/examples/agent/langgraph-telecom-agent/public/avatars/assistant.png b/examples/agent/langgraph-telecom-agent/public/avatars/assistant.png
new file mode 100644
index 00000000..114532c0
Binary files /dev/null and b/examples/agent/langgraph-telecom-agent/public/avatars/assistant.png differ
diff --git a/examples/agent/langgraph-telecom-agent/public/avatars/tool.png b/examples/agent/langgraph-telecom-agent/public/avatars/tool.png
new file mode 100644
index 00000000..e7c061e8
Binary files /dev/null and b/examples/agent/langgraph-telecom-agent/public/avatars/tool.png differ
diff --git a/examples/agent/langgraph-telecom-agent/public/logo_dark.png b/examples/agent/langgraph-telecom-agent/public/logo_dark.png
new file mode 100644
index 00000000..3a3417d2
Binary files /dev/null and b/examples/agent/langgraph-telecom-agent/public/logo_dark.png differ
diff --git a/examples/agent/langgraph-telecom-agent/public/logo_light.png b/examples/agent/langgraph-telecom-agent/public/logo_light.png
new file mode 100644
index 00000000..379ff554
Binary files /dev/null and b/examples/agent/langgraph-telecom-agent/public/logo_light.png differ
diff --git a/examples/agent/langgraph-telecom-agent/pyproject.toml b/examples/agent/langgraph-telecom-agent/pyproject.toml
new file mode 100644
index 00000000..6d605536
--- /dev/null
+++ b/examples/agent/langgraph-telecom-agent/pyproject.toml
@@ -0,0 +1,28 @@
+[project]
+name = "galileo-langgraph-telecom-agent"
+version = "0.1.0"
+description = "A demo langgraph Telecom Services agent with Splunk AO evaluations"
+license = "MIT"
+requires-python = "<3.14,>=3.11"
+dependencies = [
+ "chainlit~=2.5.5",
+ "galileo (>=1.20.0,<2.0.0)",
+ "grandalf>=0.8",
+ "langchain-community>=0.3.24",
+ "langchain-pinecone>=0.2.6",
+ "langchain[openai]~=0.3.18",
+ "langgraph~=0.4.7",
+ "langgraph-supervisor>=0.0.26",
+ "pinecone[asyncio]>=6.0.2",
+ "python-dotenv>=1.1.0",
+]
+
+[dependency-groups]
+dev = [
+ "ruff>=0.11.11",
+ "pytest (>=8.4.1,<9.0.0)",
+ "pytest-dotenv>=0.5.2"
+]
+
+[tool.ruff]
+line-length = 120
diff --git a/examples/agent/langgraph-telecom-agent/scripts/setup_pinecone.py b/examples/agent/langgraph-telecom-agent/scripts/setup_pinecone.py
new file mode 100644
index 00000000..d8644451
--- /dev/null
+++ b/examples/agent/langgraph-telecom-agent/scripts/setup_pinecone.py
@@ -0,0 +1,177 @@
+"""
+This script sets up a Pinecone index for storing and retrieving telecom documentation from the `source-docs` folder.
+
+The script will upload:
+- Telecom plan information (pricing, features, comparisons)
+- Network troubleshooting guides
+- Technical documentation
+
+To use this, you will need to have the following environment variables set in the .env file:
+- `PINECONE_API_KEY`: Your Pinecone API key.
+- `OPENAI_API_KEY`: Your OpenAI API key (for embeddings).
+"""
+
+import asyncio
+import os
+
+from dotenv import load_dotenv
+
+from langchain.text_splitter import RecursiveCharacterTextSplitter
+
+from langchain_community.document_loaders import DirectoryLoader, TextLoader
+from langchain_openai import OpenAIEmbeddings
+from langchain_pinecone import PineconeVectorStore
+
+from pinecone import Pinecone
+
+load_dotenv()
+
+EMBEDDINGS = OpenAIEmbeddings()
+PINECONE_API_KEY = os.getenv("PINECONE_API_KEY")
+
+
+def load_documents(path):
+ """Load all markdown documents from source-docs folder"""
+ loader = DirectoryLoader(path, glob="*.md", loader_cls=TextLoader, loader_kwargs={"encoding": "utf-8"})
+ documents = loader.load()
+ return documents
+
+
+def chunk_documents(documents):
+ """Chunk documents semantically"""
+ text_splitter = RecursiveCharacterTextSplitter(
+ chunk_size=1000,
+ chunk_overlap=200,
+ length_function=len,
+ separators=[
+ "\n\n", # Double newlines (paragraphs)
+ "\n", # Single newlines
+ " ", # Spaces
+ ".", # Sentences
+ ",", # Clauses
+ "\u200b", # Zero-width space
+ "\uff0c", # Fullwidth comma
+ "\u3001", # Ideographic comma
+ "\uff0e", # Fullwidth full stop
+ "\u3002", # Ideographic full stop
+ "", # Character-level
+ ],
+ is_separator_regex=False,
+ )
+
+ chunked_docs = text_splitter.split_documents(documents)
+ return chunked_docs
+
+
+def setup_pinecone_index(index_name: str) -> None:
+ """Initialize Pinecone and create/connect to index"""
+ pc = Pinecone(api_key=PINECONE_API_KEY)
+
+ # Check if index exists, create if not
+ if index_name not in pc.list_indexes().names():
+ print(f"Creating new index: {index_name}")
+ pc.create_index(
+ name=index_name,
+ dimension=1536, # OpenAI embeddings dimension
+ metric="cosine",
+ spec={"serverless": {"cloud": "aws", "region": "us-east-1"}},
+ )
+ else:
+ print(f"Index {index_name} already exists")
+
+
+def check_index_has_data(index) -> bool:
+ """Check if the index already contains data"""
+ try:
+ stats = index.describe_index_stats()
+ total_vector_count = stats.get("total_vector_count", 0)
+ return total_vector_count > 0
+ except Exception as e:
+ print(f"Error checking index stats: {e}")
+ return False
+
+
+def upload_to_pinecone(chunked_docs, index_name: str, force_upload: bool = False) -> PineconeVectorStore:
+ """Upload chunked documents to Pinecone"""
+
+ # Check if index has data and we're not forcing upload
+ if not force_upload:
+ pc = Pinecone(api_key=PINECONE_API_KEY)
+ index = pc.Index(index_name)
+
+ if check_index_has_data(index):
+ print(f"Index {index_name} already contains data. Skipping upload.")
+ print("Use force_upload=True to overwrite existing data.")
+ return PineconeVectorStore(index_name=index_name, embedding=EMBEDDINGS)
+
+ # Create vector store and upload
+ print(f"Uploading {len(chunked_docs)} chunks to Pinecone...")
+ vector_store = PineconeVectorStore.from_documents(documents=chunked_docs, embedding=EMBEDDINGS, index_name=index_name)
+
+ print(f"Successfully uploaded {len(chunked_docs)} document chunks to Pinecone")
+ return vector_store
+
+
+def test_retrieval(index_name: str, query: str):
+ """Test document retrieval from Pinecone"""
+ vector_store = PineconeVectorStore(index_name=index_name, embedding=EMBEDDINGS)
+
+ # Test similarity search
+ results = vector_store.similarity_search(query, k=3)
+
+ print(f"\nTest query: '{query}'")
+ print(f"Found {len(results)} relevant chunks:")
+ for i, doc in enumerate(results, 1):
+ print(f"\n{i}. {doc.page_content[:200]}...")
+
+
+telecom_documents = [
+ {
+ "index_name": "telecom",
+ "path": "source-docs",
+ "test_query": "unlimited data plan",
+ }
+]
+
+
+async def main():
+ """
+ Main function to process and upload documents asynchronously
+ """
+
+ for doc in telecom_documents:
+ index_name = doc["index_name"]
+ path = doc["path"]
+ test_query = doc["test_query"]
+
+ print(f"Loading documents for {index_name} folder...")
+ loaded_documents = load_documents(path)
+ print(f"Loaded {len(loaded_documents)} documents")
+
+ print(f"Chunking documents for {index_name}...")
+ chunked_docs = chunk_documents(loaded_documents)
+ print(f"Created {len(chunked_docs)} chunks")
+
+ print(f"Setting up Pinecone for {index_name}...")
+ setup_pinecone_index(index_name)
+
+ # Only upload if index is new or doesn't have data
+ print(f"Uploading to Pinecone for {index_name}...")
+ _ = upload_to_pinecone(chunked_docs, index_name=index_name)
+
+ # Wait for Pinecone to index the data
+ print("Waiting for Pinecone to index the data...")
+ await asyncio.sleep(30)
+
+ # Test retrieval for each index
+ for doc in telecom_documents:
+ index_name = doc["index_name"]
+ test_query = doc["test_query"]
+ print(f"Testing retrieval for {index_name} with query: '{test_query}'")
+ test_retrieval(index_name=index_name, query=test_query)
+
+ print("✅ Document processing and upload complete!")
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/examples/agent/langgraph-telecom-agent/source-docs/network-troubleshooting.md b/examples/agent/langgraph-telecom-agent/source-docs/network-troubleshooting.md
new file mode 100644
index 00000000..ee330b9c
--- /dev/null
+++ b/examples/agent/langgraph-telecom-agent/source-docs/network-troubleshooting.md
@@ -0,0 +1,195 @@
+# Network Troubleshooting Guide
+
+## Common Network Issues and Solutions
+
+### No Signal / No Service
+
+#### Symptoms
+- "No Service" or "Searching" message
+- Unable to make calls or send texts
+- No data connection
+
+#### Solutions
+1. **Toggle Airplane Mode**
+ - Turn ON for 30 seconds
+ - Turn OFF and wait for reconnection
+
+2. **Restart Device**
+ - Power off completely
+ - Wait 30 seconds
+ - Power on
+
+3. **Check SIM Card**
+ - Remove and reinsert SIM
+ - Clean SIM contacts with soft cloth
+ - Try SIM in another device
+
+4. **Reset Network Settings**
+ - iOS: Settings > General > Reset > Reset Network Settings
+ - Android: Settings > System > Reset > Reset Network Settings
+
+5. **Update Carrier Settings**
+ - iOS: Settings > General > About (prompt appears if update available)
+ - Android: Settings > System > Advanced > System Update
+
+### Slow Data Speeds
+
+#### Symptoms
+- Web pages loading slowly
+- Video buffering frequently
+- Apps timing out
+- Speed test shows <5 Mbps
+
+#### Solutions
+1. **Check Network Type**
+ - Ensure 5G/4G is enabled
+ - iOS: Settings > Cellular > Cellular Data Options > Voice & Data
+ - Android: Settings > Network & Internet > Mobile Network > Preferred Network Type
+
+2. **Clear Cache**
+ - Browser cache and cookies
+ - App cache for problematic apps
+ - System cache partition (Android)
+
+3. **Disable Background Apps**
+ - Turn off background app refresh
+ - Close unused apps
+ - Disable auto-updates on cellular
+
+4. **Check Data Throttling**
+ - Verify you haven't exceeded high-speed data limit
+ - Check for network congestion in area
+ - Consider upgrading plan if consistently throttled
+
+5. **APN Settings Reset**
+ - Reset to default ConnectTel APN
+ - APN: fast.connecttel.com
+ - MMS Proxy: Leave blank
+ - Port: 8080
+
+### Call Quality Issues
+
+#### Symptoms
+- Dropped calls
+- Static or echo
+- One-way audio
+- Calls not connecting
+
+#### Solutions
+1. **Enable HD Voice/VoLTE**
+ - Improves call quality significantly
+ - iOS: Settings > Cellular > Cellular Data Options > Enable LTE > Voice & Data
+ - Android: Settings > Network & Internet > Mobile Network > VoLTE
+
+2. **WiFi Calling Setup**
+ - Use when cellular signal is weak
+ - Requires stable WiFi (minimum 1 Mbps)
+ - Update E911 address for emergency services
+
+3. **Disable Bluetooth**
+ - Disconnect Bluetooth devices
+ - Test if call quality improves
+ - Re-pair devices if needed
+
+4. **Network Selection**
+ - Switch from automatic to manual
+ - Select ConnectTel network specifically
+ - Avoid roaming networks if possible
+
+### Text Message Issues
+
+#### Symptoms
+- Messages not sending/receiving
+- Delayed message delivery
+- Group messages not working
+- MMS failures
+
+#### Solutions
+1. **Check Message Settings**
+ - Verify phone number is correct
+ - Enable MMS messaging
+ - Check blocked numbers list
+
+2. **Reset Message App**
+ - Clear app cache and data
+ - Set as default messaging app
+ - Update to latest version
+
+3. **iMessage Troubleshooting (iOS)**
+ - Sign out and back into iMessage
+ - Verify phone number is checked
+ - Reset iMessage: Settings > Messages > Send & Receive
+
+4. **RCS Troubleshooting (Android)**
+ - Verify RCS is enabled
+ - Clear Google Messages cache
+ - Re-verify phone number
+
+## Advanced Troubleshooting
+
+### Network Diagnostic Codes
+
+- `*#*#4636#*#*` - Network information (Android)
+- `*3001#12345#*` - Field Test Mode (iPhone)
+- `*#06#` - Display IMEI
+- `*225#` - Account balance check
+- `##72786#` - Network reset (carrier-specific)
+
+### Signal Strength Guide
+
+| dBm Range | Signal Quality | Expected Performance |
+|-----------|---------------|---------------------|
+| -50 to -79 | Excellent | Full speed, no issues |
+| -80 to -89 | Good | Normal performance |
+| -90 to -99 | Fair | Slower speeds possible |
+| -100 to -109 | Poor | Connection issues likely |
+| -110+ | No Signal | Service unavailable |
+
+### Tower Connection Issues
+
+1. **Force Tower Refresh**
+ - Dial `*228` (CDMA) or `*#*#72786#*#*` (GSM)
+ - Select option 2 for roaming update
+
+2. **Preferred Roaming List Update**
+ - Ensures connection to newest towers
+ - Updates automatically monthly
+ - Manual update: `*228` option 2
+
+3. **Band Selection** (Advanced)
+ - Some devices allow manual band selection
+ - Useful in areas with specific band congestion
+ - Access via service menus (device-specific)
+
+## Network Technology Guide
+
+### 5G Networks
+- **5G Ultra Wideband**: Fastest speeds (1+ Gbps possible)
+- **5G Nationwide**: Broader coverage, moderate speeds
+- **Requirements**: 5G-capable device and plan
+
+### 4G LTE
+- **LTE+/LTE-A**: Enhanced LTE with carrier aggregation
+- **Standard LTE**: Reliable, widespread coverage
+- **VoLTE**: Voice over LTE for better call quality
+
+### Network Priorities
+1. **Premium Data**: First 50-200GB depending on plan
+2. **Standard Data**: After premium allowance
+3. **Deprioritized**: During network congestion
+4. **Safety Mode**: 128 Kbps after data limit
+
+## When to Contact Support
+
+Contact technical support if:
+- Issues persist after all troubleshooting
+- Hardware damage suspected
+- Account-specific problems
+- Multiple devices affected
+- Consistent issues in multiple locations
+
+**Support Channels**
+- Phone: 1-800-TELECOM (24/7)
+- Chat: connecttel.com/support
+- App: ConnectTel Mobile App
+- Store: Find nearest location
\ No newline at end of file
diff --git a/examples/agent/langgraph-telecom-agent/source-docs/telecom-plans.md b/examples/agent/langgraph-telecom-agent/source-docs/telecom-plans.md
new file mode 100644
index 00000000..8cd1edde
--- /dev/null
+++ b/examples/agent/langgraph-telecom-agent/source-docs/telecom-plans.md
@@ -0,0 +1,118 @@
+# ConnectTel Mobile Plans
+
+## Individual Plans
+
+### Basic Essential
+- **Price**: $65/month
+- **Data**: 50GB high-speed data
+- **Speed**: 4G LTE (5G where available)
+- **Talk & Text**: Unlimited domestic
+- **Hotspot**: 10GB
+- **International**: Text to 120+ countries
+- **Perks**: Basic streaming (480p)
+
+### Premium Unlimited 5G
+- **Price**: $85/month
+- **Data**: Truly unlimited premium data
+- **Speed**: 5G Ultra Wideband access
+- **Talk & Text**: Unlimited domestic
+- **Hotspot**: Unlimited (50GB high-speed)
+- **International**: Text to 200+ countries, Talk to Canada/Mexico
+- **Perks**: HD streaming, 6 months Apple Music, Travel Pass discount
+
+### Business Elite
+- **Price**: $120/month
+- **Data**: 200GB priority data
+- **Speed**: 5G with network priority
+- **Talk & Text**: Unlimited domestic + international
+- **Hotspot**: 100GB high-speed
+- **International**: Unlimited calling to 80+ countries
+- **Perks**: Microsoft 365, advanced security, dedicated support
+
+## Family Plans
+
+### Family Share 100GB
+- **Price**: $120/month (2 lines), $40/additional line
+- **Data**: 100GB shared data
+- **Speed**: 5G access for all lines
+- **Talk & Text**: Unlimited domestic
+- **Hotspot**: Shared from data pool
+- **International**: Text included
+- **Perks**: Disney+ included, parental controls
+
+### Family Unlimited Plus
+- **Price**: $180/month (3 lines), $50/additional line
+- **Data**: Unlimited for each line
+- **Speed**: 5G Ultra Wideband
+- **Talk & Text**: Unlimited
+- **Hotspot**: 30GB per line
+- **International**: Mexico/Canada included
+- **Perks**: Apple One subscription, device protection
+
+## Prepaid Plans
+
+### Prepaid Basic
+- **Price**: $35/month
+- **Data**: 15GB
+- **Speed**: 4G LTE
+- **Talk & Text**: Unlimited domestic
+- **No contract required**
+
+### Prepaid Unlimited
+- **Price**: $60/month
+- **Data**: Unlimited (deprioritized after 35GB)
+- **Speed**: 5G access
+- **Talk & Text**: Unlimited
+- **International texting included**
+
+## Special Plans
+
+### Senior 55+
+- **Price**: $55/month (2 lines for $80)
+- **Data**: Unlimited
+- **Special perks**: Fraud protection, simplified billing
+
+### Student Plan
+- **Price**: $45/month (with valid .edu email)
+- **Data**: 75GB
+- **Perks**: Spotify Premium included
+
+### First Responder/Military
+- **25% discount on any plan**
+- **Priority network access during emergencies**
+- **Free international roaming**
+
+## Add-Ons
+
+### International Pass
+- **Daily Pass**: $10/day (unlimited talk/text, 2GB data)
+- **Monthly Pass**: $70/month (unlimited talk/text, 15GB data)
+- **Countries**: 185+ destinations
+
+### Device Protection
+- **Basic**: $7/month (coverage up to $1,000)
+- **Premium**: $15/month (unlimited claims, same-day replacement)
+
+### Entertainment Bundles
+- **Streaming Pack**: $25/month (Netflix, Hulu, HBO Max)
+- **Sports Pack**: $15/month (ESPN+, NFL RedZone)
+- **Gaming Pack**: $20/month (Xbox Game Pass, 5G gaming priority)
+
+## Plan Features Comparison
+
+| Feature | Basic Essential | Premium Unlimited | Family Share | Business Elite |
+|---------|----------------|-------------------|--------------|----------------|
+| Priority Data | 50GB | Unlimited | 100GB shared | 200GB |
+| 5G Access | Limited | Ultra Wideband | Yes | Priority |
+| Hotspot | 10GB | Unlimited | Shared | 100GB |
+| International | Text only | Talk to 2 countries | Text only | 80+ countries |
+| Streaming Quality | 480p | 4K HDR | HD | 4K HDR |
+| Cloud Storage | 5GB | 50GB | 100GB shared | 1TB |
+
+## Promotional Offers (Current)
+
+1. **New Customer Special**: Get 3 months free when you switch
+2. **BOGO Deal**: Buy one line, get one free (24-month credits)
+3. **Trade-In Bonus**: Up to $800 off new device with eligible trade
+4. **Refer a Friend**: $50 credit for each successful referral
+5. **Auto-Pay Discount**: Save $10/month per line with auto-pay
\ No newline at end of file
diff --git a/examples/agent/langgraph-telecom-agent/src/__init__.py b/examples/agent/langgraph-telecom-agent/src/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/examples/agent/langgraph-telecom-agent/src/agents/__init__.py b/examples/agent/langgraph-telecom-agent/src/agents/__init__.py
new file mode 100644
index 00000000..a1c9e4f8
--- /dev/null
+++ b/examples/agent/langgraph-telecom-agent/src/agents/__init__.py
@@ -0,0 +1,13 @@
+"""Agents package for the Splunk AO LangGraph Telecom Agent."""
+
+from .billing_account_agent import create_billing_account_agent
+from .technical_support_agent import create_technical_support_agent
+from .plan_advisor_agent import create_plan_advisor_agent
+from .supervisor_agent import create_supervisor_agent
+
+__all__ = [
+ "create_billing_account_agent",
+ "create_technical_support_agent",
+ "create_plan_advisor_agent",
+ "create_supervisor_agent",
+]
diff --git a/examples/agent/langgraph-telecom-agent/src/agents/billing_account_agent.py b/examples/agent/langgraph-telecom-agent/src/agents/billing_account_agent.py
new file mode 100644
index 00000000..e328d151
--- /dev/null
+++ b/examples/agent/langgraph-telecom-agent/src/agents/billing_account_agent.py
@@ -0,0 +1,53 @@
+"""
+Billing and Account Management Agent for handling customer billing inquiries.
+"""
+
+import os
+from langchain_openai import ChatOpenAI
+from langgraph.graph.graph import CompiledGraph
+from langgraph.prebuilt import create_react_agent
+
+from ..tools.billing_tool import BillingTool
+
+# Create the billing tool
+billing_tool = BillingTool()
+
+
+def create_billing_account_agent() -> CompiledGraph:
+ """
+ Create an agent that handles billing inquiries, usage tracking, and account management.
+
+ returns: A compiled graph for this agent.
+ """
+
+ # Create an agent
+ agent = create_react_agent(
+ model=ChatOpenAI(model=os.environ["MODEL_NAME_WORKER"], name="Billing Account Agent"),
+ tools=[billing_tool],
+ prompt=(
+ """
+ You are a Billing and Account specialist for ConnectTel.
+ You help customers with billing inquiries, usage tracking, plan details, and payment issues.
+ Be helpful, accurate, and proactive in identifying potential savings.
+
+ Key responsibilities:
+ - Check account balances and payment due dates
+ - Track data, voice, and text usage
+ - Explain charges and fees clearly
+ - Suggest plan optimizations based on usage
+ - Process payment-related inquiries
+ - Review billing history
+
+ When discussing charges:
+ - Break down costs clearly
+ - Highlight any unusual charges
+ - Suggest ways to reduce bills if usage patterns show opportunity
+ - Always mention auto-pay discounts if not enrolled
+
+ Be empathetic about high bills and offer solutions.
+ """
+ ),
+ name="billing-account-agent",
+ )
+
+ return agent
diff --git a/examples/agent/langgraph-telecom-agent/src/agents/plan_advisor_agent.py b/examples/agent/langgraph-telecom-agent/src/agents/plan_advisor_agent.py
new file mode 100644
index 00000000..5148613d
--- /dev/null
+++ b/examples/agent/langgraph-telecom-agent/src/agents/plan_advisor_agent.py
@@ -0,0 +1,63 @@
+"""
+Plan Advisor Agent for recommending telecom plans and services based on customer needs.
+"""
+
+import os
+from langchain_openai import ChatOpenAI
+from langgraph.graph.graph import CompiledGraph
+from langgraph.prebuilt import create_react_agent
+
+from ..tools.pinecone_retrieval_tool import PineconeRetrievalTool
+
+# Create the plan information retrieval tool
+plan_information_retrieval_tool = PineconeRetrievalTool("telecom")
+
+
+def create_plan_advisor_agent() -> CompiledGraph:
+ """
+ Create an agent that recommends plans and services based on customer usage and needs.
+
+ returns: A compiled graph for this agent.
+ """
+
+ # Create an agent
+ agent = create_react_agent(
+ model=ChatOpenAI(model=os.environ["MODEL_NAME_WORKER"], name="Plan Advisor Agent"),
+ tools=[plan_information_retrieval_tool],
+ prompt=(
+ """
+ You are a Plan Advisor specialist for ConnectTel.
+ You analyze customer needs and recommend the most suitable plans and services.
+ Be consultative, honest, and focus on value rather than just upselling.
+
+ Key responsibilities:
+ - Analyze customer usage patterns
+ - Recommend suitable plans based on needs
+ - Explain plan features and benefits
+ - Compare plan options clearly
+ - Identify potential savings
+ - Suggest add-on services when beneficial
+
+ Consultation approach:
+ - First understand customer needs and usage
+ - Present 2-3 suitable options
+ - Clearly explain differences and trade-offs
+ - Highlight both savings and benefits
+ - Mention any current promotions
+ - Be transparent about any limitations
+
+ Plan categories to consider:
+ - Individual vs Family plans
+ - Prepaid vs Postpaid
+ - Data allowances and speeds
+ - International features
+ - Business vs Personal
+ - 5G access levels
+
+ Always prioritize customer needs over higher-priced plans.
+ """
+ ),
+ name="plan-advisor-agent",
+ )
+
+ return agent
diff --git a/examples/agent/langgraph-telecom-agent/src/agents/supervisor_agent.py b/examples/agent/langgraph-telecom-agent/src/agents/supervisor_agent.py
new file mode 100644
index 00000000..f9a47f5b
--- /dev/null
+++ b/examples/agent/langgraph-telecom-agent/src/agents/supervisor_agent.py
@@ -0,0 +1,60 @@
+"""
+Supervisor Agent for ConnectTel Telecom Application
+"""
+
+import os
+from langchain_openai import ChatOpenAI
+from langgraph_supervisor import create_supervisor
+from langgraph.checkpoint.memory import MemorySaver
+
+from .billing_account_agent import create_billing_account_agent
+from .technical_support_agent import create_technical_support_agent
+from .plan_advisor_agent import create_plan_advisor_agent
+
+# Define the agents that the supervisor will manage
+billing_account_agent = create_billing_account_agent()
+technical_support_agent = create_technical_support_agent()
+plan_advisor_agent = create_plan_advisor_agent()
+
+
+def create_supervisor_agent():
+ """
+ Create a supervisor agent that manages all the agents in the ConnectTel telecom application.
+ """
+ # Create a memory checkpointer to persist conversation history
+ checkpointer = MemorySaver()
+
+ telecom_supervisor_agent = create_supervisor(
+ model=ChatOpenAI(model=os.environ["MODEL_NAME_SUPERVISOR"], name="Supervisor"),
+ agents=[
+ billing_account_agent,
+ technical_support_agent,
+ plan_advisor_agent,
+ ],
+ prompt=(
+ """
+ You are a supervisor managing a team of specialized telecom service agents at ConnectTel.
+
+ Route customer queries to the appropriate agent based on their needs:
+
+ - Billing Account Agent: Bill inquiries, payment issues, usage tracking, account balance, charges, credit card information, credit score, etc.
+ - Technical Support Agent: Device troubleshooting, connectivity issues, configuration help, resets
+ - Plan Advisor Agent: Plan recommendations, upgrades, comparing plans, finding savings
+
+ Guidelines:
+ - Route queries to the most appropriate specialist agent
+ - For complex issues spanning multiple areas, coordinate between agents
+ - Be helpful and empathetic to customer concerns
+ - If unsure, ask clarifying questions before routing
+ - For general greetings, respond warmly before asking how you can help
+
+ If a query doesn't fit any agent's expertise, politely explain our service limitations.
+ """
+ ),
+ add_handoff_back_messages=True,
+ output_mode="full_history",
+ supervisor_name="connecttel-supervisor-agent",
+ ).compile(checkpointer=checkpointer)
+ telecom_supervisor_agent.name = "connecttel-supervisor-agent"
+
+ return telecom_supervisor_agent
diff --git a/examples/agent/langgraph-telecom-agent/src/agents/technical_support_agent.py b/examples/agent/langgraph-telecom-agent/src/agents/technical_support_agent.py
new file mode 100644
index 00000000..2f79c189
--- /dev/null
+++ b/examples/agent/langgraph-telecom-agent/src/agents/technical_support_agent.py
@@ -0,0 +1,58 @@
+"""
+Technical Support Agent for troubleshooting and device configuration.
+"""
+
+import os
+from langchain_openai import ChatOpenAI
+from langgraph.graph.graph import CompiledGraph
+from langgraph.prebuilt import create_react_agent
+
+from ..tools.technical_support_tool import TechnicalSupportTool
+from ..tools.pinecone_retrieval_tool import PineconeRetrievalTool
+
+# Create the technical support tool
+technical_support_tool = TechnicalSupportTool()
+
+# Create the plan information retrieval tool
+plan_information_retrieval_tool = PineconeRetrievalTool("telecom")
+
+
+def create_technical_support_agent() -> CompiledGraph:
+ """
+ Create an agent that provides technical support, troubleshooting, and device configuration help.
+
+ returns: A compiled graph for this agent.
+ """
+
+ # Create an agent
+ agent = create_react_agent(
+ model=ChatOpenAI(model=os.environ["MODEL_NAME_WORKER"], name="Technical Support Agent"),
+ tools=[technical_support_tool, plan_information_retrieval_tool],
+ prompt=(
+ """
+ You are a Technical Support specialist for ConnectTel.
+ You help customers troubleshoot connectivity issues, configure devices, and resolve technical problems.
+ Be patient, thorough, and provide step-by-step guidance.
+
+ Key responsibilities:
+ - Troubleshoot connectivity issues (no signal, slow speeds, call problems)
+ - Guide device configuration (APN settings, WiFi calling, etc.)
+ - Provide reset and recovery procedures
+ - Escalate complex issues when needed
+ - Educate customers on self-service options
+
+ Communication style:
+ - Use simple, non-technical language when possible
+ - Provide clear step-by-step instructions
+ - Confirm customer understanding before proceeding
+ - Offer multiple solution paths when available
+ - Always provide estimated resolution times
+
+ If basic troubleshooting fails, escalate to Level 2 support.
+ Document all attempted solutions for future reference.
+ """
+ ),
+ name="technical-support-agent",
+ )
+
+ return agent
diff --git a/examples/agent/langgraph-telecom-agent/src/tools/__init__.py b/examples/agent/langgraph-telecom-agent/src/tools/__init__.py
new file mode 100644
index 00000000..b1cd7056
--- /dev/null
+++ b/examples/agent/langgraph-telecom-agent/src/tools/__init__.py
@@ -0,0 +1,11 @@
+"""Tools package for the Splunk AO LangGraph Telecom Agent."""
+
+from .pinecone_retrieval_tool import PineconeRetrievalTool
+from .billing_tool import BillingTool
+from .technical_support_tool import TechnicalSupportTool
+
+__all__ = [
+ "PineconeRetrievalTool",
+ "BillingTool",
+ "TechnicalSupportTool",
+]
diff --git a/examples/agent/langgraph-telecom-agent/src/tools/billing_tool.py b/examples/agent/langgraph-telecom-agent/src/tools/billing_tool.py
new file mode 100644
index 00000000..db644b02
--- /dev/null
+++ b/examples/agent/langgraph-telecom-agent/src/tools/billing_tool.py
@@ -0,0 +1,81 @@
+"""
+Mock billing tool for telecom demo system.
+Returns simulated customer billing and usage data.
+"""
+
+from typing import Optional
+from langchain.tools import BaseTool
+from datetime import datetime, timedelta
+import random
+
+
+class BillingTool(BaseTool):
+ """Tool for retrieving customer billing and usage information."""
+
+ name: str = "billing_account"
+ description: str = "Check account balance, data usage, plan details, and billing history"
+
+ def _run(self, customer_id: Optional[str] = None, query_type: str = "summary") -> str:
+ """
+ Get billing and usage information.
+
+ Args:
+ customer_id: Customer account number (uses default if not provided)
+ query_type: Type of query (summary, usage, plan, history)
+ """
+ # Simple mock customer data
+ customer = {
+ "name": "John Doe",
+ "account": customer_id or "ACC-2024-789456",
+ "plan": "Premium Unlimited 5G",
+ "monthly_charge": 85.00,
+ "data_used": random.uniform(20, 80),
+ "data_limit": "Unlimited",
+ "due_date": (datetime.now() + timedelta(days=15)).strftime("%Y-%m-%d"),
+ }
+
+ if query_type == "usage":
+ return f"""
+Usage Summary for {customer['name']}:
+- Data: {customer['data_used']:.1f} GB used ({customer['data_limit']})
+- Minutes: {random.randint(300, 800)} (Unlimited)
+- Texts: {random.randint(500, 2000)} (Unlimited)
+- Average daily: {customer['data_used'] / 15:.2f} GB
+"""
+
+ elif query_type == "plan":
+ return f"""
+Current Plan: {customer['plan']}
+- Monthly Cost: ${customer['monthly_charge']:.2f}
+- Data: {customer['data_limit']}
+- Talk & Text: Unlimited
+- 5G Access: Included
+
+Available Upgrades:
+- Business Elite ($120/month)
+- International Plus ($95/month)
+"""
+
+ elif query_type == "history":
+ history = []
+ for i in range(3):
+ date = (datetime.now() - timedelta(days=30 * (i + 1))).strftime("%Y-%m-%d")
+ amount = customer["monthly_charge"] + random.uniform(-5, 15)
+ history.append(f"- {date}: ${amount:.2f} (Paid)")
+
+ return f"""
+Billing History:
+{chr(10).join(history)}
+
+Auto-pay: Enabled
+"""
+
+ # Default summary
+ return f"""
+Account Summary for {customer['name']}:
+- Account: {customer['account']}
+- Plan: {customer['plan']}
+- Amount Due: ${customer['monthly_charge']:.2f}
+- Due Date: {customer['due_date']}
+- Data Used: {customer['data_used']:.1f} GB ({customer['data_limit']})
+"""
diff --git a/examples/agent/langgraph-telecom-agent/src/tools/pinecone_retrieval_tool.py b/examples/agent/langgraph-telecom-agent/src/tools/pinecone_retrieval_tool.py
new file mode 100644
index 00000000..b86ad5b0
--- /dev/null
+++ b/examples/agent/langgraph-telecom-agent/src/tools/pinecone_retrieval_tool.py
@@ -0,0 +1,114 @@
+"""
+Tool for retrieving information from Pinecone vector database.
+Falls back to mock data if Pinecone is not configured.
+"""
+
+from langchain.tools import BaseTool
+from pydantic import BaseModel, Field
+
+
+class RetrievalInput(BaseModel):
+ """Input schema for document retrieval."""
+
+ query: str = Field(description="Search query")
+ k: int = Field(default=3, description="Number of documents to retrieve")
+
+
+class PineconeRetrievalTool(BaseTool):
+ """Tool for retrieving telecom plan and service information."""
+
+ name: str = "pinecone_retrieval"
+ description: str = "Retrieve telecom plans and service information from knowledge base"
+ args_schema: type[BaseModel] = RetrievalInput
+
+ def __init__(self, index_name: str = "telecom"):
+ super().__init__()
+ self._index_name = index_name
+ self._vector_store = None
+
+ # Try to initialize Pinecone, fallback to mock if unavailable
+ try:
+ from langchain_pinecone import PineconeVectorStore
+ from langchain_openai import OpenAIEmbeddings
+
+ self._embeddings = OpenAIEmbeddings()
+ self._vector_store = PineconeVectorStore(index_name=self._index_name, embedding=self._embeddings)
+ except Exception:
+ # Use mock data if Pinecone not configured
+ pass
+
+ def _get_mock_results(self, query: str) -> str:
+ """Return mock plan data when Pinecone unavailable."""
+
+ mock_data = {
+ "unlimited": """
+Premium Unlimited 5G Plan:
+- Price: $85/month
+- Data: Truly unlimited
+- Speed: 5G where available
+- Hotspot: 50GB high-speed
+- Perks: Netflix Basic included
+""",
+ "family": """
+Family Share Plans:
+- 2 lines: $120/month (100GB shared)
+- 3 lines: $150/month (150GB shared)
+- 4+ lines: $180/month (200GB shared)
+- All plans include unlimited talk/text
+""",
+ "business": """
+Business Plans:
+- Essential: $45/line (25GB)
+- Professional: $65/line (50GB)
+- Enterprise: $85/line (unlimited)
+- All include priority support
+""",
+ "international": """
+International Features:
+- Global Pass: $10/day (200+ countries)
+- International Plus: +$15/month
+- Unlimited texting to 200+ countries
+- Call rates from $0.25/minute
+""",
+ }
+
+ # Simple keyword matching
+ query_lower = query.lower()
+ for key, value in mock_data.items():
+ if key in query_lower:
+ return value
+
+ # Default response
+ return """
+Available Plans:
+- Premium Unlimited 5G ($85/month)
+- Family Share (from $120/month)
+- Business Plans (from $45/line)
+- Basic Essential ($65/month)
+
+Ask about specific plans for details.
+"""
+
+ def _run(self, query: str, k: int = 3) -> str:
+ """Execute retrieval from vector store or mock data."""
+
+ if self._vector_store:
+ try:
+ # Try Pinecone retrieval
+ results = self._vector_store.similarity_search(query, k=k)
+
+ if not results:
+ return "No relevant information found."
+
+ formatted = []
+ for i, doc in enumerate(results, 1):
+ formatted.append(f"Result {i}:\n{doc.page_content}\n")
+
+ return "\n".join(formatted)
+
+ except Exception:
+ # Fallback to mock on error
+ pass
+
+ # Use mock data
+ return self._get_mock_results(query)
diff --git a/examples/agent/langgraph-telecom-agent/src/tools/technical_support_tool.py b/examples/agent/langgraph-telecom-agent/src/tools/technical_support_tool.py
new file mode 100644
index 00000000..0fd7184e
--- /dev/null
+++ b/examples/agent/langgraph-telecom-agent/src/tools/technical_support_tool.py
@@ -0,0 +1,109 @@
+"""
+Mock technical support tool for telecom demo system.
+Provides troubleshooting steps and device configuration assistance.
+"""
+
+from typing import Optional
+from langchain.tools import BaseTool
+from datetime import datetime, timedelta
+import random
+
+
+class TechnicalSupportTool(BaseTool):
+ """Tool for troubleshooting and technical support."""
+
+ name: str = "technical_support"
+ description: str = "Troubleshoot connectivity issues, configure devices, and provide technical solutions"
+
+ def _run(self, issue_type: Optional[str] = None, action: str = "help") -> str:
+ """
+ Provide technical support.
+
+ Args:
+ issue_type: Type of issue (no_signal, slow_internet, calls, wifi_calling)
+ action: Action to take (help, troubleshoot, configure, escalate)
+ """
+
+ # Troubleshooting guides
+ guides = {
+ "no_signal": """
+No Signal Troubleshooting:
+1. Toggle Airplane Mode on/off
+2. Restart device
+3. Check SIM card
+4. Reset network settings
+5. Update carrier settings
+Time: 5-10 minutes
+""",
+ "slow_internet": """
+Slow Internet Fix:
+1. Check network type (5G/4G)
+2. Run speed test
+3. Clear cache
+4. Disable background apps
+5. Reset APN settings
+Time: 10-15 minutes
+""",
+ "calls": """
+Call Issues Fix:
+1. Check Do Not Disturb
+2. Verify blocked numbers
+3. Enable VoLTE/HD Voice
+4. Reset network settings
+5. Check account status
+Time: 5-8 minutes
+""",
+ "wifi_calling": """
+WiFi Calling Setup:
+1. Settings > Phone > Wi-Fi Calling
+2. Toggle ON
+3. Update E911 address
+4. Ensure stable WiFi
+5. Wait 2-3 minutes
+Time: 3-5 minutes
+""",
+ }
+
+ if action == "escalate":
+ ticket_id = f"TECH-{random.randint(1000, 9999)}"
+ return f"""
+Support Ticket Created: {ticket_id}
+Priority: High
+Response Time: Within 2 hours
+Callback: {(datetime.now() + timedelta(hours=2)).strftime('%Y-%m-%d %H:%M')}
+24/7 Support: 1-800-TELECOM
+"""
+
+ if action == "configure":
+ return """
+Device Configuration:
+iPhone: Settings > Cellular > Cellular Data Options
+- APN: wholesale
+- Leave username/password blank
+
+Android: Settings > Network > Mobile > APN
+- APN: fast.t-mobile.com
+- APN Type: default,supl,mms
+
+Restart device after changes.
+"""
+
+ if issue_type and issue_type in guides:
+ return guides[issue_type]
+
+ # Default help menu
+ return """
+Technical Support Options:
+- no_signal: Fix service issues
+- slow_internet: Improve speeds
+- calls: Voice call problems
+- wifi_calling: Setup guide
+
+Actions:
+- configure: Device setup
+- escalate: Create ticket
+
+Quick Codes:
+- Signal info: *3001#12345#*
+- Network reset: *#*#72786#*#*
+"""
diff --git a/examples/agent/langgraph-traceloop/.env.example b/examples/agent/langgraph-traceloop/.env.example
new file mode 100644
index 00000000..667d4ecc
--- /dev/null
+++ b/examples/agent/langgraph-traceloop/.env.example
@@ -0,0 +1,12 @@
+# Galileo Configuration
+# Get your API key from: https://app.galileo.ai/settings/api-keys
+GALILEO_API_KEY=your_galileo_api_key_here
+
+# Galileo console URL (change if using a custom deployment)
+TRACELOOP_BASE_URL="https://api.galileo.ai/otel"
+TRACELOOP_HEADERS="Galileo-API-Key=your_galileo_api_key_here, project=traceloop, logstream=default, X-Use-Otel-New=true"
+TRACELOOP_METRICS_ENABLED=false
+
+# OpenAI Configuration
+# Get your API key from: https://platform.openai.com/api-keys
+OPENAI_API_KEY=your_openai_api_key_here
diff --git a/examples/agent/langgraph-traceloop/.gitignore b/examples/agent/langgraph-traceloop/.gitignore
new file mode 100644
index 00000000..da2b44d8
--- /dev/null
+++ b/examples/agent/langgraph-traceloop/.gitignore
@@ -0,0 +1,55 @@
+# Python
+__pycache__/
+*.py[cod]
+*$py.class
+*.so
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# Virtual Environment
+.venv/
+venv/
+ENV/
+env/
+
+# Environment variables
+.env
+.env.local
+
+# UV
+.uv/
+uv.lock
+
+# IDE
+.vscode/
+.idea/
+*.swp
+*.swo
+*~
+.DS_Store
+
+# Logs
+*.log
+
+# Testing
+.pytest_cache/
+.coverage
+htmlcov/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
diff --git a/examples/agent/langgraph-traceloop/README.md b/examples/agent/langgraph-traceloop/README.md
new file mode 100644
index 00000000..072b5cec
--- /dev/null
+++ b/examples/agent/langgraph-traceloop/README.md
@@ -0,0 +1,63 @@
+# LangGraph + Traceloop + Splunk AO Integration
+
+This example demonstrates how to add comprehensive observability to your LangGraph AI workflows using **Traceloop** (OpenLLMetry) and Splunk AO. Traceloop provides a simpler alternative to direct OpenTelemetry instrumentation while still giving you detailed traces showing execution flow, LLM calls, token usage, and input/output data.
+
+
+## Quick start
+
+### Prerequisites
+
+- Python 3.12+
+- [UV package manager](https://docs.astral.sh/uv/getting-started/installation/)
+- [Splunk AO account](https://app.galileo.ai) (free)
+- OpenAI API key
+
+### Installation
+
+```bash
+# Clone and navigate
+git clone https://github.com/rungalileo/sdk-examples
+cd sdk-examples/python/agent/langgraph-traceloop
+
+# Install dependencies
+uv sync
+
+# Create environment file
+cp .env.example .env
+# Edit .env with your API keys (see below)
+```
+
+### Environment variables
+
+Create a `.env` file in the project root with the following variables:
+
+```bash
+# Your Splunk AO API key (get from https://app.galileo.ai/settings/api-keys)
+
+TRACELOOP_BASE_URL=https://api.galileo.ai/otel
+
+TRACELOOP_HEADERS="Galileo-API-Key=your_splunk_ao_api_key_here, project=traceloop, logstream=default, X-Use-Otel-New=true"
+
+# Your OpenAI API key
+OPENAI_API_KEY=your_openai_api_key_here
+```
+
+| Variable | Required | Description |
+| -------------------- | -------- | ----------------------------------------------------------------------- |
+| `TRACELOOP_BASE_URL` | Yes | The base URL for the Traceloop Client it will send traces to galileo |
+| `TRACELOOP_HEADERS` | Yes | The headers for the Traceloop Client to send to galileo |
+| `OPENAI_API_KEY` | Yes | Your OpenAI API key from [OpenAI](https://platform.openai.com/api-keys) |
+
+### Run
+
+```bash
+uv run python main.py
+```
+
+This runs a question-answering LangGraph workflow with comprehensive Traceloop tracing. Check your Splunk AO project for detailed traces!
+
+## Example Trace in Splunk AO
+
+After running the agent, you'll see a detailed trace in the Splunk AO UI showing the complete execution flow:
+
+
diff --git a/examples/agent/langgraph-traceloop/agent.py b/examples/agent/langgraph-traceloop/agent.py
new file mode 100644
index 00000000..44e7b052
--- /dev/null
+++ b/examples/agent/langgraph-traceloop/agent.py
@@ -0,0 +1,201 @@
+import os
+from typing import TypedDict, Annotated
+import dotenv
+
+import openai
+from langgraph.graph import END, StateGraph, add_messages
+from langgraph.prebuilt import ToolNode
+from langchain_core.tools import tool
+from langchain_core.messages import BaseMessage
+from langchain_openai import ChatOpenAI
+
+dotenv.load_dotenv()
+
+openai_api_key = os.environ.get("OPENAI_API_KEY")
+if not openai_api_key:
+ raise ValueError("OPENAI_API_KEY environment variable is required")
+
+# Initialize OpenAI client for tool usage
+client = openai.OpenAI(api_key=openai_api_key)
+print("OpenAI client configured")
+
+
+# ============================================================================
+# TOOL DEFINITIONS
+# ============================================================================
+
+
+@tool
+def validate_input_tool(user_input: str) -> str:
+ """
+ Validates and prepares the user input for processing.
+
+ Args:
+ user_input: The user's input question to validate
+
+ Returns:
+ The validated user input
+ """
+ print(f"[TOOL] Validating input: '{user_input}'")
+
+ if not user_input or len(user_input.strip()) == 0:
+ return "Error: Empty input provided"
+
+ return user_input.strip()
+
+
+@tool
+def generate_response_tool(user_input: str) -> str:
+ """
+ Generates a response from OpenAI based on the user input.
+
+ Args:
+ user_input: The validated user input question
+
+ Returns:
+ The LLM's response to the question
+ """
+ try:
+ print(f"[TOOL] Calling OpenAI with: '{user_input}'")
+
+ # Make the OpenAI API call - Traceloop automatically traces this
+ response = client.chat.completions.create(
+ model="gpt-3.5-turbo",
+ messages=[{"role": "user", "content": user_input}],
+ max_tokens=300,
+ temperature=0.7,
+ )
+
+ # Extract the response content
+ llm_response = response.choices[0].message.content
+
+ if not llm_response:
+ print("No response from OpenAI")
+ return "Error: No response from OpenAI"
+ else:
+ print(f"Received response: '{llm_response[:100]}...'")
+
+ return llm_response
+
+ except Exception as e:
+ print(f"Error calling OpenAI: {e}")
+ return f"Error: {str(e)}"
+
+
+@tool
+def format_answer_tool(llm_response: str) -> str:
+ """
+ Formats and cleans up the LLM response into a concise answer.
+
+ Args:
+ llm_response: The raw response from the LLM
+
+ Returns:
+ A formatted and cleaned answer
+ """
+ print(f"[TOOL] Formatting answer from: '{llm_response[:50]}...'")
+
+ # Simple parsing - extract first sentence for a concise answer
+ sentences = llm_response.split(". ")
+ parsed_answer = sentences[0] if sentences else llm_response
+
+ # Clean up the answer
+ parsed_answer = parsed_answer.strip()
+ if not parsed_answer.endswith(".") and parsed_answer:
+ parsed_answer += "."
+
+ print(f"Parsed answer: '{parsed_answer}'")
+
+ return parsed_answer
+
+
+# List of all available tools
+tools = [validate_input_tool, generate_response_tool, format_answer_tool]
+
+
+# ============================================================================
+# STATE DEFINITION
+# ============================================================================
+
+
+class AgentState(TypedDict):
+ # The add_messages reducer handles message list updates properly
+ # It ensures messages are appended correctly without duplication
+ messages: Annotated[list[BaseMessage], add_messages]
+
+
+# ============================================================================
+# NODE FUNCTIONS
+# ============================================================================
+
+
+def agent_node(state: AgentState):
+ """
+ The agent node that decides which tools to call.
+ """
+ messages = state["messages"]
+
+ # Initialize the LLM with tool calling capabilities
+ llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
+ llm_with_tools = llm.bind_tools(tools)
+
+ # Get the agent's response
+ response = llm_with_tools.invoke(messages)
+
+ print(f"Agent response: {response}")
+
+ # Return just the new message - add_messages reducer will append it
+ return {"messages": [response]}
+
+
+def should_continue(state: AgentState):
+ """
+ Determines whether to continue with tool calls or end.
+ """
+ messages = state["messages"]
+ last_message = messages[-1]
+
+ # If there are tool calls, continue to the tools node
+ if hasattr(last_message, "tool_calls") and last_message.tool_calls:
+ return "tools"
+
+ # Otherwise, end the workflow
+ return "end"
+
+
+# ============================================================================
+# AGENT FACTORY
+# ============================================================================
+
+
+def create_agent():
+ """
+ Creates an agent that uses tools to process requests.
+ This demonstrates the tool-calling pattern in LangGraph.
+ """
+ workflow = StateGraph(AgentState)
+
+ # Add nodes
+ workflow.add_node("agent", agent_node)
+ workflow.add_node("tools", ToolNode(tools))
+
+ # Set entry point
+ workflow.set_entry_point("agent")
+
+ # Add conditional edges
+ workflow.add_conditional_edges(
+ "agent",
+ should_continue,
+ {
+ "tools": "tools",
+ "end": END,
+ },
+ )
+
+ # After tools are called, go back to the agent
+ workflow.add_edge("tools", "agent")
+
+ # Compile the workflow
+ app = workflow.compile()
+
+ return app
diff --git a/examples/agent/langgraph-traceloop/main.py b/examples/agent/langgraph-traceloop/main.py
new file mode 100644
index 00000000..81b6ef44
--- /dev/null
+++ b/examples/agent/langgraph-traceloop/main.py
@@ -0,0 +1,61 @@
+import dotenv
+from agent import create_agent
+from traceloop.sdk import Traceloop
+from langchain_core.messages import HumanMessage
+
+dotenv.load_dotenv()
+
+Traceloop.init(
+ app_name="LangGraph-Traceloop-Demo",
+ disable_batch=False, # Enable batching for better performance
+ resource_attributes={
+ "service.version": "1.0.0",
+ "deployment.environment": "development",
+ },
+)
+
+
+if __name__ == "__main__":
+ print("\n" + "=" * 60)
+ print("RUNNING TOOL-BASED AGENT")
+ print("=" * 60)
+
+ # Create the agent
+ app = create_agent()
+
+ # Prepare the input with instructions for the agent
+ user_question = "what moons did galileo discover"
+
+ # Create a message that instructs the agent to use the tools
+ instructions = f"""Please help me answer this question: "{user_question}"
+
+To do this, follow these steps:
+1. First, use the validate_input_tool to validate the question
+2. Then, use the generate_response_tool to get an answer
+3. Finally, use the format_answer_tool to format the response nicely
+
+After completing all steps, provide the final formatted answer."""
+
+ inputs = {"messages": [HumanMessage(content=instructions)]}
+
+ # Run the agent
+ result = app.invoke(inputs)
+
+ print("\n=== FINAL RESULT ===")
+ print(f"Total messages exchanged: {len(result.get('messages', []))}")
+
+ # Extract and display the conversation
+ messages = result.get("messages", [])
+ for i, msg in enumerate(messages):
+ msg_type = type(msg).__name__
+ print(f"\n--- Message {i+1} ({msg_type}) ---")
+
+ if hasattr(msg, "content") and msg.content:
+ print(f"Content: {msg.content[:200]}...")
+
+ if hasattr(msg, "tool_calls") and msg.tool_calls:
+ print(f"Tool Calls: {len(msg.tool_calls)}")
+ for tc in msg.tool_calls:
+ print(f" - {tc.get('name', 'unknown')}: {tc.get('args', {})}")
+
+ print("\nExecution complete - check Splunk AO for traces in your project/log stream")
diff --git a/examples/agent/langgraph-traceloop/pyproject.toml b/examples/agent/langgraph-traceloop/pyproject.toml
new file mode 100644
index 00000000..3bebbcd4
--- /dev/null
+++ b/examples/agent/langgraph-traceloop/pyproject.toml
@@ -0,0 +1,21 @@
+[project]
+name = "langgraph-traceloop"
+version = "0.1.0"
+description = "LangGraph + Traceloop (OpenLLMetry) + Splunk AO Integration"
+readme = "README.md"
+requires-python = ">=3.12"
+dependencies = [
+ "langgraph>=0.6.0",
+ "langgraph-prebuilt>=0.6.0",
+ "langchain-core>=0.3.0",
+ "langchain-openai>=0.2.0",
+ "openai",
+ "python-dotenv>=1.1.0",
+ "traceloop-sdk>=0.30.0",
+]
+
+[dependency-groups]
+dev = [
+ "black>=25.1.0",
+]
+
diff --git a/examples/agent/langgraph-traceloop/trace.png b/examples/agent/langgraph-traceloop/trace.png
new file mode 100644
index 00000000..837c5cf1
Binary files /dev/null and b/examples/agent/langgraph-traceloop/trace.png differ
diff --git a/examples/agent/microsoft-agent-framework/.env.example b/examples/agent/microsoft-agent-framework/.env.example
new file mode 100644
index 00000000..20034a86
--- /dev/null
+++ b/examples/agent/microsoft-agent-framework/.env.example
@@ -0,0 +1,8 @@
+# OpenAI environment variables
+OPENAI_API_KEY=
+
+# Galileo environment variables
+# GALILEO_API_ENDPOINT= # Optional, only set this if you are using a custom Galileo deployment
+GALILEO_API_KEY=
+GALILEO_PROJECT=
+GALILEO_LOG_STREAM=
diff --git a/examples/agent/microsoft-agent-framework/README.md b/examples/agent/microsoft-agent-framework/README.md
new file mode 100644
index 00000000..e1867206
--- /dev/null
+++ b/examples/agent/microsoft-agent-framework/README.md
@@ -0,0 +1,50 @@
+# Microsoft Agent Framework + Splunk AO Example
+
+This is an example project demonstrating how to use Splunk AO with the [Microsoft Agent Framework](https://github.com/microsoft/agent-framework). The Microsoft Agent Framework has built-in OpenTelemetry instrumentation, so traces are captured automatically using the `SplunkAOSpanProcessor` from the Splunk AO SDK.
+
+## Getting Started
+
+To get started with this project, you'll need to have Python 3.12 or later installed. You can then install the required dependencies in a virtual environment:
+
+```bash
+pip install -r requirements.txt
+```
+
+## Configure environment variables
+
+You will need to configure environment variables to use this project. Copy the `.env.example` file to `.env`, then update the environment variables in the `.env` file with your OpenAI and Splunk AO values:
+
+```ini
+# OpenAI environment variables
+OPENAI_API_KEY=
+
+# Splunk AO environment variables
+# SPLUNK_AO_API_ENDPOINT= # Optional, only set this if you are using a custom Splunk AO deployment
+SPLUNK_AO_API_KEY=
+SPLUNK_AO_PROJECT=
+SPLUNK_AO_LOG_STREAM=
+```
+
+For the `SPLUNK_AO_API_ENDPOINT`, you only need to set this if you are using a custom Splunk AO deployment. There is no need to set this if you are using [app.galileo.ai](https://app.galileo.ai). This endpoint is different to the console URL that you would normally use. See the [Splunk AO OpenTelemetry documentation](https://docs.galileo.ai/sdk-api/third-party-integrations/opentelemetry-and-openinference#self-hosted-deployments) for more details.
+
+## Usage
+
+Once the dependencies are installed, you can run the example application:
+
+```bash
+python agent.py
+```
+
+Traces will be captured and logged to Splunk AO.
+
+## Project Structure
+
+The project structure is as follows:
+
+```folder
+microsoft-agent-framework/
+├── .env.example # List of environment variables
+├── agent.py # The main agent application
+├── requirements.txt # Python project requirements
+└── README.md # Project documentation
+```
diff --git a/examples/agent/microsoft-agent-framework/agent.py b/examples/agent/microsoft-agent-framework/agent.py
new file mode 100644
index 00000000..196c1b33
--- /dev/null
+++ b/examples/agent/microsoft-agent-framework/agent.py
@@ -0,0 +1,54 @@
+from random import randint
+from typing import Annotated
+
+from agent_framework import openai, tool
+from agent_framework.observability import enable_instrumentation
+from splunk_ao.otel import SplunkAOSpanProcessor, add_splunk_ao_span_processor
+from opentelemetry import trace
+from opentelemetry.sdk.trace import TracerProvider
+from pydantic import Field
+
+# Set up the OTel tracer provider with the Splunk AO span processor
+tracer_provider = TracerProvider()
+galileo_processor = SplunkAOSpanProcessor()
+add_splunk_ao_span_processor(tracer_provider, galileo_processor)
+trace.set_tracer_provider(tracer_provider)
+
+# Enable the Microsoft Agent Framework's built-in OTel instrumentation.
+# Set enable_sensitive_data=True to send LLM inputs and outputs to Splunk AO.
+# If set to False, only span metadata (timing, token counts, etc.) will be sent.
+enable_instrumentation(enable_sensitive_data=True)
+
+
+# The following code is the basic tool call example from the
+# Microsoft Agent Framework documentation
+# https://github.com/microsoft/agent-framework
+
+
+@tool(approval_mode="never_require")
+def get_weather(
+ location: Annotated[str, Field(description="The location to get the weather for.")],
+) -> str:
+ """Get the weather for a given location."""
+ conditions = ["sunny", "cloudy", "rainy", "stormy"]
+ return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}C."
+
+
+client = openai.OpenAIChatClient(model_id="gpt-4.1-mini")
+
+agent = client.as_agent(
+ name="WeatherAgent",
+ instructions="You are a helpful weather agent. Use the get_weather tool to answer questions.",
+ tools=[get_weather],
+)
+
+
+async def main():
+ result = await agent.run("What's the weather like in Seattle?")
+ print(result)
+
+
+if __name__ == "__main__":
+ import asyncio
+
+ asyncio.run(main())
diff --git a/examples/agent/microsoft-agent-framework/requirements.txt b/examples/agent/microsoft-agent-framework/requirements.txt
new file mode 100644
index 00000000..0b913a1d
--- /dev/null
+++ b/examples/agent/microsoft-agent-framework/requirements.txt
@@ -0,0 +1,3 @@
+agent-framework>=1.0.0b251120
+galileo[otel]>=1.46.2
+pydantic
diff --git a/examples/agent/minimal-agent-example/.env.example b/examples/agent/minimal-agent-example/.env.example
new file mode 100644
index 00000000..17495eb3
--- /dev/null
+++ b/examples/agent/minimal-agent-example/.env.example
@@ -0,0 +1,10 @@
+# Galileo Environment Variables
+GALILEO_API_KEY=your-galileo-api-key # Your Galileo API key.
+GALILEO_PROJECT=your-galileo-project-name # Your Galileo project name.
+GALILEO_LOG_STREAM=your-galileo-log-stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# GALILEO_CONSOLE_URL=your-galileo-console-url # Optional if you are using a hosted version of Galileo
+
+OPENAI_API_KEY=your-openai-key
+OPENAI_ORGANIZATION=your-openai-organization
diff --git a/examples/agent/minimal-agent-example/app.py b/examples/agent/minimal-agent-example/app.py
new file mode 100644
index 00000000..7fe10462
--- /dev/null
+++ b/examples/agent/minimal-agent-example/app.py
@@ -0,0 +1,332 @@
+import os
+import streamlit as st
+from splunk_ao import (
+ log,
+ splunk_ao_context,
+ openai,
+)
+from pydantic import BaseModel
+import json
+from typing import Callable
+from dotenv import load_dotenv
+
+load_dotenv()
+
+client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
+
+
+class DestinationOverviewRequest(BaseModel):
+ destination: str
+
+
+class ItineraryRequest(BaseModel):
+ destination: str
+ days: int
+
+
+class WeatherRequest(BaseModel):
+ destination: str
+
+
+class BudgetRequest(BaseModel):
+ destination: str
+ days: int
+
+
+tools = [
+ {
+ "type": "function",
+ "function": {
+ "name": "get_weather_forecast",
+ "description": "Get the weather forecast for a given location.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "destination": {
+ "type": "string",
+ "description": "City and country e.g. Bogotá, Colombia",
+ },
+ },
+ "required": [
+ "destination",
+ ],
+ "additionalProperties": False,
+ },
+ "strict": True,
+ },
+ },
+ {
+ "type": "function",
+ "function": {
+ "name": "estimate_travel_budget",
+ "description": "Estimate the travel budget for a given location.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "destination": {
+ "type": "string",
+ "description": "City and country e.g. Bogotá, Colombia",
+ },
+ "days": {
+ "type": "integer",
+ "description": "Number of days for the itinerary",
+ },
+ },
+ "required": ["destination", "days"],
+ "additionalProperties": False,
+ },
+ "strict": True,
+ },
+ },
+ {
+ "type": "function",
+ "function": {
+ "name": "generate_destination_overview",
+ "description": "Generate a destination overview.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "destination": {
+ "type": "string",
+ "description": "City and country e.g. Bogotá, Colombia",
+ },
+ },
+ "required": [
+ "destination",
+ ],
+ "additionalProperties": False,
+ },
+ "strict": True,
+ },
+ },
+ {
+ "type": "function",
+ "function": {
+ "name": "generate_itinerary",
+ "description": "Generate a travel itinerary for a destination.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "destination": {
+ "type": "string",
+ "description": "City and country e.g. Bogotá, Colombia",
+ },
+ "days": {
+ "type": "integer",
+ "description": "Number of days for the itinerary",
+ },
+ },
+ "required": ["destination", "days"],
+ "additionalProperties": False,
+ },
+ "strict": True,
+ },
+ },
+]
+
+
+# =============================================================================
+# Local function to simulate an API call for weather data.
+# =============================================================================
+@log(span_type="tool")
+def get_weather_forecast(destination: str) -> str:
+ # Simulate a local function call that returns dummy weather data.
+ return f"Weather forecast for {destination}: Mostly sunny with a slight chance of rain."
+
+
+# =============================================================================
+# LLM call: Generate a destination overview.
+# =============================================================================
+def generate_destination_overview(destination: str) -> str:
+ prompt = f"Provide a brief overview of {destination}, including its top attractions, " "cultural highlights, and essential travel tips."
+ # Call the OpenAI API (assuming proper API key configuration)
+ response = client.chat.completions.create(
+ model="gpt-4o-mini",
+ messages=[{"role": "user", "content": prompt}],
+ )
+ # Extract and return the text from the response.
+ return response.choices[0].message.content.strip()
+
+
+# =============================================================================
+# LLM call: Generate a day-by-day travel itinerary.
+# =============================================================================
+def generate_itinerary(destination: str, days: int) -> str:
+ prompt = f"""
+Plan a {days}-day travel itinerary for a trip to {destination}.
+Include daily sightseeing activities, dining suggestions, and local experiences.
+
+Important:
+- Every plan must contain a destination overview and an itinerary.
+- Only include a travel budget and weather info if the user requests it.
+"""
+ response = client.chat.completions.create(
+ model="gpt-4o-mini",
+ messages=[{"role": "user", "content": prompt}],
+ )
+ return response.choices[0].message.content.strip()
+
+
+# =============================================================================
+# LLM call: Estimate a travel budget.
+# =============================================================================
+def estimate_travel_budget(destination: str, days: int, itinerary: str | None = None) -> str:
+ itinerary_prompt = f"\n\nHere is the itinerary:\n\n {itinerary}" if itinerary else ""
+ prompt = (
+ f"Estimate a travel budget for a {days}-day trip to {destination} that covers accommodation, "
+ "food, transportation, and activities. Provide a rough breakdown of the costs (in USD)."
+ f"{itinerary_prompt}"
+ )
+ response = client.chat.completions.create(
+ model="gpt-4o-mini",
+ messages=[{"role": "user", "content": prompt}],
+ )
+ return response.choices[0].message.content.strip()
+
+
+# =============================================================================
+# LLM call: Decide which functions to call and assemble the itinerary.
+# =============================================================================
+@log
+def assemble_travel_plan(query: str, info_callback: Callable[[str], None]) -> str:
+ #
+ # Develop a plan
+ #
+
+ function_calling_prompt = f"""
+You are an expert travel planner. I've included a request that you need to process:
+
+\"{query}\"
+
+Important:
+- Every plan MUST contain a destination overview and an itinerary. Make sure to always call the `generate_destination_overview` and `generate_itinerary` functions.
+- Only include a travel budget (using the `estimate_travel_budget` function) and weather info (using the `get_weather_forecast` function) if the user requests it.
+"""
+
+ response = client.chat.completions.create(
+ model="gpt-4-turbo",
+ messages=[{"role": "user", "content": function_calling_prompt}],
+ tools=tools,
+ )
+
+ # Extract function call responses
+ message_response = response.choices[0].message
+
+ if message_response.function_call:
+ function_calls = [message_response.function_call] # Single function case
+ else:
+ function_calls = message_response.tool_calls or [] # Multiple function calls
+
+ destination_overview = ""
+ itinerary = ""
+ budget = ""
+ weather = ""
+
+ #
+ # Process multiple function calls
+ #
+ for function_call in function_calls:
+ function_name = function_call.function.name
+ function_args = json.loads(function_call.function.arguments)
+
+ if function_name == "generate_destination_overview":
+ destination_overview_request = DestinationOverviewRequest(**function_args)
+ info_callback(f"Generating a destination overview for {destination_overview_request.destination}...")
+ destination_overview = destination_overview + "\n" + generate_destination_overview(destination_overview_request.destination)
+
+ elif function_name == "generate_itinerary":
+ itinerary_request = ItineraryRequest(**function_args)
+ info_callback(f"Generating an itinerary for {itinerary_request.destination}...")
+ itinerary = itinerary + "\n" + generate_itinerary(itinerary_request.destination, itinerary_request.days)
+
+ elif function_name == "estimate_travel_budget":
+ budget_request = BudgetRequest(**function_args)
+ info_callback(f"Generating a travel budget for {budget_request.destination}...")
+ budget = (
+ budget
+ + "\n"
+ + estimate_travel_budget(
+ destination=budget_request.destination,
+ days=budget_request.days,
+ itinerary=itinerary,
+ )
+ )
+
+ elif function_name == "get_weather_forecast":
+ weather_request = WeatherRequest(**function_args)
+ info_callback(f"Generating a weather forecast for {weather_request.destination}...")
+ weather = weather + "\n" + get_weather_forecast(weather_request.destination)
+
+ #
+ # Assemble the results
+ #
+ info_callback("Assembling the final plan...")
+ travel_budget = f"Travel budget: {budget}" if budget else ""
+ weather_forecast = f"Weather forecast: {weather}" if weather else ""
+ assembly_prompt = (
+ f"""
+You are an expert travel planner.
+
+My original request was: \"{query}\"
+
+You have generated the following outputs:
+
+Destination overview: {destination_overview}
+Itinerary: {itinerary}
+"""
+ + travel_budget
+ + weather_forecast
+ + "\n\nPlease package the information above into a plan that I can use for my next trip."
+ )
+
+ response = client.chat.completions.create(
+ model="gpt-4o",
+ messages=[{"role": "user", "content": assembly_prompt}],
+ )
+ return response.choices[0].message.content.strip()
+
+
+# =============================================================================
+# Main Streamlit App
+# =============================================================================
+def main():
+ st.title("Travel Itinerary Planner")
+ st.write("Plan your next adventure with our AI-powered travel planner.")
+
+ with st.container():
+ # User inputs for the travel query.
+ query = st.text_input(
+ "Where would you like to go?",
+ "Rome for 5 days later this month, please include a trip budget and weather info",
+ )
+
+ # Create a button for planning the trip.
+ plan_trip_clicked = st.button("Plan My Trip")
+
+ info_placeholder = st.empty()
+
+ # Create an empty container for results so that previous outputs are cleared on re-run.
+ result_container = st.empty()
+
+ def info_callback(message):
+ info_placeholder.info(message)
+
+ if plan_trip_clicked:
+ if not query.strip():
+ info_placeholder.warning("Please enter a travel query.")
+ else:
+ result_container.empty()
+ info_placeholder.info("Generating your travel plan. Please wait...")
+
+ with splunk_ao_context():
+ plan = assemble_travel_plan(query, info_callback)
+
+ # Clear the info message once the generation is complete.
+ info_placeholder.empty()
+
+ with result_container.container():
+ st.write(plan)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/agent/minimal-agent-example/minimal_agent.py b/examples/agent/minimal-agent-example/minimal_agent.py
new file mode 100644
index 00000000..5a824dfa
--- /dev/null
+++ b/examples/agent/minimal-agent-example/minimal_agent.py
@@ -0,0 +1,178 @@
+import os
+import json
+import warnings
+from splunk_ao import log, splunk_ao_context, openai as splunk_ao_openai
+from dotenv import load_dotenv
+from rich.console import Console
+import questionary
+import openai
+
+# Suppress Pydantic serializer warnings
+warnings.filterwarnings("ignore", message="Pydantic serializer warnings")
+
+load_dotenv()
+console = Console()
+client = splunk_ao_openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
+openai_client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
+
+
+# Tool: Convert text numbers to numerical values
+@log(span_type="tool", name="convert_text_to_arithmetic_expression")
+def convert_text_to_arithmetic_expression(text):
+ """Convert a text number (like 'seven') to its numerical value (7)."""
+ console.print(f"Converting: {text}")
+
+ response = openai_client.chat.completions.create(
+ model="gpt-4o",
+ messages=[
+ {
+ "role": "user",
+ "content": f"Convert the expression {text} with text numbers to a valid arithmetic expression. Respond with only the arithmetic expression.",
+ }
+ ],
+ )
+
+ result = response.choices[0].message.content.strip()
+ try:
+ expression = result
+ console.print(f"Converted to: {expression}")
+ return str(expression)
+ except:
+ console.print(f"Error parsing: {result}")
+ return "Error"
+
+
+# Tool: Calculator for arithmetic operations
+@log(span_type="tool", name="calculate")
+def calculate(expression):
+ """Perform a calculation based on the given expression."""
+ console.print(f"Calculating: {expression}")
+
+ try:
+ result = eval(expression)
+ console.print(f"Result: {result}")
+ return f"The result of {expression} is {result}"
+ except Exception as e:
+ return f"Error calculating {expression}: {str(e)}"
+
+
+# Load tools from tools.json
+def get_tools():
+ with open(os.path.join(os.path.dirname(__file__), "tools.json"), "r") as f:
+ return json.load(f)
+
+
+# Main processing function
+@log(span_type="llm")
+def process_query(query):
+ """Process a numerical query using LLM and tools."""
+ console.print(f"Processing query: {query}")
+
+ # Initialize conversation history with serializable dictionaries
+ messages = [
+ {
+ "role": "system",
+ "content": "Convert text expressions to valid arithmetic expressions, then calculate results. Use tools one at a time.",
+ },
+ {"role": "user", "content": f"Process this query: '{query}'"},
+ ]
+
+ tools = get_tools()
+ results = []
+
+ # Agent loop - continue until the LLM decides we're done
+ while True:
+ # Get next tool call from LLM
+ response = client.chat.completions.create(
+ model="gpt-4o",
+ messages=messages,
+ tools=tools,
+ )
+
+ # Convert the assistant message to a serializable dictionary
+ assistant_message = response.choices[0].message
+ assistant_dict = {"role": "assistant", "content": assistant_message.content}
+
+ # Add tool calls if present
+ if assistant_message.tool_calls:
+ tool_calls_list = []
+ for tool_call in assistant_message.tool_calls:
+ tool_calls_list.append(
+ {
+ "id": tool_call.id,
+ "type": "function",
+ "function": {
+ "name": tool_call.function.name,
+ "arguments": tool_call.function.arguments,
+ },
+ }
+ )
+ assistant_dict["tool_calls"] = tool_calls_list
+
+ messages.append(assistant_dict) # Add assistant's response to history
+
+ # Check if LLM is done (no more tool calls)
+ if not assistant_message.tool_calls:
+ # LLM provided a final answer
+ if assistant_message.content:
+ results.append(assistant_message.content)
+ break
+
+ # Process the tool call
+ for tool_call in assistant_message.tool_calls:
+ function_name = tool_call.function.name
+ function_args = json.loads(tool_call.function.arguments)
+
+ console.print(f"\n[bold]Executing {function_name} tool:[/bold]")
+
+ # Execute the appropriate tool
+ if function_name == "convert_text_to_arithmetic_expression":
+ text = function_args["text"]
+ result = convert_text_to_arithmetic_expression(text)
+ elif function_name == "calculate":
+ expression = function_args["expression"]
+ result = calculate(expression)
+ else:
+ result = f"Unknown tool: {function_name}"
+
+ # Add the tool result to conversation history as a serializable dictionary
+ tool_result_message = {
+ "tool_call_id": tool_call.id,
+ "role": "tool",
+ "name": function_name,
+ "content": result,
+ }
+ messages.append(tool_result_message)
+ results.append(result)
+
+ # Create a summary
+ if results:
+ summary = "\n".join(results)
+ else:
+ summary = "No results produced."
+
+ return summary
+
+
+def main():
+ console.print("[bold]Minimal Number Converter & Calculator[/bold]")
+
+ query = questionary.text("Enter your query:", default="What's 4 + seven?").ask()
+
+ if query is None or query.lower() in ["exit", "quit", "q"]:
+ console.print("Exiting.")
+ return
+
+ # Process the query within a Splunk AO context
+ with splunk_ao_context():
+ result = process_query(query)
+
+ console.print("\n[bold green]Result:[/bold green]")
+ console.print(result)
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ console.print("\nExiting.")
diff --git a/examples/agent/minimal-agent-example/requirements.txt b/examples/agent/minimal-agent-example/requirements.txt
new file mode 100644
index 00000000..a230cd74
--- /dev/null
+++ b/examples/agent/minimal-agent-example/requirements.txt
@@ -0,0 +1,20 @@
+galileo==0.0.7
+rich>=13.7.0
+questionary>=2.0.1
+openai==1.61.1
+pydantic==2.10.6
+aiohappyeyeballs==2.4.6
+aiohttp==3.11.12
+aiosignal==1.3.2
+attrs==25.1.0
+certifi==2025.1.31
+frozenlist==1.5.0
+idna==3.10
+multidict==6.1.0
+propcache==0.2.1
+python-dateutil==2.9.0.post0
+six==1.17.0
+typing_extensions==4.12.2
+urllib3==2.3.0
+yarl==1.18.3
+python-dotenv>=1.0.0
diff --git a/examples/agent/minimal-agent-example/tools.json b/examples/agent/minimal-agent-example/tools.json
new file mode 100644
index 00000000..38992c0b
--- /dev/null
+++ b/examples/agent/minimal-agent-example/tools.json
@@ -0,0 +1,40 @@
+[
+ {
+ "type": "function",
+ "function": {
+ "name": "convert_text_to_arithmetic_expression",
+ "description": "Convert numbers written as words to their numerical values.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "text": {
+ "type": "string",
+ "description": "A text expression which can contain numbers written as words (e.g., 'twenty-five', 'one hundred and two'), numbers written as digits (e.g., '5', '100'), and arithmetic operators (e.g., '+', '-', '*', '/')"
+ }
+ },
+ "required": ["text"],
+ "additionalProperties": false
+ },
+ "strict": true
+ }
+ },
+ {
+ "type": "function",
+ "function": {
+ "name": "calculate",
+ "description": "Perform arithmetic calculations on numbers.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "expression": {
+ "type": "string",
+ "description": "Arithmetic expression to calculate (e.g., '5 + 3', '10 * 4', '100 / 25')"
+ }
+ },
+ "required": ["expression"],
+ "additionalProperties": false
+ },
+ "strict": true
+ }
+ }
+]
\ No newline at end of file
diff --git a/examples/agent/pydantic-ai-support-agent/.env.example b/examples/agent/pydantic-ai-support-agent/.env.example
new file mode 100644
index 00000000..e1b4cccb
--- /dev/null
+++ b/examples/agent/pydantic-ai-support-agent/.env.example
@@ -0,0 +1,9 @@
+# Galileo Environment Variables
+GALILEO_API_KEY=your-galileo-api-key # Your Galileo API key.
+GALILEO_PROJECT=your-galileo-project-name # Your Galileo project name.
+GALILEO_LOG_STREAM=your-galileo-log-stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# GALILEO_CONSOLE_URL=your-galileo-console-url # Optional if you are using a hosted version of Galileo
+
+OPENAI_API_KEY=your-openai-key # Your OpenAI API key.
diff --git a/examples/agent/pydantic-ai-support-agent/README.md b/examples/agent/pydantic-ai-support-agent/README.md
new file mode 100644
index 00000000..02290390
--- /dev/null
+++ b/examples/agent/pydantic-ai-support-agent/README.md
@@ -0,0 +1,34 @@
+# PydanticAI Example Project
+
+This is an example project demonstrating how to use Splunk AO with PydanticAI. It showcases an enterprise customer support agent with tools for looking up customer data, checking order status, creating support tickets, and processing refunds.
+
+The example uses the Splunk AO SDK's built-in OpenTelemetry support combined with PydanticAI's native instrumentation to send traces to Splunk AO for observability.
+
+## Getting Started
+
+To get started with this project, you'll need to have Python 3.11 or later installed. You can then install the required dependencies using uv:
+
+```bash
+uv sync
+```
+
+## Usage
+
+Once the dependencies are installed, you can run the example application:
+
+```bash
+uv run src/main.py
+```
+
+## Project Structure
+
+The project structure is as follows:
+
+```
+pydantic-ai-support-agent/
+├── src/ # Main application files
+│ └── main.py
+├── pyproject.toml # Project configuration file
+├── README.md # Project documentation
+└── .env.example # List of environment variables
+```
diff --git a/examples/agent/pydantic-ai-support-agent/pyproject.toml b/examples/agent/pydantic-ai-support-agent/pyproject.toml
new file mode 100644
index 00000000..1d00c806
--- /dev/null
+++ b/examples/agent/pydantic-ai-support-agent/pyproject.toml
@@ -0,0 +1,10 @@
+[project]
+name = "pydantic-ai-support-agent"
+version = "0.1.0"
+description = "An example project for using Splunk AO with PydanticAI."
+readme = "README.md"
+requires-python = ">=3.11, <3.14"
+dependencies = [
+ "galileo[otel]>=1.40.0",
+ "pydantic-ai>=1.0.0",
+]
diff --git a/examples/agent/pydantic-ai-support-agent/src/main.py b/examples/agent/pydantic-ai-support-agent/src/main.py
new file mode 100644
index 00000000..16da77bc
--- /dev/null
+++ b/examples/agent/pydantic-ai-support-agent/src/main.py
@@ -0,0 +1,230 @@
+"""Enterprise customer support agent with Splunk AO observability."""
+
+from dataclasses import dataclass
+from datetime import datetime
+from typing import Optional
+
+from splunk_ao.otel import SplunkAOSpanProcessor, add_splunk_ao_span_processor
+from opentelemetry import trace
+from opentelemetry.sdk.trace import TracerProvider
+from pydantic import BaseModel
+from pydantic_ai import Agent, RunContext
+
+# Set up Splunk AO observability
+provider = TracerProvider()
+trace.set_tracer_provider(provider)
+add_splunk_ao_span_processor(
+ tracer_provider=provider,
+ processor=SplunkAOSpanProcessor(project="pydantic-ai-support", logstream="default"),
+)
+
+# Enable instrumentation on all PydanticAI agents
+Agent.instrument_all()
+
+
+# --- Mock Database Models ---
+@dataclass
+class Customer:
+ id: str
+ name: str
+ email: str
+ tier: str # "standard", "premium", "enterprise"
+ account_created: datetime
+
+
+@dataclass
+class Order:
+ id: str
+ customer_id: str
+ product: str
+ amount: float
+ status: str # "pending", "shipped", "delivered", "cancelled"
+ created_at: datetime
+
+
+@dataclass
+class SupportTicket:
+ id: str
+ customer_id: str
+ subject: str
+ priority: str
+ status: str
+
+
+# --- Mock Database ---
+CUSTOMERS_DB: dict[str, Customer] = {
+ "C001": Customer(
+ "C001",
+ "Alice Johnson",
+ "alice@example.com",
+ "enterprise",
+ datetime(2022, 1, 15),
+ ),
+ "C002": Customer("C002", "Bob Smith", "bob@example.com", "premium", datetime(2023, 6, 20)),
+ "C003": Customer("C003", "Carol White", "carol@example.com", "standard", datetime(2024, 3, 10)),
+}
+
+ORDERS_DB: dict[str, Order] = {
+ "ORD-1001": Order(
+ "ORD-1001",
+ "C001",
+ "Enterprise License",
+ 5000.00,
+ "delivered",
+ datetime(2024, 11, 1),
+ ),
+ "ORD-1002": Order(
+ "ORD-1002",
+ "C001",
+ "Support Package",
+ 1200.00,
+ "shipped",
+ datetime(2024, 12, 15),
+ ),
+ "ORD-1003": Order(
+ "ORD-1003",
+ "C002",
+ "Premium Subscription",
+ 299.99,
+ "pending",
+ datetime(2025, 1, 5),
+ ),
+}
+
+TICKETS_DB: dict[str, SupportTicket] = {}
+TICKET_COUNTER = 1000
+
+
+# --- Agent Dependencies ---
+@dataclass
+class SupportDeps:
+ customer_id: str
+
+
+# --- Response Model ---
+class SupportResponse(BaseModel):
+ message: str
+ ticket_id: Optional[str] = None
+ refund_processed: bool = False
+
+
+# --- Support Agent ---
+support_agent = Agent(
+ "openai:gpt-4o",
+ deps_type=SupportDeps,
+ output_type=SupportResponse,
+ system_prompt=(
+ "You are an enterprise customer support agent. "
+ "Help customers with their inquiries by looking up their information, "
+ "checking order status, creating support tickets, and processing refunds when appropriate. "
+ "Always be professional and helpful. For enterprise customers, prioritize their requests."
+ ),
+)
+
+
+@support_agent.tool
+async def get_customer_info(ctx: RunContext[SupportDeps]) -> str:
+ """Retrieve customer information including their tier and account details."""
+ customer = CUSTOMERS_DB.get(ctx.deps.customer_id)
+ if not customer:
+ return "Customer not found."
+ return (
+ f"Customer: {customer.name}\n" f"Email: {customer.email}\n" f"Tier: {customer.tier}\n" f"Account since: {customer.account_created.strftime('%Y-%m-%d')}"
+ )
+
+
+@support_agent.tool
+async def get_order_status(ctx: RunContext[SupportDeps], order_id: str) -> str:
+ """Check the status of a specific order.
+
+ Args:
+ order_id: The order ID to look up (e.g., ORD-1001).
+ """
+ order = ORDERS_DB.get(order_id)
+ if not order:
+ return f"Order {order_id} not found."
+ if order.customer_id != ctx.deps.customer_id:
+ return "You don't have access to this order."
+ return (
+ f"Order ID: {order.id}\n"
+ f"Product: {order.product}\n"
+ f"Amount: ${order.amount:.2f}\n"
+ f"Status: {order.status}\n"
+ f"Order date: {order.created_at.strftime('%Y-%m-%d')}"
+ )
+
+
+@support_agent.tool
+async def list_customer_orders(ctx: RunContext[SupportDeps]) -> str:
+ """List all orders for the current customer."""
+ customer_orders = [o for o in ORDERS_DB.values() if o.customer_id == ctx.deps.customer_id]
+ if not customer_orders:
+ return "No orders found for this customer."
+ lines = ["Your orders:"]
+ for order in customer_orders:
+ lines.append(f" - {order.id}: {order.product} (${order.amount:.2f}) - {order.status}")
+ return "\n".join(lines)
+
+
+@support_agent.tool
+async def create_support_ticket(ctx: RunContext[SupportDeps], subject: str, priority: str = "medium") -> str:
+ """Create a new support ticket for the customer.
+
+ Args:
+ subject: Brief description of the issue.
+ priority: Ticket priority - 'low', 'medium', 'high', or 'urgent'.
+ """
+ global TICKET_COUNTER
+ customer = CUSTOMERS_DB.get(ctx.deps.customer_id)
+
+ # Enterprise customers get priority boost
+ if customer and customer.tier == "enterprise" and priority == "medium":
+ priority = "high"
+
+ TICKET_COUNTER += 1
+ ticket_id = f"TKT-{TICKET_COUNTER}"
+ ticket = SupportTicket(
+ id=ticket_id,
+ customer_id=ctx.deps.customer_id,
+ subject=subject,
+ priority=priority,
+ status="open",
+ )
+ TICKETS_DB[ticket_id] = ticket
+ return f"Support ticket created: {ticket_id} (Priority: {priority})"
+
+
+@support_agent.tool
+async def process_refund(ctx: RunContext[SupportDeps], order_id: str, reason: str) -> str:
+ """Process a refund for an order. Only available for delivered or shipped orders.
+
+ Args:
+ order_id: The order ID to refund.
+ reason: Reason for the refund request.
+ """
+ order = ORDERS_DB.get(order_id)
+ if not order:
+ return f"Order {order_id} not found."
+ if order.customer_id != ctx.deps.customer_id:
+ return "You don't have access to this order."
+ if order.status not in ("delivered", "shipped"):
+ return f"Cannot process refund for order with status: {order.status}"
+
+ # Update order status
+ order.status = "refunded"
+ return f"Refund of ${order.amount:.2f} processed for order {order_id}. Reason: {reason}"
+
+
+if __name__ == "__main__":
+ # Simulate a customer support interaction
+ deps = SupportDeps(customer_id="C001")
+
+ # Invoke the support agent with a sample customer query
+ result = support_agent.run_sync(
+ "Hi, I need help with my recent order ORD-1002. It shows as shipped but I haven't "
+ "received it yet. Can you check the status and create a support ticket for this issue?",
+ deps=deps,
+ )
+ print(f"Response: {result.output.message}")
+ if result.output.ticket_id:
+ print(f"Ticket ID: {result.output.ticket_id}")
diff --git a/examples/agent/startup-simulator-3000/.example.env b/examples/agent/startup-simulator-3000/.example.env
new file mode 100644
index 00000000..5a9e560d
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/.example.env
@@ -0,0 +1,31 @@
+# Example .env file — copy this file to .env and fill in the values.
+# Be sure to add the .env file to your .gitignore file.
+
+# **Required API Keys:**
+# - **OpenAI API Key**: Get one at [https://platform.openai.com/api-keys](https://platform.openai.com/api-keys)
+# - **NewsAPI Key**: Get one at [https://newsapi.org/register](https://newsapi.org/register) (for serious mode)
+# - **Galileo API Key**: Get one at [https://console.galileo.ai/](https://console.galileo.ai/) (for observability)
+
+# Galileo Environment Variables
+GALILEO_API_KEY=your-galileo-api-key # Your Galileo API key.
+GALILEO_PROJECT=your-galileo-project-name # Your Galileo project name.
+GALILEO_LOG_STREAM=your-galileo-log-stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# GALILEO_CONSOLE_URL=your-galileo-console-url # Optional if you are using a hosted version of Galileo
+
+# Required API Keys
+OPENAI_API_KEY=sk-your-openai-key-here
+NEWS_API_KEY=your-newsapi-key-here
+
+
+# Optional LLM configuration
+LLM_MODEL=gpt-4
+LLM_TEMPERATURE=0.7
+
+# Optional agent configuration
+VERBOSITY=low # Options: none, low, high
+ENVIRONMENT=development
+ENABLE_LOGGING=true
+ENABLE_TOOL_SELECTION=true
+
diff --git a/examples/agent/startup-simulator-3000/README.md b/examples/agent/startup-simulator-3000/README.md
new file mode 100644
index 00000000..9014eafb
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/README.md
@@ -0,0 +1,289 @@
+# 🚀 Startup Simulator 3000
+
+An 8-bit styled AI-powered startup pitch generator that creates either silly, creative
+pitches or professional business proposals. Built with a custom agentic framework
+powered by OpenAI and monitored with Splunk AO observability.
+
+This is a **complete, self-contained version** that you can copy to any directory and
+run immediately!
+
+
+
+## ✨ Features
+
+### 🎭 Dual Modes
+
+- **Silly Mode**: Generates absurd, creative startup pitches inspired by HackerNews
+ trends
+- **Serious Mode**: Creates professional, corporate business proposals with market
+ analysis from NewsAPI
+
+### 🎮 8-bit Web Interface
+
+- Retro pixel art styling with vibrant color scheme
+- Animated backgrounds and glowing text effects
+- Responsive design for desktop and mobile
+- Interactive mode selection and form validation
+
+### 🤖 Custom Agent Framework
+
+- Multi-tool agent architecture built from scratch
+- Dynamic tool selection based on execution mode
+- Comprehensive input validation and error handling
+- Real-time context fetching from external APIs
+- Custom tool registry and execution system
+
+### 📊 Splunk AO Observability
+
+- Complete workflow and tool execution logging
+- Structured JSON output for debugging and analysis
+- LLM call tracking with token usage and performance metrics
+- Distributed tracing across the entire execution pipeline
+
+## 🚀 Quick Start Guide
+
+### Step 1: Prerequisites
+
+Make sure you have:
+
+- **Python 3.10+** installed on your system
+- **Git** (optional, for cloning)
+- **A code editor** (VS Code, PyCharm, etc.)
+
+### Step 2: Copy This Folder
+
+Simply copy this entire `startup-sim-3000-standalone` folder to wherever you want to
+run it!
+
+### Step 3: Set Up Python Environment
+
+```bash
+# Navigate to the folder
+cd startup-sim-3000-standalone
+
+# Create a virtual environment
+python -m venv venv
+
+# Activate the virtual environment
+# On Windows:
+venv\Scripts\activate
+# On macOS/Linux:
+source venv/bin/activate
+
+# Install dependencies
+pip install -r requirements.txt
+```
+
+### Step 4: Configure API Keys
+
+From within your code editor of choice, copy the `.example.env` file to `.env` and
+fill in the values. Don't forget to add the `.env` file to your `.gitignore` file.
+
+**Required API Keys:**
+
+- **OpenAI API Key**: Get one at
+ [https://platform.openai.com/api-keys](https://platform.openai.com/api-keys)
+- **NewsAPI Key**: Get one at
+ [https://newsapi.org/register](https://newsapi.org/register) (for serious mode)
+- **Splunk AO API Key**: Get one at
+ [https://console.galileo.ai/](https://console.galileo.ai/) (for observability)
+
+Your `.env` file should look like this:
+
+```env
+# Splunk AO Environment Variables
+SPLUNK_AO_API_KEY=your-splunk-ao-api-key # Your Splunk AO API key.
+SPLUNK_AO_PROJECT=your-splunk-ao-project-name # Your Splunk AO project name.
+SPLUNK_AO_LOG_STREAM=your-splunk-ao-log-stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# SPLUNK_AO_CONSOLE_URL=your-splunk-ao-console-url # Optional if you are using a hosted version of Splunk AO
+
+# Required API Keys
+OPENAI_API_KEY=sk-your-openai-key-here
+NEWS_API_KEY=your-newsapi-key-here
+
+# Optional Configuration
+LLM_MODEL=gpt-4
+LLM_TEMPERATURE=0.7
+VERBOSITY=low
+ENVIRONMENT=development
+ENABLE_LOGGING=true
+```
+
+### Step 5: Run the Application
+
+```bash
+# Start the web server
+python app.py
+```
+
+### Step 6: Open Your Browser
+
+Navigate to: **http://localhost:2021**
+
+You should see the Startup Sim 3000 web interface! 🎉
+
+## 🎯 How to Use
+
+### Web Interface
+
+1. **Choose Mode**: Select either "🎭 SILLY MODE" or "💼 SERIOUS MODE"
+2. **Fill in Details**:
+ - **Industry**: What industry your startup is in (e.g., "fintech", "healthcare",
+ "education")
+ - **Target Audience**: Who you're targeting (e.g., "millennials", "small
+ businesses", "developers")
+ - **Random Word**: A word to include in your pitch (e.g., "blockchain", "AI",
+ "sustainability")
+3. **Generate**: Click the "Generate Startup Pitch" button
+4. **Enjoy**: Read your creative or professional startup pitch!
+
+### Command Line (Alternative)
+
+```bash
+# Run the CLI version
+python run_startup_sim.py
+```
+
+## 🏗️ Project Structure
+
+```
+startup-sim-3000-standalone/
+├── app.py # Main Flask application
+├── agent.py # Core agent implementation
+├── tools.json # Tool configuration
+├── requirements.txt # Python dependencies
+├── .env.example # Environment variables template
+├── .gitignore # Git ignore patterns
+├── README.md # This file
+├── TUTORIAL.md # Detailed tutorial
+├── agent_framework/ # Custom agent framework
+│ ├── agent.py # Base Agent class
+│ ├── models.py # Data models and schemas
+│ ├── config.py # Configuration management
+│ ├── exceptions.py # Custom exceptions
+│ ├── llm/ # LLM providers (OpenAI)
+│ ├── tools/ # Tool base classes
+│ ├── prompts/ # Prompt templates
+│ └── utils/ # Utility functions
+├── tools/ # Tool implementations
+│ ├── startup_simulator.py
+│ ├── serious_startup_simulator.py
+│ ├── hackernews_tool.py
+│ └── news_api_tool.py
+├── templates/ # HTML templates
+│ ├── index.html # Main web interface
+│ ├── instructions.html
+│ └── credits.html
+└── static/ # Static assets
+ ├── css/ # Stylesheets
+ ├── js/ # JavaScript
+ └── images/ # Images and logos
+```
+
+## 🔧 Troubleshooting
+
+### Common Issues
+
+**1. "Module not found" errors**
+
+```bash
+# Make sure you're in the virtual environment
+# Your prompt should show (venv)
+source venv/bin/activate # or venv\Scripts\activate on Windows
+```
+
+**2. "OPENAI_API_KEY not set" error**
+
+```bash
+# Check your .env file exists and has the correct key
+cat .env
+# Make sure OPENAI_API_KEY=sk-your-actual-key-here
+```
+
+**3. Port 2021 already in use**
+
+```bash
+# Change the port in app.py or kill the existing process
+# In app.py, change: app.run(debug=True, host='0.0.0.0', port=2021)
+# to: app.run(debug=True, host='0.0.0.0', port=2022)
+```
+
+**4. Splunk AO logging not working**
+
+- This is optional! The app will work without Splunk AO
+- If you want Splunk AO, make sure your API key and project are set correctly
+
+### Getting Help
+
+1. **Check the logs**: Look at the terminal output for error messages
+2. **Verify API keys**: Make sure all required API keys are set in `.env`
+3. **Check Python version**: Ensure you're using Python 3.8+
+4. **Reinstall dependencies**: `pip install -r requirements.txt --force-reinstall`
+
+## 🎓 Learning Resources
+
+### For Beginners
+
+- **Python Basics**:
+ [Python.org Tutorial](https://docs.python.org/3/tutorial/)
+- **Flask Web Framework**:
+ [Flask Documentation](https://flask.palletsprojects.com/)
+- **Async Programming**:
+ [Python AsyncIO Tutorial](https://docs.python.org/3/library/asyncio.html)
+
+### For AI/ML Developers
+
+- **OpenAI API**:
+ [OpenAI Documentation](https://platform.openai.com/docs)
+- **Custom Agent Development**: Study the `agent_framework/` directory to understand
+ agent architecture
+- **Splunk AO Observability**:
+ [Splunk AO Documentation](https://docs.galileo.ai/)
+
+### For Web Developers
+
+- **HTML/CSS/JavaScript**:
+ [MDN Web Docs](https://developer.mozilla.org/)
+- **Responsive Design**:
+ [CSS Grid and Flexbox](https://css-tricks.com/snippets/css/complete-guide-grid/)
+
+### For Agent Framework Development
+
+- **Custom Tool Development**: Study the tools in the `tools/` directory
+- **Agent Architecture**: Examine `agent_framework/agent.py` for the base Agent class
+- **Observability Patterns**: Learn from the Splunk AO integration in each tool
+
+## 🤝 Contributing
+
+This is a standalone version, but if you want to contribute to the main project:
+
+1. Fork the original repository
+2. Create a feature branch
+3. Make your changes
+4. Submit a pull request
+
+## 🙏 Acknowledgments
+
+- **OpenAI** for providing the GPT models
+- **Splunk AO** for observability and monitoring
+- **NewsAPI** for business news data
+- **HackerNews** for tech community trends
+- **Flask** for the web framework
+- **Custom Agent Framework** for demonstrating agent architecture from scratch
+
+## 📞 Support
+
+If you run into issues:
+
+1. Check the troubleshooting section above
+2. Look at the terminal logs for error messages
+3. Verify your API keys are correct
+4. Make sure you're using Python 3.10+
+
+---
+
+**Happy Startup Pitching! 🚀**
+
+*Built with ❤️ and silliness for those exploring the world of AI*
\ No newline at end of file
diff --git a/examples/agent/startup-simulator-3000/TUTORIAL.md b/examples/agent/startup-simulator-3000/TUTORIAL.md
new file mode 100644
index 00000000..94980075
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/TUTORIAL.md
@@ -0,0 +1,491 @@
+# 🎓 Tutorial: Building an AI-Powered Startup Pitch Generator
+
+## Overview
+
+### Learning Objectives
+
+By the end of this tutorial, you will be able to:
+
+* Build a complete AI agent system that coordinates multiple specialized tools using a custom framework
+* Implement proper observability using Splunk AO logging with both tool spans and LLM spans
+* Create a dual-mode AI application that generates both creative and professional startup pitches
+* Develop a modern web interface for AI applications with real-time feedback
+* Understand best practices for custom agent architecture, error handling, and deployment
+
+### Intended Audience
+
+This tutorial is designed for developers who want to learn how to build production-ready AI applications with proper observability using a custom agent framework. You should have:
+
+* Basic knowledge of Python programming (intermediate level)
+* Familiarity with async/await patterns in Python
+* Understanding of web development concepts (HTML, CSS, JavaScript)
+* Experience with API integrations and environment configuration
+
+## 🚀 Getting Started
+
+### Step 1: Environment Setup
+
+First, make sure you have the prerequisites installed:
+
+```bash
+# Check Python version (should be 3.8+)
+python --version
+
+# Create and activate virtual environment
+
+# Windows instructions:
+venv\Scripts\activate
+
+# Mac instructions
+python -m venv venv
+source venv/bin/activate # On Windows: venv\Scripts\activate
+
+# Install dependencies
+pip install -r requirements.txt
+```
+
+### Step 2: API Key Configuration
+
+You'll need several API keys to run this application:
+
+1. **OpenAI API Key** (Required)
+ - Visit: https://platform.openai.com/api-keys
+ - Create an account and generate a new API key
+ - This is used for the AI language model
+
+2. **NewsAPI Key** (Required for Serious Mode)
+ - Visit: https://newsapi.org/register
+ - Sign up for a free account
+ - This provides business news for market analysis
+
+3. **Splunk AO API Key** (Optional but Recommended)
+ - Visit: https://console.galileo.ai/
+ - Create an account and generate an API key
+ - This provides observability and monitoring
+
+### Step 3: Configure Environment Variables
+
+```bash
+# Copy the example environment file
+cp .env.example .env
+
+# Edit the file with your API keys
+nano .env # or use your preferred editor
+```
+
+Your `.env` file should look like this:
+
+```env
+# Splunk AO Environment Variables
+SPLUNK_AO_API_KEY=your-splunk-ao-api-key # Your Splunk AO API key.
+SPLUNK_AO_PROJECT=your-splunk-ao-project-name # Your Splunk AO project name.
+SPLUNK_AO_LOG_STREAM=your-splunk-ao-log-stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# SPLUNK_AO_CONSOLE_URL=your-splunk-ao-console-url # Optional if you are using a hosted version of Splunk AO
+
+# Required API Keys
+OPENAI_API_KEY=sk-your-openai-api-key-here
+NEWS_API_KEY=your-newsapi-key-here
+
+# Optional Configuration
+LLM_MODEL=gpt-4
+LLM_TEMPERATURE=0.7
+VERBOSITY=low
+ENVIRONMENT=development
+ENABLE_LOGGING=true
+```
+
+## 🏗️ Understanding the Architecture
+
+### How the Application Works
+
+The Startup Simulator 3000 follows this flow:
+
+```
+1. User Input → 2. Agent Planning → 3. Tool Execution → 4. Result Generation
+```
+
+#### Step 1: User Input
+- User provides: Industry, Audience, Random Word
+- System determines mode (Silly vs Serious)
+
+#### Step 2: Agent Planning
+- Custom AI agent analyzes the request
+- Creates a step-by-step execution plan
+- Selects appropriate tools based on mode
+
+#### Step 3: Tool Execution
+- **Silly Mode**: HackerNews Tool → Startup Simulator
+- **Serious Mode**: NewsAPI Tool → Serious Startup Simulator
+- Each tool executes with Splunk AO logging
+
+#### Step 4: Result Generation
+- Agent combines all results
+- Formats the final startup pitch
+- Returns structured output
+
+### Core Components
+
+#### 1. Flask Web Server (`app.py`)
+```python
+@app.route('/api/generate', methods=['POST'])
+def generate_startup():
+ # Handles web requests
+ # Validates input
+ # Calls the agent
+ # Returns results
+```
+
+#### 2. Custom Agent Framework (`agent.py`)
+```python
+class SimpleAgent(Agent):
+ def __init__(self, llm_provider, mode="silly"):
+ # Initializes the agent with tools
+ # Sets up Splunk AO logging
+ # Configures execution mode
+```
+
+#### 3. Tools (`tools/`)
+- `startup_simulator.py`: Generates creative pitches
+- `serious_startup_simulator.py`: Generates professional plans
+- `hackernews_tool.py`: Fetches tech trends
+- `news_api_tool.py`: Fetches business news
+
+#### 4. Web Interface (`templates/index.html`)
+- 8-bit retro styling
+- Mode selection
+- Form validation
+- Real-time feedback
+
+## 🎯 Running the Application
+
+### Option 1: Web Interface (Recommended)
+
+```bash
+# Start the Flask server
+python app.py
+```
+
+Then open your browser to: **http://localhost:2021**
+
+### Option 2: Command Line
+
+```bash
+# Run the CLI version
+python run_startup_sim.py
+```
+
+### Option 3: Test Individual Tools
+
+```bash
+# Test the startup simulator directly
+python -c "
+import asyncio
+from tools.startup_simulator import StartupSimulatorTool
+result = asyncio.run(StartupSimulatorTool().execute('tech', 'developers', 'AI'))
+print(result)
+"
+```
+
+## 🔍 Understanding the Code
+
+### Agent Execution Flow
+
+Let's trace through what happens when you generate a startup pitch:
+
+1. **Web Request** (`app.py`)
+```python
+@app.route('/api/generate', methods=['POST'])
+def generate_startup():
+ data = request.json
+ industry = data.get('industry', '').strip()
+ audience = data.get('audience', '').strip()
+ random_word = data.get('randomWord', '').strip()
+ mode = data.get('mode', 'silly').strip()
+```
+
+2. **Splunk AO Trace Start**
+```python
+logger = SplunkAOLogger(
+ project=os.environ.get("SPLUNK_AO_PROJECT"),
+ log_stream=os.environ.get("SPLUNK_AO_LOG_STREAM")
+)
+trace = logger.start_trace(f"Generate startup pitch - {mode} mode")
+```
+
+3. **Agent Creation**
+```python
+llm_provider = OpenAIProvider(config=LLMConfig(model="gpt-4", temperature=0.7))
+agent = SimpleAgent(llm_provider=llm_provider, mode=mode)
+```
+
+4. **Task Execution**
+```python
+task = f"Generate a startup pitch for {industry} targeting {audience} with word '{random_word}'"
+result = await agent.run(task, industry=industry, audience=audience, random_word=random_word)
+```
+
+### Tool Execution Example
+
+Here's how the startup simulator tool works:
+
+```python
+class StartupSimulatorTool(BaseTool):
+ async def execute(self, industry: str, audience: str, random_word: str, hn_context: str = "") -> str:
+ # 1. Log inputs
+ inputs = {"industry": industry, "audience": audience, "random_word": random_word}
+
+ # 2. Create prompt
+ prompt = f"Generate a creative startup pitch for {industry} targeting {audience}..."
+
+ # 3. Call OpenAI API
+ response = client.chat.completions.create(
+ messages=[{"role": "user", "content": prompt}],
+ model="gpt-4"
+ )
+
+ # 4. Format output
+ output = {
+ "pitch": response.choices[0].message.content,
+ "character_count": len(pitch),
+ "timestamp": datetime.now().isoformat()
+ }
+
+ # 5. Log to Splunk AO
+ logger.conclude(output=json.dumps(output), duration_ns=0)
+
+ return json.dumps(output)
+```
+
+## 🎨 Customizing the Application
+
+### Adding New Tools
+
+To add a new tool, create a file in the `tools/` directory:
+
+```python
+# tools/my_new_tool.py
+from agent_framework.tools.base import BaseTool
+from agent_framework.models import ToolMetadata
+
+class MyNewTool(BaseTool):
+ def __init__(self):
+ super().__init__()
+ self.name = "my_new_tool"
+ self.description = "Description of what this tool does"
+
+ @classmethod
+ def get_metadata(cls) -> ToolMetadata:
+ return ToolMetadata(
+ name="my_new_tool",
+ description="Description of what this tool does",
+ tags=["custom", "tool"],
+ input_schema={
+ "type": "object",
+ "properties": {
+ "input_param": {"type": "string", "description": "Input parameter"}
+ },
+ "required": ["input_param"]
+ },
+ output_schema={
+ "type": "string",
+ "description": "Tool output"
+ }
+ )
+
+ async def execute(self, input_param: str) -> str:
+ # Your tool logic here
+ result = f"Processed: {input_param}"
+ return result
+```
+
+Then register it in the agent's tool registry in `agent.py`:
+
+```python
+def _register_tools(self) -> None:
+ # Register your new tool
+ self.tool_registry.register(
+ metadata=MyNewTool.get_metadata(),
+ implementation=MyNewTool
+ )
+```
+
+### Modifying the Web Interface
+
+The web interface is in `templates/index.html`. Key sections:
+
+```html
+
+
+ 🎭 SILLY MODE
+ 💼 SERIOUS MODE
+
+
+
+
+```
+
+### Styling Changes
+
+The CSS is in `static/css/style.css`. Key styling features:
+
+```css
+/* 8-bit Retro Theme */
+body {
+ background: linear-gradient(45deg, #1a1a2e, #16213e, #0f3460);
+ font-family: 'Courier New', monospace;
+ color: #00ff41;
+}
+
+/* Glowing Effects */
+.glow {
+ text-shadow: 0 0 10px #00ff41, 0 0 20px #00ff41, 0 0 30px #00ff41;
+}
+
+/* Animated Background */
+@keyframes pixelate {
+ 0% { transform: scale(1); }
+ 50% { transform: scale(1.1); }
+ 100% { transform: scale(1); }
+}
+```
+
+## 🔧 Debugging and Troubleshooting
+
+### Common Issues and Solutions
+
+#### 1. "Module not found" errors
+```bash
+# Make sure virtual environment is activated
+source venv/bin/activate
+pip install -r requirements.txt
+```
+
+#### 2. API Key errors
+```bash
+# Check your .env file
+cat .env
+# Make sure all required keys are set
+```
+
+#### 3. Splunk AO logging issues
+```bash
+# Splunk AO is optional - the app works without it
+# Check your Splunk AO configuration
+echo $SPLUNK_AO_API_KEY
+echo $SPLUNK_AO_PROJECT
+```
+
+#### 4. Port conflicts
+```bash
+# Change port in app.py
+app.run(debug=True, host='0.0.0.0', port=2022) # Change 2021 to 2022
+```
+
+### Debug Mode
+
+Enable debug logging by setting in `.env`:
+```env
+VERBOSITY=high
+ENABLE_LOGGING=true
+```
+
+### Splunk AO Dashboard
+
+If you have Splunk AO set up, you can view:
+- Tool execution traces
+- LLM call metrics
+- Performance analytics
+- Error tracking
+
+Visit: https://console.galileo.ai/
+
+## 🚀 Deployment
+
+### Local Development
+```bash
+python app.py
+```
+
+### Production Deployment
+
+For production, consider:
+
+1. **Environment Variables**
+```bash
+export FLASK_ENV=production
+export FLASK_DEBUG=0
+```
+
+2. **WSGI Server**
+```bash
+pip install gunicorn
+gunicorn -w 4 -b 0.0.0.0:2021 app:app
+```
+
+3. **Docker Deployment**
+```dockerfile
+FROM python:3.10-slim
+WORKDIR /app
+COPY requirements.txt .
+RUN pip install -r requirements.txt
+COPY . .
+EXPOSE 2021
+CMD ["python", "app.py"]
+```
+
+## 📚 Next Steps
+
+### Learning Path
+
+1. **Understand the Basics**
+ - Read through `app.py` and understand the Flask routes
+ - Study `agent.py` to understand the custom agent framework
+ - Examine the tools in the `tools/` directory
+ - Explore the `agent_framework/` directory to understand the architecture
+
+2. **Experiment with Tools**
+ - Try modifying the startup simulator prompts
+ - Add new tools to the system
+ - Test different LLM models
+
+3. **Enhance the Interface**
+ - Modify the CSS for different themes
+ - Add new form fields
+ - Implement real-time updates
+
+4. **Scale the Application**
+ - Add database storage for generated pitches
+ - Implement user authentication
+ - Add rate limiting and caching
+
+### Advanced Topics
+
+- **Custom Agent Development**: Learn more about building agent frameworks from scratch
+- **Observability**: Deep dive into Splunk AO's monitoring capabilities
+- **API Design**: Study RESTful API best practices
+- **Frontend Development**: Explore modern JavaScript frameworks
+- **Tool Architecture**: Understand how to design and implement custom tools
+
+## 🎉 Congratulations!
+
+You've successfully:
+- Set up a complete AI application with a custom agent framework
+- Understood the custom agentic architecture
+- Implemented observability with Splunk AO
+- Created a dual-mode startup pitch generator
+- Built a modern web interface
+
+You now have a solid foundation for building AI-powered applications with custom agent frameworks, proper observability, and user interfaces!
+
+---
+
+**Happy Coding! 🚀**
+
+*This tutorial demonstrates building AI agents from scratch. For more information, explore the `agent_framework/` directory to understand the custom architecture.*
\ No newline at end of file
diff --git a/examples/agent/startup-simulator-3000/__init__.py b/examples/agent/startup-simulator-3000/__init__.py
new file mode 100644
index 00000000..ee0f238e
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/__init__.py
@@ -0,0 +1,8 @@
+from tools.startup_simulator import StartupSimulatorTool
+
+__all__ = [
+ "SimpleAgent",
+ "TextAnalyzerTool",
+ "KeywordExtractorTool",
+ "StartupSimulatorTool",
+]
diff --git a/examples/agent/startup-simulator-3000/agent.py b/examples/agent/startup-simulator-3000/agent.py
new file mode 100644
index 00000000..402bd4e8
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent.py
@@ -0,0 +1,774 @@
+#!/usr/bin/env python3
+"""
+Simple Agent for Startup Pitch Generation
+This agent generates startup pitches using different tools based on the selected mode.
+"""
+
+import os
+import json
+from typing import Dict, Any, List, Optional
+from datetime import datetime
+from dotenv import load_dotenv
+from splunk_ao import SplunkAOLogger
+from splunk_ao.openai import openai
+
+from agent_framework.agent import Agent
+from agent_framework.models import VerbosityLevel, ToolSelectionHooks
+from agent_framework.llm.openai_provider import OpenAIProvider
+from agent_framework.llm.models import LLMConfig
+from agent_framework.utils.logging import ConsoleAgentLogger
+from agent_framework.utils.tool_hooks import LoggingToolSelectionHooks
+
+# Import all available tools
+from tools.startup_simulator import StartupSimulatorTool
+from tools.serious_startup_simulator import SeriousStartupSimulatorTool
+from tools.hackernews_tool import HackerNewsTool
+from tools.news_api_tool import NewsAPITool
+from tools.text_analysis import TextAnalyzerTool
+from tools.keyword_extraction import KeywordExtractorTool
+
+# Load environment variables
+load_dotenv()
+
+# Use the Splunk AO-wrapped OpenAI client
+client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
+
+
+class SimpleAgent(Agent):
+ """
+ A simple agent that generates startup pitches.
+
+ This agent demonstrates:
+ 1. Tool-based architecture with specialized tools
+ 2. Mode-based execution (silly vs serious)
+ 3. Splunk AO observability with proper span logging
+ 4. Context-aware tool execution
+ """
+
+ def __init__(
+ self,
+ verbosity: VerbosityLevel = VerbosityLevel.LOW,
+ logger: Optional[ConsoleAgentLogger] = None,
+ tool_selection_hooks: Optional[ToolSelectionHooks] = None,
+ metadata: Optional[Dict[str, Any]] = None,
+ llm_provider: Optional[OpenAIProvider] = None,
+ mode: str = "silly",
+ ):
+ # Create default LLM config if not provided
+ if llm_provider is None:
+ llm_config = LLMConfig(model="gpt-4", temperature=0.7, max_tokens=1000)
+ llm_provider = OpenAIProvider(config=llm_config)
+
+ # Initialize the base Agent class with configuration
+ super().__init__(
+ agent_id=f"startup-agent-{mode}",
+ verbosity=verbosity,
+ logger=logger or ConsoleAgentLogger(f"startup-agent-{mode}"),
+ tool_selection_hooks=tool_selection_hooks or LoggingToolSelectionHooks(logger or ConsoleAgentLogger(f"startup-agent-{mode}")),
+ metadata=metadata or {},
+ llm_provider=llm_provider,
+ )
+
+ self.mode = mode
+ self.task_parameters = {}
+
+ # Register all available tools
+ self._register_tools()
+
+ # Set up logger with tool hooks
+ if self.logger:
+ self._setup_logger(self.logger)
+
+ def _register_tools(self) -> None:
+ """
+ Register all available tools with the agent's tool registry.
+
+ Think of tools as specialized functions that the agent can call.
+ Each tool has:
+ - A name and description
+ - Input/output schemas (what it expects and returns)
+ - Tags for categorization
+ - An implementation (the actual code that runs)
+
+ The agent will automatically choose which tools to use based on the task.
+ """
+
+ # Text analysis tool - can analyze and process text content
+ self.tool_registry.register(metadata=TextAnalyzerTool.get_metadata(), implementation=TextAnalyzerTool)
+
+ # Keyword extraction tool - finds important words/phrases in text
+ self.tool_registry.register(
+ metadata=KeywordExtractorTool.get_metadata(),
+ implementation=KeywordExtractorTool,
+ )
+
+ # Startup simulator tool - generates silly, creative startup pitches
+ # Used in "silly" mode
+ self.tool_registry.register(
+ metadata=StartupSimulatorTool.get_metadata(),
+ implementation=StartupSimulatorTool,
+ )
+
+ # Serious startup simulator tool - generates professional business plans
+ # Used in "serious" mode
+ self.tool_registry.register(
+ metadata=SeriousStartupSimulatorTool.get_metadata(),
+ implementation=SeriousStartupSimulatorTool,
+ )
+
+ # HackerNews tool - fetches trending tech stories for inspiration
+ # Used in "silly" mode to get creative context
+ self.tool_registry.register(metadata=HackerNewsTool.get_metadata(), implementation=HackerNewsTool)
+
+ # NewsAPI tool - fetches business news for market analysis
+ # Used in "serious" mode to get professional context
+ self.tool_registry.register(metadata=NewsAPITool.get_metadata(), implementation=NewsAPITool)
+
+ async def _format_result(self, task: str, results: List[tuple[str, Any]], galileo_logger: SplunkAOLogger) -> str:
+ """
+ Format the final result from tool executions.
+
+ This method takes the raw outputs from all the tools and formats them
+ into a coherent, user-friendly response. It's like the final step in
+ a recipe where you plate the dish nicely.
+
+ Args:
+ task: The original user request
+ results: List of (tool_name, result) tuples from executed tools
+ galileo_logger: Splunk AO logger instance for span creation
+
+ Returns:
+ Formatted string response for the user
+ """
+
+ # Add LLM span for result formatting
+ galileo_logger.add_llm_span(
+ input=f"Formatting results for task: {task}",
+ output="Formatting started",
+ model="result_formatter",
+ num_input_tokens=len(str(results)),
+ num_output_tokens=0,
+ total_tokens=len(str(results)),
+ duration_ns=0,
+ )
+
+ try:
+ # Check for silly mode first - look for startup_simulator tool results
+ for tool_name, result in results:
+ if tool_name == "startup_simulator":
+ # Parse the JSON string result from Splunk AO-formatted output
+ try:
+ if isinstance(result, str):
+ parsed_result = json.loads(result)
+ pitch = parsed_result.get("pitch", "")
+ else:
+ # Fallback for dict format
+ pitch = result.get("pitch", "")
+
+ # Log full structured result to Splunk AO for observability
+ result_data = {
+ "tool": tool_name,
+ "mode": "silly",
+ "full_result": result,
+ "extracted_pitch": pitch,
+ }
+ print(f"Agent Result Data (Silly): {json.dumps(result_data, indent=2)}")
+
+ # Add LLM span for formatting completion
+ galileo_logger.add_llm_span(
+ input=f"Result formatting completed for {tool_name}",
+ output=pitch,
+ model="result_formatter",
+ num_input_tokens=len(str(result)),
+ num_output_tokens=len(pitch),
+ total_tokens=len(str(result)) + len(pitch),
+ duration_ns=0,
+ )
+
+ return pitch
+
+ except json.JSONDecodeError as e:
+ print(f"Error parsing startup simulator result: {e}")
+ galileo_logger.add_llm_span(
+ input=f"Error parsing result for {tool_name}",
+ output=str(e),
+ model="result_formatter",
+ num_input_tokens=len(str(result)),
+ num_output_tokens=len(str(e)),
+ total_tokens=len(str(result)) + len(str(e)),
+ duration_ns=0,
+ )
+ return str(result)
+
+ elif tool_name == "serious_startup_simulator":
+ # Parse the JSON string result from Splunk AO-formatted output
+ try:
+ if isinstance(result, str):
+ parsed_result = json.loads(result)
+ pitch = parsed_result.get("pitch", "")
+ else:
+ # Fallback for dict format
+ pitch = result.get("pitch", "")
+
+ # Log full structured result to Splunk AO for observability
+ result_data = {
+ "tool": tool_name,
+ "mode": "serious",
+ "full_result": result,
+ "extracted_pitch": pitch,
+ }
+ print(f"Agent Result Data (Serious): {json.dumps(result_data, indent=2)}")
+
+ # Add LLM span for formatting completion
+ galileo_logger.add_llm_span(
+ input=f"Result formatting completed for {tool_name}",
+ output=pitch,
+ model="result_formatter",
+ num_input_tokens=len(str(result)),
+ num_output_tokens=len(pitch),
+ total_tokens=len(str(result)) + len(pitch),
+ duration_ns=0,
+ )
+
+ return pitch
+
+ except json.JSONDecodeError as e:
+ print(f"Error parsing serious startup simulator result: {e}")
+ galileo_logger.add_llm_span(
+ input=f"Error parsing result for {tool_name}",
+ output=str(e),
+ model="result_formatter",
+ num_input_tokens=len(str(result)),
+ num_output_tokens=len(str(e)),
+ total_tokens=len(str(result)) + len(str(e)),
+ duration_ns=0,
+ )
+ return str(result)
+
+ # If no startup simulator results found, return a summary
+ summary = f"Generated results for {len(results)} tools: {[r[0] for r in results]}"
+ galileo_logger.add_llm_span(
+ input="No startup simulator results found",
+ output=summary,
+ model="result_formatter",
+ num_input_tokens=len(str(results)),
+ num_output_tokens=len(summary),
+ total_tokens=len(str(results)) + len(summary),
+ duration_ns=0,
+ )
+ return summary
+
+ except Exception as e:
+ galileo_logger.add_llm_span(
+ input="Error in result formatting",
+ output=str(e),
+ model="result_formatter",
+ num_input_tokens=len(str(results)),
+ num_output_tokens=len(str(e)),
+ total_tokens=len(str(results)) + len(str(e)),
+ duration_ns=0,
+ )
+ raise e
+
+ async def _execute_hackernews_tool(self, limit: int = 3, galileo_logger: SplunkAOLogger = None) -> str:
+ """
+ Execute the HackerNews tool to get trending stories for context.
+
+ This tool fetches recent HackerNews stories to provide creative inspiration
+ for the startup pitch generation. It's used in "silly" mode.
+
+ Args:
+ limit: Number of stories to fetch
+ galileo_logger: Splunk AO logger instance for span creation
+
+ Returns:
+ JSON string with HackerNews context
+ """
+
+ if galileo_logger:
+ # Add LLM span for tool execution start
+ galileo_logger.add_llm_span(
+ input=f"Executing HackerNews tool with limit: {limit}",
+ output="Tool execution started",
+ model="hackernews_tool",
+ num_input_tokens=len(str(limit)),
+ num_output_tokens=0,
+ total_tokens=len(str(limit)),
+ duration_ns=0,
+ )
+
+ try:
+ startup_tool_class = self.tool_registry.get_implementation("hackernews_tool")
+ if startup_tool_class:
+ startup_tool = startup_tool_class()
+ startup_result = await startup_tool.execute(limit=limit)
+
+ # Add LLM span for tool completion
+ if galileo_logger:
+ galileo_logger.add_llm_span(
+ input="HackerNews tool execution completed",
+ output=(startup_result[:200] + "..." if len(startup_result) > 200 else startup_result),
+ model="hackernews_tool",
+ num_input_tokens=len(str(limit)),
+ num_output_tokens=len(startup_result),
+ total_tokens=len(str(limit)) + len(startup_result),
+ duration_ns=0,
+ )
+
+ return startup_result
+
+ # Tool not found
+ if galileo_logger:
+ galileo_logger.add_llm_span(
+ input="HackerNews tool not found",
+ output="",
+ model="hackernews_tool",
+ num_input_tokens=len(str(limit)),
+ num_output_tokens=0,
+ total_tokens=len(str(limit)),
+ duration_ns=0,
+ )
+ return ""
+
+ except Exception as e:
+ if galileo_logger:
+ galileo_logger.add_llm_span(
+ input="Error in HackerNews tool execution",
+ output=str(e),
+ model="hackernews_tool",
+ num_input_tokens=len(str(limit)),
+ num_output_tokens=len(str(e)),
+ total_tokens=len(str(limit)) + len(str(e)),
+ duration_ns=0,
+ )
+ raise e
+
+ async def _execute_news_api_tool(
+ self,
+ category: str = "business",
+ limit: int = 5,
+ galileo_logger: SplunkAOLogger = None,
+ ) -> str:
+ """
+ Execute the NewsAPI tool to get business news for context.
+
+ This tool fetches recent business news articles to provide market analysis
+ and professional context for the startup plan generation. It's used in "serious" mode.
+
+ Args:
+ category: News category to fetch
+ limit: Number of articles to fetch
+ galileo_logger: Splunk AO logger instance for span creation
+
+ Returns:
+ JSON string with business news context
+ """
+
+ if galileo_logger:
+ # Add LLM span for tool execution start
+ galileo_logger.add_llm_span(
+ input=f"Executing News API tool with category: {category}, limit: {limit}",
+ output="Tool execution started",
+ model="news_api_tool",
+ num_input_tokens=len(str(category)) + len(str(limit)),
+ num_output_tokens=0,
+ total_tokens=len(str(category)) + len(str(limit)),
+ duration_ns=0,
+ )
+
+ try:
+ startup_tool_class = self.tool_registry.get_implementation("news_api_tool")
+ if startup_tool_class:
+ startup_tool = startup_tool_class()
+ startup_result = await startup_tool.execute(category=category, limit=limit)
+
+ # Add LLM span for tool completion
+ if galileo_logger:
+ galileo_logger.add_llm_span(
+ input="News API tool execution completed",
+ output=(startup_result[:200] + "..." if len(startup_result) > 200 else startup_result),
+ model="news_api_tool",
+ num_input_tokens=len(str(category)) + len(str(limit)),
+ num_output_tokens=len(startup_result),
+ total_tokens=len(str(category)) + len(str(limit)) + len(startup_result),
+ duration_ns=0,
+ )
+
+ return startup_result
+
+ # Tool not found
+ if galileo_logger:
+ galileo_logger.add_llm_span(
+ input="News API tool not found",
+ output="",
+ model="news_api_tool",
+ num_input_tokens=len(str(category)) + len(str(limit)),
+ num_output_tokens=0,
+ total_tokens=len(str(category)) + len(str(limit)),
+ duration_ns=0,
+ )
+ return ""
+
+ except Exception as e:
+ if galileo_logger:
+ galileo_logger.add_llm_span(
+ input="Error in News API tool execution",
+ output=str(e),
+ model="news_api_tool",
+ num_input_tokens=len(str(category)) + len(str(limit)),
+ num_output_tokens=len(str(e)),
+ total_tokens=len(str(category)) + len(str(limit)) + len(str(e)),
+ duration_ns=0,
+ )
+ raise e
+
+ async def _execute_startup_simulator(
+ self,
+ industry: str,
+ audience: str,
+ random_word: str,
+ hn_context: str = "",
+ galileo_logger: SplunkAOLogger = None,
+ ) -> str:
+ """
+ Execute the startup simulator tool for silly mode.
+
+ This tool generates creative, humorous startup pitches using HackerNews
+ context for inspiration. It's the main tool used in "silly" mode.
+
+ Args:
+ industry: Target industry for the startup
+ audience: Target audience for the startup
+ random_word: Random word to include in the pitch
+ hn_context: HackerNews context for inspiration
+ galileo_logger: Splunk AO logger instance for span creation
+
+ Returns:
+ JSON string with generated startup pitch
+ """
+
+ if galileo_logger:
+ # Add LLM span for tool execution start
+ galileo_logger.add_llm_span(
+ input=f"Executing startup simulator for {industry} targeting {audience} with word '{random_word}'",
+ output="Tool execution started",
+ model="startup_simulator",
+ num_input_tokens=len(industry) + len(audience) + len(random_word) + len(hn_context),
+ num_output_tokens=0,
+ total_tokens=len(industry) + len(audience) + len(random_word) + len(hn_context),
+ duration_ns=0,
+ )
+
+ try:
+ startup_tool_class = self.tool_registry.get_implementation("startup_simulator")
+ if startup_tool_class:
+ startup_tool = startup_tool_class()
+ startup_result = await startup_tool.execute(
+ industry=industry,
+ audience=audience,
+ random_word=random_word,
+ hn_context=hn_context,
+ )
+
+ # Add LLM span for tool completion
+ if galileo_logger:
+ galileo_logger.add_llm_span(
+ input="Startup simulator execution completed",
+ output=(startup_result[:200] + "..." if len(startup_result) > 200 else startup_result),
+ model="startup_simulator",
+ num_input_tokens=len(industry) + len(audience) + len(random_word) + len(hn_context),
+ num_output_tokens=len(startup_result),
+ total_tokens=len(industry) + len(audience) + len(random_word) + len(hn_context) + len(startup_result),
+ duration_ns=0,
+ )
+
+ return startup_result
+
+ # Tool not found
+ if galileo_logger:
+ galileo_logger.add_llm_span(
+ input="Startup simulator tool not found",
+ output="",
+ model="startup_simulator",
+ num_input_tokens=len(industry) + len(audience) + len(random_word) + len(hn_context),
+ num_output_tokens=0,
+ total_tokens=len(industry) + len(audience) + len(random_word) + len(hn_context),
+ duration_ns=0,
+ )
+ return ""
+
+ except Exception as e:
+ if galileo_logger:
+ galileo_logger.add_llm_span(
+ input="Error in startup simulator execution",
+ output=str(e),
+ model="startup_simulator",
+ num_input_tokens=len(industry) + len(audience) + len(random_word) + len(hn_context),
+ num_output_tokens=len(str(e)),
+ total_tokens=len(industry) + len(audience) + len(random_word) + len(hn_context) + len(str(e)),
+ duration_ns=0,
+ )
+ raise e
+
+ async def _execute_serious_startup_simulator(
+ self,
+ industry: str,
+ audience: str,
+ random_word: str,
+ news_context: str = "",
+ galileo_logger: SplunkAOLogger = None,
+ ) -> str:
+ """
+ Execute the serious startup simulator tool for professional mode.
+
+ This tool generates professional, business-focused startup plans using
+ business news context for market analysis. It's the main tool used in "serious" mode.
+
+ Args:
+ industry: Target industry for the startup
+ audience: Target audience for the startup
+ random_word: Random word to include in the plan
+ news_context: Business news context for market analysis
+ galileo_logger: Splunk AO logger instance for span creation
+
+ Returns:
+ JSON string with generated startup plan
+ """
+
+ if galileo_logger:
+ # Add LLM span for tool execution start
+ galileo_logger.add_llm_span(
+ input=f"Executing serious startup simulator for {industry} targeting {audience} with word '{random_word}'",
+ output="Tool execution started",
+ model="serious_startup_simulator",
+ num_input_tokens=len(industry) + len(audience) + len(random_word) + len(news_context),
+ num_output_tokens=0,
+ total_tokens=len(industry) + len(audience) + len(random_word) + len(news_context),
+ duration_ns=0,
+ )
+
+ try:
+ startup_tool_class = self.tool_registry.get_implementation("serious_startup_simulator")
+ if startup_tool_class:
+ startup_tool = startup_tool_class()
+ startup_result = await startup_tool.execute(
+ industry=industry,
+ audience=audience,
+ random_word=random_word,
+ news_context=news_context,
+ )
+
+ # Add LLM span for tool completion
+ if galileo_logger:
+ galileo_logger.add_llm_span(
+ input="Serious startup simulator execution completed",
+ output=(startup_result[:200] + "..." if len(startup_result) > 200 else startup_result),
+ model="serious_startup_simulator",
+ num_input_tokens=len(industry) + len(audience) + len(random_word) + len(news_context),
+ num_output_tokens=len(startup_result),
+ total_tokens=len(industry) + len(audience) + len(random_word) + len(news_context) + len(startup_result),
+ duration_ns=0,
+ )
+
+ return startup_result
+
+ # Tool not found
+ if galileo_logger:
+ galileo_logger.add_llm_span(
+ input="Serious startup simulator tool not found",
+ output="",
+ model="serious_startup_simulator",
+ num_input_tokens=len(industry) + len(audience) + len(random_word) + len(news_context),
+ num_output_tokens=0,
+ total_tokens=len(industry) + len(audience) + len(random_word) + len(news_context),
+ duration_ns=0,
+ )
+ return ""
+
+ except Exception as e:
+ if galileo_logger:
+ galileo_logger.add_llm_span(
+ input="Error in serious startup simulator execution",
+ output=str(e),
+ model="serious_startup_simulator",
+ num_input_tokens=len(industry) + len(audience) + len(random_word) + len(news_context),
+ num_output_tokens=len(str(e)),
+ total_tokens=len(industry) + len(audience) + len(random_word) + len(news_context) + len(str(e)),
+ duration_ns=0,
+ )
+ raise e
+
+ async def run(self, task: str, industry: str = "", audience: str = "", random_word: str = "") -> str:
+ """
+ Execute the agent's task with Splunk AO monitoring.
+
+ This is the main entry point for the agent. It orchestrates the entire process:
+ 1. Stores user parameters for tool execution
+ 2. Starts Splunk AO tracing for observability
+ 3. Executes tools in sequence with proper context passing
+ 4. Formats the final result
+
+ Args:
+ task: The user's request (e.g., "generate a startup pitch")
+ industry: Target industry for the startup
+ audience: Target audience for the startup
+ random_word: Random word to include in the pitch
+
+ Returns:
+ Formatted startup pitch as a string
+ """
+
+ # Store parameters for tool execution
+ # These will be passed to individual tools as needed
+ self.task_parameters = {
+ "industry": industry,
+ "audience": audience,
+ "random_word": random_word,
+ }
+
+ # Log workflow start as JSON for observability
+ # This helps us understand the agent's decision-making process
+ workflow_data = {
+ "agent_id": self.agent_id,
+ "mode": self.mode,
+ "task": task,
+ "start_time": datetime.now().isoformat(),
+ "tools_registered": list(self.tool_registry.get_all_tools().keys()),
+ }
+ print(f"Agent Workflow Start: {json.dumps(workflow_data, indent=2)}")
+
+ # Get the centralized Splunk AO logger instance
+ from agent_framework.utils.logging import get_galileo_logger
+
+ galileo_logger = get_galileo_logger()
+
+ # Start the main agent trace - this is the parent trace for the entire workflow
+ if galileo_logger:
+ galileo_logger.start_trace(f"agent_workflow_{self.mode}")
+
+ try:
+ # Add LLM span for workflow start if logger is available
+ if galileo_logger:
+ galileo_logger.add_llm_span(
+ input=f"Agent workflow started for task: {task}",
+ output="Workflow initialization",
+ model="agent_workflow",
+ num_input_tokens=len(task),
+ num_output_tokens=0,
+ total_tokens=len(task),
+ duration_ns=0,
+ )
+
+ # Execute tools based on mode with proper context passing
+ results = []
+
+ if self.mode == "serious":
+ # Step 1: Get news context first
+ print("🔍 Step 1: Fetching business news for context...")
+ news_context = await self._execute_news_api_tool(category="business", limit=5, galileo_logger=galileo_logger)
+ results.append(("news_api", news_context))
+
+ # Step 2: Generate serious startup pitch using the news context
+ print("📝 Step 2: Generating professional startup plan...")
+ startup_result = await self._execute_serious_startup_simulator(
+ industry=industry,
+ audience=audience,
+ random_word=random_word,
+ news_context=news_context,
+ galileo_logger=galileo_logger,
+ )
+ results.append(("serious_startup_simulator", startup_result))
+
+ else: # silly mode
+ # Step 1: Get HackerNews context first
+ print("🔍 Step 1: Fetching HackerNews stories for inspiration...")
+ hn_context = await self._execute_hackernews_tool(limit=3, galileo_logger=galileo_logger)
+ results.append(("hackernews", hn_context))
+
+ # Step 2: Generate silly startup pitch using the HN context
+ print("🎭 Step 2: Generating creative startup pitch...")
+ startup_result = await self._execute_startup_simulator(
+ industry=industry,
+ audience=audience,
+ random_word=random_word,
+ hn_context=hn_context,
+ galileo_logger=galileo_logger,
+ )
+ results.append(("startup_simulator", startup_result))
+
+ # Step 3: Format the final result
+ print("✨ Step 3: Formatting final result...")
+ formatted_result = await self._format_result(task, results, galileo_logger)
+
+ # Log workflow completion as JSON
+ completion_data = {
+ "agent_id": self.agent_id,
+ "mode": self.mode,
+ "task": task,
+ "end_time": datetime.now().isoformat(),
+ "result_length": len(formatted_result),
+ "tools_used": [result[0] for result in results],
+ "execution_status": "success",
+ }
+ print(f"Agent Workflow Complete: {json.dumps(completion_data, indent=2)}")
+
+ # Add LLM span for workflow completion if logger is available
+ if galileo_logger:
+ galileo_logger.add_llm_span(
+ input="Agent workflow completed successfully",
+ output=formatted_result,
+ model="agent_workflow",
+ num_input_tokens=len(task),
+ num_output_tokens=len(formatted_result),
+ total_tokens=len(task) + len(formatted_result),
+ duration_ns=0,
+ )
+
+ # Prepare structured JSON output for Splunk AO workflow logging
+ workflow_result = {
+ "agent_id": self.agent_id,
+ "mode": self.mode,
+ "task": task,
+ "final_output": formatted_result,
+ "tools_used": [result[0] for result in results],
+ "execution_status": "success",
+ "timestamp": datetime.now().isoformat(),
+ }
+
+ # Only call on_agent_done after all tools have completed
+ if self.logger:
+ await self.logger.on_agent_done(formatted_result, self.message_history)
+
+ # Conclude the trace successfully and flush immediately
+ if galileo_logger:
+ galileo_logger.conclude(output=formatted_result, duration_ns=0)
+ galileo_logger.flush()
+
+ # Return structured JSON string for Splunk AO workflow logging
+ return json.dumps(workflow_result, indent=2)
+
+ except Exception as e:
+ # Add LLM span for workflow error if logger is available
+ if galileo_logger:
+ galileo_logger.add_llm_span(
+ input="Agent workflow error",
+ output=str(e),
+ model="agent_workflow",
+ num_input_tokens=len(task),
+ num_output_tokens=len(str(e)),
+ total_tokens=len(task) + len(str(e)),
+ duration_ns=0,
+ )
+
+ # Conclude the trace with error and flush immediately
+ galileo_logger.conclude(output=str(e), duration_ns=0, error=True)
+ galileo_logger.flush()
+
+ raise e
+ finally:
+ # Only set end_time if current_task exists
+ if hasattr(self, "current_task") and self.current_task is not None:
+ self.current_task.end_time = datetime.now()
+ if self.current_task.status == "in_progress":
+ self.current_task.status = "completed"
+ self._current_plan = None # Clear the plan
diff --git a/examples/agent/startup-simulator-3000/agent_framework/__init__.py b/examples/agent/startup-simulator-3000/agent_framework/__init__.py
new file mode 100644
index 00000000..39e869af
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/__init__.py
@@ -0,0 +1,18 @@
+"""Agent Framework - A framework for building AI agents"""
+
+from .agent import Agent
+from .config import AgentConfiguration
+from .models import AgentMetadata, VerbosityLevel
+from .exceptions import AgentError, ToolNotFoundError, ToolExecutionError
+
+__version__ = "0.1.0"
+
+__all__ = [
+ "Agent",
+ "AgentConfiguration",
+ "AgentMetadata",
+ "VerbosityLevel",
+ "AgentError",
+ "ToolNotFoundError",
+ "ToolExecutionError",
+]
diff --git a/examples/agent/startup-simulator-3000/agent_framework/agent.py b/examples/agent/startup-simulator-3000/agent_framework/agent.py
new file mode 100644
index 00000000..9fa7cd2e
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/agent.py
@@ -0,0 +1,397 @@
+from abc import ABC, abstractmethod
+from typing import Any, Dict, List, Optional
+from uuid import uuid4
+from datetime import datetime
+from splunk_ao import log # 🔍 Splunk AO import - this is the main Splunk AO logging library
+from .utils.logging import AgentLogger
+from .utils.tool_registry import ToolRegistry
+
+from .models import (
+ TaskExecution,
+ VerbosityLevel,
+ TaskAnalysis,
+ ToolContext,
+ ToolSelectionHooks,
+ AgentConfig,
+)
+from .llm.base import LLMProvider
+from .llm.models import LLMMessage
+
+from .utils.formatting import (
+ display_task_header,
+ display_analysis,
+ display_chain_of_thought,
+ display_execution_plan,
+ display_error,
+ display_final_result,
+)
+
+from .exceptions import ToolNotFoundError, ToolExecutionError
+
+
+class Agent(ABC):
+ """Base class for all agents in the framework"""
+
+ def __init__(
+ self,
+ *args,
+ agent_id: Optional[str] = None,
+ verbosity: VerbosityLevel = VerbosityLevel.LOW,
+ logger: Optional[AgentLogger] = None,
+ tool_selection_hooks: Optional[ToolSelectionHooks] = None,
+ metadata: Optional[Dict[str, Any]] = None,
+ llm_provider: Optional[LLMProvider] = None,
+ **kwargs,
+ ):
+ self.agent_id = agent_id or str(uuid4())
+ self.config = AgentConfig(
+ verbosity=verbosity,
+ tool_selection_hooks=tool_selection_hooks,
+ metadata=metadata or {},
+ )
+ self.llm_provider = llm_provider
+ self.tool_registry = ToolRegistry()
+ self.current_task: Optional[TaskExecution] = None
+ self.state: Dict[str, Any] = {}
+ self.message_history: List[Dict[str, Any]] = []
+ self.logger = logger
+ self._current_plan: Optional[TaskAnalysis] = None
+
+ def _setup_logger(self, logger: AgentLogger) -> None:
+ """Create and set up the logger after tools are registered"""
+
+ # Set hooks for all registered tools
+ for tool in self.tool_registry.list_tools():
+ tool.hooks = logger.get_tool_hooks()
+ # Set tool selection hooks
+ self.tool_selection_hooks = logger.get_tool_selection_hooks()
+
+ def log_message(self, message: str, level: VerbosityLevel = VerbosityLevel.LOW) -> None:
+ """Log a message if verbosity level is sufficient"""
+ if self.config.verbosity.value >= level.value:
+ print(message)
+
+ def _create_tool_context(self, tool_name: str, inputs: Dict[str, Any]) -> ToolContext:
+ """Create a context object for tool execution"""
+ if not self.current_task:
+ raise ValueError("No active task")
+
+ return ToolContext(
+ task=self.current_task.input,
+ tool_name=tool_name,
+ inputs=inputs,
+ available_tools=self.tool_registry.get_formatted_tools(),
+ previous_tools=[step.tool_name for step in self.current_task.steps],
+ previous_results=[step.result for step in self.current_task.steps if step.result],
+ previous_errors=[step.error for step in self.current_task.steps if step.error],
+ message_history=self.message_history.copy(),
+ agent_id=self.agent_id,
+ task_id=self.current_task.task_id,
+ start_time=self.current_task.start_time,
+ metadata=self.config.metadata,
+ plan=self._current_plan, # Pass the current plan in the context
+ )
+
+ # 👀 GALILEO DECORATOR: This decorator automatically creates a span for tool execution
+ # The @log decorator wraps this method and automatically logs it to Splunk AO
+ # This means every tool call will be tracked in your Splunk AO dashboard
+ @log(span_type="tool", name="tool_execution")
+ async def call_tool(
+ self,
+ tool_name: str,
+ inputs: Dict[str, Any],
+ execution_reasoning: str,
+ context: Dict[str, Any],
+ ) -> Dict[str, Any]:
+ """Execute a tool and log the call with selection reasoning"""
+ tool = self.tool_registry.get_tool(tool_name)
+ if not tool:
+ raise ValueError(f"Tool {tool_name} not found")
+
+ tool_context = self._create_tool_context(tool_name, inputs)
+
+ try:
+ # Call before_execution hook if available
+ if tool.hooks:
+ await tool.hooks.before_execution(tool_context)
+
+ # Execute the tool using registry
+ result = await self._execute_tool(tool_name, inputs)
+
+ # Record the execution
+ self.message_history.append(
+ {
+ "role": "tool",
+ "tool_name": tool_name,
+ "inputs": inputs,
+ "result": result,
+ "reasoning": execution_reasoning,
+ "timestamp": datetime.now(),
+ }
+ )
+
+ # Call after_execution hook if available
+ if tool.hooks:
+ await tool.hooks.after_execution(tool_context, result)
+
+ return result
+
+ except Exception as e:
+ # Call after_execution hook with error if available
+ if tool.hooks:
+ await tool.hooks.after_execution(tool_context, None, error=e)
+ raise
+
+ async def _execute_tool(self, tool_name: str, inputs: Dict[str, Any]) -> Dict[str, Any]:
+ """Execute a tool with given inputs"""
+ tool_impl = self.tool_registry.get_implementation(tool_name)
+ if not tool_impl:
+ raise ToolNotFoundError(f"No implementation found for tool: {tool_name}")
+
+ try:
+ tool_instance = tool_impl()
+ result = await tool_instance.execute(**inputs)
+
+ # Store result in state
+ self.state.set_tool_result(tool_name, result)
+
+ return result
+ except Exception as e:
+ raise ToolExecutionError(tool_name, e)
+
+ def _create_planning_prompt(self, task: str) -> List[LLMMessage]:
+ """Create prompt for task planning"""
+ tools_description = "\n".join(
+ [
+ f"Tool: {tool.name}\n"
+ f"Description: {tool.description}\n"
+ f"Tags: {', '.join(tool.tags)}\n"
+ f"Input Schema: {tool.input_schema}\n"
+ f"Output Schema: {tool.output_schema}\n"
+ for tool in self.tool_registry.get_all_tools().values()
+ ]
+ )
+
+ system_prompt = (
+ "You are an intelligent task planning system. Your role is to analyze tasks and create detailed execution plans.\n\n"
+ "You MUST provide a complete response with ALL of the following components:\n\n"
+ "1. input_analysis: A thorough analysis of the task requirements and constraints\n"
+ "2. available_tools: List of all tools that could potentially be used\n"
+ "3. tool_capabilities: A mapping of each available tool to its key capabilities\n"
+ "4. execution_plan: A list of steps, where each step has:\n"
+ " - tool: The name of the tool to use\n"
+ " - reasoning: Why this tool was chosen for this step\n"
+ "5. requirements_coverage: How each requirement is covered by which tools\n"
+ "6. chain_of_thought: Your step-by-step reasoning process\n\n"
+ f"Available Tools:\n{tools_description}\n\n"
+ "Your response MUST be a JSON object with this EXACT structure:\n"
+ "{\n"
+ ' "input_analysis": "detailed analysis of the task",\n'
+ ' "available_tools": ["tool1", "tool2"],\n'
+ ' "tool_capabilities": {\n'
+ ' "tool1": ["capability1", "capability2"],\n'
+ ' "tool2": ["capability3"]\n'
+ " },\n"
+ ' "execution_plan": [\n'
+ ' {"tool": "tool1", "reasoning": "why tool1 is used"},\n'
+ ' {"tool": "tool2", "reasoning": "why tool2 is used"}\n'
+ " ],\n"
+ ' "requirements_coverage": {\n'
+ ' "requirement1": ["tool1"],\n'
+ ' "requirement2": ["tool1", "tool2"]\n'
+ " },\n"
+ ' "chain_of_thought": [\n'
+ ' "step 1 reasoning",\n'
+ ' "step 2 reasoning"\n'
+ " ]\n"
+ "}\n\n"
+ "Ensure ALL fields are present and properly formatted. Missing fields will cause errors."
+ )
+
+ return [
+ LLMMessage(role="system", content=system_prompt),
+ LLMMessage(
+ role="user",
+ content=f"Task: {task}\n\nAnalyze this task and create a complete execution plan with ALL required fields.",
+ ),
+ ]
+
+ async def plan_task(self, task: str) -> TaskAnalysis:
+ """Create an execution plan for the task using chain of thought reasoning"""
+ if not self.llm_provider:
+ raise RuntimeError("LLM provider not configured")
+
+ messages = self._create_planning_prompt(task)
+
+ # Log the planning prompt
+ if self.logger:
+ self.logger.on_agent_start(task)
+
+ if self.config.verbosity == VerbosityLevel.HIGH:
+ display_task_header(task)
+
+ try:
+ plan: TaskAnalysis = await self.llm_provider.generate_structured(messages, TaskAnalysis, self.llm_provider.config)
+
+ # Log the planning response
+ if self.logger:
+ await self.logger.on_agent_planning(plan.input_analysis)
+
+ if self.config.verbosity == VerbosityLevel.HIGH:
+ display_analysis(plan.input_analysis)
+ display_chain_of_thought(plan.chain_of_thought)
+ display_execution_plan(plan.execution_plan)
+
+ return plan
+ except Exception as e:
+ if self.logger:
+ self.logger.error(
+ "Failed to generate task plan",
+ error=str(e),
+ task=task,
+ task_id=self.current_task.task_id if self.current_task else None,
+ )
+ if self.config.verbosity == VerbosityLevel.HIGH:
+ display_error(str(e))
+ raise
+
+ async def run(self, task: str) -> str:
+ """Execute a task and return the result"""
+ self.current_task = TaskExecution(
+ task_id=str(uuid4()),
+ agent_id=self.agent_id,
+ input=task,
+ start_time=datetime.now(),
+ steps=[],
+ )
+
+ if self.logger:
+ self.logger.on_agent_start(task)
+
+ try:
+ # Create a plan using chain of thought reasoning
+ self._current_plan = await self.plan_task(task)
+
+ # Execute each step in the plan
+ results = []
+ for step in self._current_plan.execution_plan:
+ result = await self._execute_step(step, task, self._current_plan)
+ results.append((step["tool"], result))
+
+ # Format final result
+ result = await self._format_result(task, results)
+ self.current_task.output = result
+
+ # Only call on_agent_done after all tools have completed
+ if self.logger:
+ await self.logger.on_agent_done(result, self.message_history)
+
+ if self.config.verbosity == VerbosityLevel.HIGH:
+ display_final_result(result)
+ return result
+
+ except Exception as e:
+ self.current_task.error = str(e)
+ self.current_task.status = "failed"
+ raise
+ finally:
+ self.current_task.end_time = datetime.now()
+ if self.current_task.status == "in_progress":
+ self.current_task.status = "completed"
+ self._current_plan = None # Clear the plan
+
+ async def _execute_step(self, step: Dict[str, Any], task: str, plan: TaskAnalysis) -> Any:
+ """Execute a single step in the plan"""
+ tool_name = step["tool"]
+ if not self.tool_registry.get_tool(tool_name):
+ raise ToolNotFoundError(f"Tool {tool_name} not found")
+
+ # Map inputs for the tool
+ inputs = await self._map_inputs_to_tool(tool_name, task, step.get("input_mapping", {}))
+
+ # Create tool context once for both calls
+ tool_context = self._create_tool_context(tool_name, inputs)
+
+ # Log tool selection first
+ if self.logger and (hooks := self.logger.get_tool_selection_hooks()):
+ await hooks.after_selection(tool_context, tool_name, 1.0, [step["reasoning"]])
+
+ # Then execute the tool
+ result = await self.call_tool(
+ tool_name=tool_name,
+ inputs=inputs,
+ execution_reasoning=step["reasoning"],
+ context={"task": task, "plan": plan},
+ )
+
+ return result
+
+ @abstractmethod
+ async def _format_result(self, task: str, results: List[tuple[str, Dict[str, Any]]]) -> str:
+ """Format the final result from tool executions"""
+ pass
+
+ async def _map_inputs_to_tool(self, tool_name: str, task: str, input_mapping: Dict[str, str]) -> Dict[str, Any]:
+ """Map inputs based on tool schema"""
+ tool = self.tool_registry.get_tool(tool_name)
+ if not tool:
+ raise ToolNotFoundError(f"Tool {tool_name} not found")
+
+ # Get the tool's input schema
+ required_inputs = tool.input_schema.get("properties", {})
+
+ # If there's an explicit mapping from the LLM, use it
+ if input_mapping:
+ mapped_inputs = {}
+ for input_name, value_ref in input_mapping.items():
+ # Handle dot notation references (e.g., "event_finder.events")
+ if "." in value_ref:
+ tool_name, field = value_ref.split(".")
+ tool_result = self.state.get_tool_result(tool_name)
+ if tool_result and isinstance(tool_result, dict):
+ mapped_inputs[input_name] = tool_result.get(field)
+ else:
+ # Try to get the entire tool result
+ tool_result = self.state.get_tool_result(value_ref)
+ if tool_result is not None:
+ mapped_inputs[input_name] = tool_result
+ else:
+ # Fall back to using the value as is
+ mapped_inputs[input_name] = value_ref
+ return mapped_inputs
+
+ # Try to map inputs based on schema and state
+ mapped_inputs = {}
+ for input_name, input_schema in required_inputs.items():
+ # Check for referenced tool outputs in schema
+ if "$ref" in input_schema:
+ input_schema.get("$ref").split("/")[-1] # Get referenced type name
+ # Look for any tool result that matches this type
+ for tool_name, result in self.state.tool_results.items():
+ if result and isinstance(result, dict): # Basic type check
+ mapped_inputs[input_name] = result
+ break
+ # Otherwise try direct mapping
+ elif self.state.has_tool_result(input_name):
+ mapped_inputs[input_name] = self.state.get_tool_result(input_name)
+ elif self.state.has_variable(input_name):
+ mapped_inputs[input_name] = self.state.get_variable(input_name)
+ elif input_schema.get("type") == "string":
+ if input_name == "news_context" and hasattr(self, "context_data"):
+ mapped_inputs[input_name] = getattr(self, "context_data", "")
+ elif input_name == "hn_context" and hasattr(self, "context_data"):
+ mapped_inputs[input_name] = getattr(self, "context_data", "")
+ elif hasattr(self, "task_parameters") and input_name in self.task_parameters:
+ mapped_inputs[input_name] = self.task_parameters[input_name]
+ else:
+ mapped_inputs[input_name] = task
+
+ # For tools with no required inputs, return empty dict (all optional)
+ required_fields = tool.input_schema.get("required", [])
+ if not required_fields and not mapped_inputs:
+ return {} # All inputs are optional, can call with no params
+
+ if mapped_inputs:
+ return mapped_inputs
+
+ raise ValueError(f"Could not map inputs for tool {tool_name}")
diff --git a/examples/agent/startup-simulator-3000/agent_framework/config.py b/examples/agent/startup-simulator-3000/agent_framework/config.py
new file mode 100644
index 00000000..884a071d
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/config.py
@@ -0,0 +1,94 @@
+import os
+from typing import Optional, Any, Dict, List
+from dotenv import load_dotenv
+from dataclasses import dataclass, field
+from .models import VerbosityLevel
+from .llm.models import LLMConfig
+
+
+class EnvironmentError(Exception):
+ """Raised when required environment variables are missing"""
+
+ pass
+
+
+@dataclass
+class AgentConfiguration:
+ """Configuration for the agent framework"""
+
+ llm_config: LLMConfig = field(default_factory=lambda: LLMConfig(model="gpt-4", temperature=0.1))
+ api_keys: Dict[str, str] = field(default_factory=dict)
+ verbosity: VerbosityLevel = field(default=VerbosityLevel.LOW)
+ metadata: Dict[str, Any] = field(default_factory=dict)
+ enable_logging: bool = field(default=True)
+ enable_tool_selection: bool = field(default=True)
+
+ @staticmethod
+ def get_env(key: str, default: Optional[str] = None) -> Optional[str]:
+ """Get an environment variable with an optional default"""
+ return os.getenv(key, default)
+
+ @classmethod
+ def from_env(cls, required_keys: List[str], optional_keys: Optional[Dict[str, str]] = None) -> "AgentConfiguration":
+ """Create configuration from environment variables
+
+ Args:
+ required_keys: OPENAI_API_KEY, SPLUNK_AO_API_KEY, SPLUNK_AO_CONSOLE_URL
+ optional_keys: Dict of optional key names to their default values
+ """
+ load_dotenv()
+
+ # Load required API keys
+ api_keys = {}
+ for key_name in required_keys:
+ env_value = os.getenv(f"{key_name.upper()}_API_KEY")
+ if not env_value:
+ raise EnvironmentError(f"{key_name.upper()}_API_KEY environment variable is required. " "Please set it in your .env file")
+ api_keys[key_name] = env_value
+
+ # Load optional API keys
+ if optional_keys:
+ for key_name, default in optional_keys.items():
+ env_value = os.getenv(f"{key_name.upper()}_API_KEY", default)
+ if env_value:
+ api_keys[key_name] = env_value
+
+ # Create configuration
+ return cls(
+ llm_config=LLMConfig(
+ model=os.getenv("LLM_MODEL", "gpt-4"),
+ temperature=float(os.getenv("LLM_TEMPERATURE", "0.1")),
+ ),
+ api_keys=api_keys,
+ verbosity=VerbosityLevel(os.getenv("VERBOSITY", "low")),
+ metadata={"env": os.getenv("ENVIRONMENT", "development")},
+ enable_logging=os.getenv("ENABLE_LOGGING", "true").lower() == "true",
+ enable_tool_selection=os.getenv("ENABLE_TOOL_SELECTION", "true").lower() == "true",
+ )
+
+ def with_overrides(self, **overrides) -> "AgentConfiguration":
+ """Create new config with overridden values"""
+ config_dict = self.__dict__.copy()
+ config_dict.update(overrides)
+ return AgentConfiguration(**config_dict)
+
+ @classmethod
+ def from_dict(cls, config_dict: Dict[str, Any]) -> "AgentConfiguration":
+ """Create configuration from dictionary - mainly used for testing"""
+ if "api_keys" not in config_dict or "openai" not in config_dict["api_keys"]:
+ raise ValueError("OpenAI API key must be provided in api_keys dictionary")
+
+ llm_config = LLMConfig(
+ model=config_dict.get("llm_model", "gpt-4"),
+ temperature=config_dict.get("llm_temperature", 0.1),
+ **config_dict.get("llm_settings", {}),
+ )
+
+ return cls(
+ llm_config=llm_config,
+ api_keys=config_dict["api_keys"],
+ verbosity=VerbosityLevel(config_dict.get("verbosity", "low")),
+ metadata=config_dict.get("metadata", {}),
+ enable_logging=config_dict.get("enable_logging", True),
+ enable_tool_selection=config_dict.get("enable_tool_selection", True),
+ )
diff --git a/examples/agent/startup-simulator-3000/agent_framework/exceptions.py b/examples/agent/startup-simulator-3000/agent_framework/exceptions.py
new file mode 100644
index 00000000..4a6e9e0f
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/exceptions.py
@@ -0,0 +1,43 @@
+class AgentError(Exception):
+ """Base class for agent framework exceptions"""
+
+ pass
+
+
+class ToolError(AgentError):
+ """Base class for tool-related errors"""
+
+ pass
+
+
+class ToolNotFoundError(ToolError):
+ """Raised when a requested tool is not found"""
+
+ pass
+
+
+class ToolExecutionError(ToolError):
+ """Raised when a tool execution fails"""
+
+ def __init__(self, tool_name: str, original_error: Exception):
+ self.tool_name = tool_name
+ self.original_error = original_error
+ super().__init__(f"Tool {tool_name} execution failed: {str(original_error)}")
+
+
+class ConfigurationError(AgentError):
+ """Raised when there's a configuration problem"""
+
+ pass
+
+
+class PlanningError(AgentError):
+ """Raised when task planning fails"""
+
+ pass
+
+
+class StateError(AgentError):
+ """Raised when there's a state-related error"""
+
+ pass
diff --git a/examples/agent/startup-simulator-3000/agent_framework/factory.py b/examples/agent/startup-simulator-3000/agent_framework/factory.py
new file mode 100644
index 00000000..19cb84ee
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/factory.py
@@ -0,0 +1,43 @@
+from typing import Optional, Type
+from .config import AgentConfiguration
+from .llm.base import LLMProvider
+from .llm.openai_provider import OpenAIProvider
+from .utils.logging import ConsoleAgentLogger
+from .agent import Agent
+
+
+class AgentFactory:
+ """Factory for creating agents with proper dependency injection"""
+
+ def __init__(self, config: AgentConfiguration):
+ self.config = config
+ self._llm_provider: Optional[LLMProvider] = None
+ self._logger: Optional[ConsoleAgentLogger] = None
+
+ def get_llm_provider(self) -> LLMProvider:
+ """Get or create LLM provider"""
+ if not self._llm_provider:
+ if "openai" in self.config.api_keys:
+ self._llm_provider = OpenAIProvider(config=self.config.llm_config)
+ else:
+ raise ValueError("No LLM provider configured")
+ return self._llm_provider
+
+ def get_logger(self, agent_id: str) -> Optional[ConsoleAgentLogger]:
+ """Get logger if enabled"""
+ if self.config.enable_logging:
+ return ConsoleAgentLogger(agent_id)
+ return None
+
+ def create_agent(self, agent_class: Type[Agent], agent_id: Optional[str] = None, **kwargs) -> Agent:
+ """Create an agent instance with proper dependencies"""
+ # Create core dependencies
+ llm_provider = self.get_llm_provider()
+ logger = self.get_logger(agent_id) if agent_id else None
+
+ # Create agent with injected dependencies
+ agent = agent_class(
+ agent_id=agent_id, llm_provider=llm_provider, logger=logger, verbosity=self.config.verbosity, metadata=self.config.metadata, **kwargs
+ )
+
+ return agent
diff --git a/examples/agent/startup-simulator-3000/agent_framework/llm/__init__.py b/examples/agent/startup-simulator-3000/agent_framework/llm/__init__.py
new file mode 100644
index 00000000..ccf06cf0
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/llm/__init__.py
@@ -0,0 +1,7 @@
+"""LLM Provider Package"""
+
+from .base import LLMProvider
+from .models import LLMMessage, LLMResponse, LLMConfig
+from .openai_provider import OpenAIProvider
+
+__all__ = ["LLMProvider", "LLMMessage", "LLMResponse", "LLMConfig", "OpenAIProvider"]
diff --git a/examples/agent/startup-simulator-3000/agent_framework/llm/base.py b/examples/agent/startup-simulator-3000/agent_framework/llm/base.py
new file mode 100644
index 00000000..9571ec6c
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/llm/base.py
@@ -0,0 +1,21 @@
+from abc import ABC, abstractmethod
+from typing import List, Optional
+
+from .models import LLMMessage, LLMResponse, LLMConfig
+
+
+class LLMProvider(ABC):
+ """Base class for LLM providers"""
+
+ def __init__(self, config: LLMConfig):
+ self.config = config
+
+ @abstractmethod
+ async def generate(self, messages: List[LLMMessage], config: Optional[LLMConfig] = None) -> LLMResponse:
+ """Generate a response from the LLM"""
+ pass
+
+ @abstractmethod
+ async def generate_stream(self, messages: List[LLMMessage], config: Optional[LLMConfig] = None):
+ """Generate a streaming response from the LLM"""
+ pass
diff --git a/examples/agent/startup-simulator-3000/agent_framework/llm/local_provider.py b/examples/agent/startup-simulator-3000/agent_framework/llm/local_provider.py
new file mode 100644
index 00000000..e69de29b
diff --git a/examples/agent/startup-simulator-3000/agent_framework/llm/models.py b/examples/agent/startup-simulator-3000/agent_framework/llm/models.py
new file mode 100644
index 00000000..346b65b4
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/llm/models.py
@@ -0,0 +1,58 @@
+from typing import Any, Dict, List, Optional
+from pydantic import BaseModel, Field
+
+
+class LLMMessage(BaseModel):
+ """Message format for LLM interactions"""
+
+ role: str
+ content: str
+ name: Optional[str] = None
+
+
+class LLMResponse(BaseModel):
+ """Structured response from LLM"""
+
+ content: str
+ raw_response: Dict[str, Any] = Field(default_factory=dict)
+ finish_reason: Optional[str] = None
+ usage: Optional[Dict[str, int]] = None
+
+
+class LLMConfig(BaseModel):
+ """Configuration for LLM provider"""
+
+ model: str
+ temperature: float = 0.7
+ max_tokens: Optional[int] = None
+ top_p: float = 1.0
+ frequency_penalty: float = 0.0
+ presence_penalty: float = 0.0
+ stop: Optional[List[str]] = None
+ custom_settings: Dict[str, Any] = Field(default_factory=dict)
+
+
+class ToolSelectionOutput(BaseModel):
+ """Output from tool selection"""
+
+ selected_tools: List[str] = Field(description="Names of the selected tools in order of execution")
+ confidence: float = Field(description="Confidence score for the tool selection (0-1)", ge=0.0, le=1.0)
+ reasoning_steps: List[str] = Field(description="List of reasoning steps that led to the tool selection")
+
+ @classmethod
+ def model_json_schema(cls) -> Dict[str, Any]:
+ """Get JSON schema with example"""
+ schema = super().model_json_schema()
+ schema["examples"] = [
+ {
+ "selected_tools": ["text_analyzer", "sentiment_analyzer"],
+ "confidence": 0.9,
+ "reasoning_steps": [
+ "Task involves understanding text complexity and sentiment",
+ "Text analyzer provides detailed analysis capabilities",
+ "Sentiment analyzer provides sentiment analysis capabilities",
+ "Other tools don't provide required capabilities",
+ ],
+ }
+ ]
+ return schema
diff --git a/examples/agent/startup-simulator-3000/agent_framework/llm/openai_provider.py b/examples/agent/startup-simulator-3000/agent_framework/llm/openai_provider.py
new file mode 100644
index 00000000..098fc4d7
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/llm/openai_provider.py
@@ -0,0 +1,153 @@
+from typing import Any, Dict, List, Optional, AsyncGenerator, Type, TypeVar
+from splunk_ao.openai import openai # Use Splunk AO's OpenAI wrapper
+from pydantic import BaseModel
+import os
+from dotenv import load_dotenv
+
+from .base import LLMProvider
+from .models import LLMMessage, LLMResponse, LLMConfig
+
+T = TypeVar("T", bound=BaseModel)
+
+
+class OpenAIProvider(LLMProvider):
+ """OpenAI implementation of LLM provider with support for both regular and project-based keys"""
+
+ def __init__(self, config: LLMConfig, organization: Optional[str] = None):
+ super().__init__(config)
+
+ # Load environment variables
+ load_dotenv()
+
+ # Use provided API key or load from environment
+ self.api_key = os.getenv("OPENAI_API_KEY")
+ if not self.api_key:
+ raise ValueError("OpenAI API key must be provided or set in OPENAI_API_KEY environment variable")
+
+ # Check if this is a project-based key
+ self.is_project_key = self.api_key.startswith("sk-proj-")
+
+ # Get project ID for project-based keys (for logging purposes)
+ self.project_id = None
+ if self.is_project_key:
+ self.project_id = os.getenv("OPENAI_PROJECT_ID")
+ if not self.project_id:
+ # Extract project ID from the key if possible
+ # Project keys format: sk-proj-{project_id}-{key_id}
+ try:
+ parts = self.api_key.split("-")
+ if len(parts) >= 3:
+ self.project_id = parts[2]
+ except:
+ pass
+
+ # Initialize the client - project-based keys should work with the standard client
+ self.client = openai.AsyncOpenAI(api_key=self.api_key)
+
+ if self.is_project_key:
+ print(f"Initialized OpenAI client with project-based key (Project ID: {self.project_id})")
+ else:
+ print("Initialized OpenAI client with regular API key")
+
+ def _prepare_messages(self, messages: List[LLMMessage]) -> List[Dict[str, Any]]:
+ """Convert internal message format to OpenAI format"""
+ return [
+ {
+ "role": msg.role,
+ "content": msg.content,
+ **({"name": msg.name} if msg.name else {}),
+ }
+ for msg in messages
+ ]
+
+ def _prepare_config(self, config: Optional[LLMConfig] = None) -> Dict[str, Any]:
+ """Prepare configuration for OpenAI API"""
+ cfg = config or self.config
+ return {
+ "model": cfg.model,
+ "temperature": cfg.temperature,
+ "max_tokens": cfg.max_tokens,
+ "top_p": cfg.top_p,
+ "frequency_penalty": cfg.frequency_penalty,
+ "presence_penalty": cfg.presence_penalty,
+ "stop": cfg.stop,
+ **cfg.custom_settings,
+ }
+
+ async def generate(self, messages: List[LLMMessage], config: Optional[LLMConfig] = None) -> LLMResponse:
+ """Generate a response using OpenAI"""
+ openai_messages = self._prepare_messages(messages)
+ api_config = self._prepare_config(config)
+
+ try:
+ response = await self.client.chat.completions.create(messages=openai_messages, **api_config)
+
+ choice = response.choices[0]
+ usage = response.usage.model_dump() if response.usage else {}
+ filtered_usage = {k: v for k, v in usage.items() if isinstance(v, int)}
+ return LLMResponse(
+ content=choice.message.content,
+ raw_response=response.model_dump(),
+ finish_reason=choice.finish_reason,
+ usage=filtered_usage if filtered_usage else None,
+ )
+ except Exception as e:
+ if "401" in str(e) and self.is_project_key:
+ raise ValueError(f"Project-based key authentication failed. Please check your OPENAI_PROJECT_ID and ensure the project exists. Error: {e}")
+ raise e
+
+ async def generate_stream(self, messages: List[LLMMessage], config: Optional[LLMConfig] = None) -> AsyncGenerator[LLMResponse, None]:
+ """Generate a streaming response using OpenAI"""
+ openai_messages = self._prepare_messages(messages)
+ api_config = self._prepare_config(config)
+
+ try:
+ stream = await self.client.chat.completions.create(messages=openai_messages, stream=True, **api_config)
+
+ async for chunk in stream:
+ if chunk.choices[0].delta.content:
+ yield LLMResponse(
+ content=chunk.choices[0].delta.content,
+ raw_response=chunk.model_dump(),
+ finish_reason=chunk.choices[0].finish_reason,
+ )
+ except Exception as e:
+ if "401" in str(e) and self.is_project_key:
+ raise ValueError(f"Project-based key authentication failed. Please check your OPENAI_PROJECT_ID and ensure the project exists. Error: {e}")
+ raise e
+
+ async def generate_structured(
+ self,
+ messages: List[LLMMessage],
+ output_model: Type[T],
+ config: Optional[LLMConfig] = None,
+ ) -> T:
+ """Generate a response with structured output using function calling"""
+ openai_messages = self._prepare_messages(messages)
+ api_config = self._prepare_config(config)
+
+ # Create function definition from Pydantic model
+ schema = output_model.model_json_schema()
+ function_def = {
+ "name": "output_structured_data",
+ "description": f"Output data in {output_model.__name__} format",
+ "parameters": schema,
+ }
+
+ try:
+ response = await self.client.chat.completions.create(
+ messages=openai_messages,
+ functions=[function_def],
+ function_call={"name": "output_structured_data"},
+ **api_config,
+ )
+
+ try:
+ function_args = response.choices[0].message.function_call.arguments
+ return output_model.model_validate_json(function_args)
+ except Exception as e:
+ raise ValueError(f"Failed to parse structured output: {e}")
+ except Exception as e:
+ if "401" in str(e) and self.is_project_key:
+ raise ValueError(f"Project-based key authentication failed. Please check your OPENAI_PROJECT_ID and ensure the project exists. Error: {e}")
+ raise e
diff --git a/examples/agent/startup-simulator-3000/agent_framework/llm/tool_models.py b/examples/agent/startup-simulator-3000/agent_framework/llm/tool_models.py
new file mode 100644
index 00000000..110f9adb
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/llm/tool_models.py
@@ -0,0 +1,69 @@
+from typing import Any, Dict, List
+from pydantic import BaseModel, Field
+
+
+class TextAnalysis(BaseModel):
+ """Structured output for text analysis"""
+
+ complexity_score: float = Field(ge=0.0, le=1.0)
+ readability_level: str
+ main_topics: List[str]
+ key_points: List[str]
+ analysis_summary: str
+ language_metrics: Dict[str, Any]
+
+ @classmethod
+ def model_json_schema(cls) -> Dict[str, Any]:
+ """Get JSON schema with example"""
+ schema = super().model_json_schema()
+ schema["examples"] = [
+ {
+ "complexity_score": 0.75,
+ "readability_level": "Advanced",
+ "main_topics": ["artificial intelligence", "neural networks"],
+ "key_points": [
+ "Discusses deep learning architectures",
+ "Covers training methodologies",
+ "Addresses performance optimization",
+ ],
+ "analysis_summary": "Technical text focusing on advanced AI concepts",
+ "language_metrics": {
+ "sentence_count": 15,
+ "average_sentence_length": 20,
+ "vocabulary_richness": 0.8,
+ },
+ }
+ ]
+ return schema
+
+
+class KeywordExtraction(BaseModel):
+ """Structured output for keyword extraction"""
+
+ keywords: List[str] = Field(min_items=1)
+ importance_scores: Dict[str, float]
+ categories: Dict[str, List[str]]
+ extraction_confidence: float = Field(ge=0.0, le=1.0)
+ context_relevance: str
+
+ @classmethod
+ def model_json_schema(cls) -> Dict[str, Any]:
+ """Get JSON schema with example"""
+ schema = super().model_json_schema()
+ schema["examples"] = [
+ {
+ "keywords": ["machine learning", "neural networks", "optimization"],
+ "importance_scores": {
+ "machine learning": 0.9,
+ "neural networks": 0.85,
+ "optimization": 0.7,
+ },
+ "categories": {
+ "technical": ["machine learning", "neural networks"],
+ "methodology": ["optimization"],
+ },
+ "extraction_confidence": 0.85,
+ "context_relevance": "High relevance to AI/ML domain",
+ }
+ ]
+ return schema
diff --git a/examples/agent/startup-simulator-3000/agent_framework/models.py b/examples/agent/startup-simulator-3000/agent_framework/models.py
new file mode 100644
index 00000000..f01230e1
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/models.py
@@ -0,0 +1,211 @@
+from datetime import datetime
+from typing import Any, Dict, List, Optional
+from pydantic import BaseModel, Field, ConfigDict
+from enum import Enum
+from dataclasses import dataclass, field
+from .utils.hooks import ToolHooks, ToolSelectionHooks
+
+
+class ToolMetadata(BaseModel):
+ """Base schema for tool metadata"""
+
+ name: str = Field(description="Unique identifier for the tool")
+ description: str = Field(description="Human-readable description of what the tool does")
+ tags: List[str] = Field(description="Categories/capabilities of the tool")
+ input_schema: Dict[str, Any] = Field(description="JSON schema for tool inputs")
+ output_schema: Dict[str, Any] = Field(description="JSON schema for tool outputs")
+ examples: Optional[List[Dict[str, Any]]] = Field(default=None, description="Example uses of the tool")
+
+
+class ToolError(BaseModel):
+ """Schema for tool errors"""
+
+ error: str = Field(description="Error message from the tool")
+
+
+class AgentMetadata(BaseModel):
+ """Base schema for agent metadata"""
+
+ name: str = Field(description="Name of the agent")
+ description: str = Field(description="What the agent does")
+ capabilities: List[str] = Field(description="High-level capabilities")
+ tools: List[ToolMetadata] = Field(description="Tools available to this agent")
+ version: str = Field(default="1.0.0", description="Version of the agent")
+ custom_attributes: Dict[str, Any] = Field(default_factory=dict, description="Additional custom metadata for the agent")
+ model_config = ConfigDict(arbitrary_types_allowed=True)
+
+
+class VerbosityLevel(str, Enum):
+ """Controls how much information is displayed to the user"""
+
+ NONE = "none" # Only show final results
+ LOW = "low" # Show major steps and results
+ HIGH = "high" # Show detailed execution steps, tool selection, and reasoning
+
+
+class TaskAnalysis(BaseModel):
+ """Analysis of a task using chain of thought reasoning"""
+
+ input_analysis: str = Field(description="Analysis of the input, identifying key requirements and constraints")
+ available_tools: List[str] = Field(description="List of tools available for the task")
+ tool_capabilities: Dict[str, List[str]] = Field(description="Mapping of tools to their key capabilities")
+ execution_plan: List[Dict[str, Any]] = Field(description="Ordered list of steps to execute, each with tool and reasoning")
+ requirements_coverage: Dict[str, List[str]] = Field(description="How the identified requirements are covered by the planned steps")
+ chain_of_thought: List[str] = Field(description="Chain of thought reasoning that led to this plan")
+
+
+@dataclass
+class ToolContext:
+ """Context object passed to tool hooks"""
+
+ def __init__(
+ self,
+ task: str,
+ tool_name: str,
+ inputs: Dict[str, Any],
+ available_tools: List[Dict[str, Any]],
+ previous_tools: List[str],
+ previous_results: List[Any],
+ previous_errors: List[Any],
+ message_history: List[Dict[str, Any]],
+ agent_id: str,
+ task_id: str,
+ start_time: datetime,
+ metadata: Dict[str, Any],
+ plan: Optional[TaskAnalysis] = None,
+ ):
+ self.task = task
+ self.tool_name = tool_name
+ self.inputs = inputs
+ self.available_tools = available_tools
+ self.previous_tools = previous_tools
+ self.previous_results = previous_results
+ self.previous_errors = previous_errors
+ self.message_history = message_history
+ self.agent_id = agent_id
+ self.task_id = task_id
+ self.start_time = start_time
+ self.metadata = metadata
+ self.plan = plan # The agent's planning analysis
+
+
+@dataclass
+class Tool:
+ """Model representing a tool that can be used by an agent"""
+
+ name: str = field(metadata={"description": "Unique identifier for the tool"})
+ description: str = field(metadata={"description": "Human-readable description of what the tool does"})
+ tags: List[str] = field(metadata={"description": "Categories or labels for the tool's capabilities"})
+ input_schema: Dict[str, Any] = field(metadata={"description": "JSON Schema defining expected input parameters"})
+ output_schema: Dict[str, Any] = field(metadata={"description": "JSON Schema defining the tool's output structure"})
+ hooks: Optional[ToolHooks] = field(
+ default=None,
+ metadata={"description": "Optional hooks for tool execution lifecycle"},
+ )
+
+
+class ToolSelectionCriteria(BaseModel):
+ """Criteria used for selecting a tool"""
+
+ required_tags: List[str] = Field(default_factory=list, description="Tags that a tool must have to be considered")
+ preferred_tags: List[str] = Field(
+ default_factory=list,
+ description="Tags that are desired but not required in a tool",
+ )
+ context_requirements: Dict[str, Any] = Field(
+ default_factory=dict,
+ description="Specific contextual requirements that influence tool selection",
+ )
+ custom_rules: Dict[str, Any] = Field(
+ default_factory=dict,
+ description="Additional rules or criteria for tool selection",
+ )
+
+
+class ToolSelectionReasoning(BaseModel):
+ """Record of the reasoning process for tool selection"""
+
+ context: Dict[str, Any] = Field(description="Current context and state when the tool selection was made")
+ considered_tools: List[str] = Field(description="Names of all tools that were evaluated for selection")
+ selection_criteria: ToolSelectionCriteria = Field(description="Criteria used to evaluate and select the tool")
+ reasoning_steps: List[str] = Field(description="Detailed steps of the decision-making process")
+ selected_tool: str = Field(description="Name of the tool that was ultimately chosen")
+ confidence_score: float = Field(
+ description="Confidence level in the tool selection (0.0 to 1.0)",
+ ge=0.0,
+ le=1.0,
+ )
+
+
+class ToolCall(BaseModel):
+ """Record of a tool invocation"""
+
+ tool_name: str = Field(description="Name of the tool that was called")
+ inputs: Dict[str, Any] = Field(description="Parameters passed to the tool during execution")
+ outputs: Optional[Dict[str, Any]] = Field(default=None, description="Results returned by the tool execution")
+ selection_reasoning: Optional[ToolSelectionReasoning] = Field(default=None, description="Reasoning process that led to selecting this tool")
+ execution_reasoning: str = Field(description="Explanation of why this tool was executed")
+ timestamp: datetime = Field(
+ default_factory=datetime.utcnow,
+ description="UTC timestamp when the tool was called",
+ )
+ success: bool = Field(default=True, description="Whether the tool execution completed successfully")
+ error: Optional[str] = Field(default=None, description="Error message if the tool execution failed")
+
+
+class ExecutionStep(BaseModel):
+ """Record of a single step in the agent's execution"""
+
+ step_type: str = Field(description="Category or type of execution step (e.g., 'task_received', 'processing', 'completion')")
+ description: str = Field(description="Human-readable description of what happened in this step")
+ timestamp: datetime = Field(
+ default_factory=datetime.utcnow,
+ description="UTC timestamp when the step occurred",
+ )
+ tool_calls: List[ToolCall] = Field(default_factory=list, description="Tools that were called during this step")
+ intermediate_state: Optional[Dict[str, Any]] = Field(
+ default=None,
+ description="State or context information captured during this step",
+ )
+
+
+class TaskExecution(BaseModel):
+ """Complete record of a task execution"""
+
+ task_id: str = Field(description="Unique identifier for this task execution")
+ agent_id: str = Field(description="Identifier of the agent executing the task")
+ input: str = Field(description="Original input or request given to the agent")
+ steps: List[ExecutionStep] = Field(
+ default_factory=list,
+ description="Sequence of steps taken during task execution",
+ )
+ output: Optional[str] = Field(default=None, description="Final result or response from the task execution")
+ start_time: datetime = Field(
+ default_factory=datetime.utcnow,
+ description="UTC timestamp when task execution began",
+ )
+ end_time: Optional[datetime] = Field(default=None, description="UTC timestamp when task execution completed")
+ status: str = Field(
+ default="in_progress",
+ description="Current status of the task (e.g., 'in_progress', 'completed', 'failed')",
+ )
+ error: Optional[str] = Field(default=None, description="Error message if the task execution failed")
+
+
+@dataclass
+class AgentConfig:
+ """Configuration for an agent"""
+
+ verbosity: VerbosityLevel = field(
+ default=VerbosityLevel.LOW,
+ metadata={"description": "Level of detail to display to the user"},
+ )
+ # logger: Optional[AgentLogger] = field(
+ # default=None,
+ # metadata={"description": "Optional logger for recording agent activity"}
+ # )
+ tool_selection_hooks: Optional[ToolSelectionHooks] = field(default=None, metadata={"description": "Hooks for tool selection lifecycle"})
+ metadata: Dict[str, Any] = field(
+ default_factory=dict,
+ metadata={"description": "Additional configuration metadata"},
+ )
diff --git a/examples/agent/startup-simulator-3000/agent_framework/prompts/templates.py b/examples/agent/startup-simulator-3000/agent_framework/prompts/templates.py
new file mode 100644
index 00000000..ddbeeb24
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/prompts/templates.py
@@ -0,0 +1,40 @@
+from typing import Dict, Any
+from pathlib import Path
+import jinja2
+
+
+class PromptTemplate:
+ """Template for generating prompts with variable substitution"""
+
+ def __init__(self, template_path: str):
+ self.env = jinja2.Environment(
+ loader=jinja2.FileSystemLoader(Path(__file__).parent / "templates"),
+ trim_blocks=True,
+ lstrip_blocks=True,
+ )
+ self.template = self.env.get_template(template_path)
+
+ def render(self, **kwargs: Any) -> str:
+ """Render the template with given variables"""
+ return self.template.render(**kwargs)
+
+
+class PromptLibrary:
+ """Central repository for prompt templates"""
+
+ def __init__(self):
+ self.templates: Dict[str, PromptTemplate] = {}
+ self._load_templates()
+
+ def _load_templates(self) -> None:
+ """Load all templates from the templates directory"""
+ template_dir = Path(__file__).parent / "templates"
+ for template_file in template_dir.glob("*.j2"):
+ template_name = template_file.stem
+ self.templates[template_name] = PromptTemplate(template_file.name)
+
+ def get_template(self, name: str) -> PromptTemplate:
+ """Get a template by name"""
+ if name not in self.templates:
+ raise ValueError(f"Template {name} not found")
+ return self.templates[name]
diff --git a/examples/agent/startup-simulator-3000/agent_framework/prompts/templates/planning.j2 b/examples/agent/startup-simulator-3000/agent_framework/prompts/templates/planning.j2
new file mode 100644
index 00000000..60691cd8
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/prompts/templates/planning.j2
@@ -0,0 +1,16 @@
+Available Tools:
+{% for tool in tools %}
+Tool: {{ tool.name }}
+Description: {{ tool.description }}
+Tags: {{ tool.tags | join(", ") }}
+Input Schema: {{ tool.input_schema | tojson }}
+Output Schema: {{ tool.output_schema | tojson }}
+{% if tool.examples %}
+Examples:
+{% for example in tool.examples %}
+ Input: {{ example.input | tojson }}
+ Output: {{ example.output | tojson }}
+{% endfor %}
+{% endif %}
+
+{% endfor %}
\ No newline at end of file
diff --git a/examples/agent/startup-simulator-3000/agent_framework/prompts/templates/tool_selection.j2 b/examples/agent/startup-simulator-3000/agent_framework/prompts/templates/tool_selection.j2
new file mode 100644
index 00000000..43b3670b
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/prompts/templates/tool_selection.j2
@@ -0,0 +1,25 @@
+You are an intelligent tool selection system. Your task is to analyze the input
+and select the most appropriate tools based on the task requirements and tool capabilities.
+
+Consider the following aspects in your analysis:
+1. Task requirements and complexity
+2. Tool capabilities and limitations
+3. Input/output compatibility
+4. Specific context requirements
+
+Available Tools:
+{{ tools_description }}
+
+Selection Criteria:
+{{ criteria_description }}
+
+Context:
+{{ context_description }}
+
+Provide a thorough analysis of the task and justify your tool selection.
+Consider edge cases and potential limitations of each tool.
+
+Provide your response as a JSON object matching this schema:
+{{ output_schema }}
+
+Ensure your response is valid JSON and matches the schema exactly.
\ No newline at end of file
diff --git a/examples/agent/startup-simulator-3000/agent_framework/state.py b/examples/agent/startup-simulator-3000/agent_framework/state.py
new file mode 100644
index 00000000..28c222cb
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/state.py
@@ -0,0 +1,58 @@
+from typing import Any, Dict, Optional
+from dataclasses import dataclass, field
+from datetime import datetime
+
+
+@dataclass
+class AgentState:
+ """Container for agent state management"""
+
+ # General state
+ variables: Dict[str, Any] = field(default_factory=dict)
+
+ # Tool execution state
+ tool_results: Dict[str, Any] = field(default_factory=dict)
+ last_tool: Optional[str] = None
+
+ # Task state
+ task_start_time: Optional[datetime] = None
+ task_variables: Dict[str, Any] = field(default_factory=dict)
+
+ def has_variable(self, name: str) -> bool:
+ """Check if a variable exists in state"""
+ return name in self.variables
+
+ def set_variable(self, name: str, value: Any) -> None:
+ """Set a state variable"""
+ self.variables[name] = value
+
+ def get_variable(self, name: str, default: Any = None) -> Any:
+ """Get a state variable"""
+ return self.variables.get(name, default)
+
+ def set_tool_result(self, tool_name: str, result: Any) -> None:
+ """Store a tool execution result"""
+ self.tool_results[tool_name] = result
+ self.last_tool = tool_name
+
+ def get_tool_result(self, tool_name: str, default: Any = None) -> Any:
+ """Get a tool execution result"""
+ return self.tool_results.get(tool_name, default)
+
+ def get_last_tool_result(self, default: Any = None) -> Any:
+ """Get the result of the last executed tool"""
+ if not self.last_tool:
+ return default
+ return self.tool_results.get(self.last_tool, default)
+
+ def clear(self) -> None:
+ """Clear all state"""
+ self.variables.clear()
+ self.tool_results.clear()
+ self.last_tool = None
+ self.task_variables.clear()
+ self.task_start_time = None
+
+ def has_tool_result(self, tool_name: str) -> bool:
+ """Check if a tool result exists"""
+ return tool_name in self.tool_results
diff --git a/examples/agent/startup-simulator-3000/agent_framework/tools/base.py b/examples/agent/startup-simulator-3000/agent_framework/tools/base.py
new file mode 100644
index 00000000..49538d79
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/tools/base.py
@@ -0,0 +1,25 @@
+from abc import ABC, abstractmethod
+from typing import Any, Dict, ClassVar, Type
+from ..models import ToolMetadata
+
+
+class BaseTool(ABC):
+ """Base class for all tools"""
+
+ # Tool metadata as class variables
+ metadata: ClassVar[Type[ToolMetadata]]
+
+ def __init__(self):
+ """Initialize the base tool"""
+ pass
+
+ @classmethod
+ def get_metadata(cls) -> ToolMetadata:
+ """Get tool metadata for planning"""
+ # Create an instance of the metadata class
+ return cls.metadata() # This will use the default values defined in the metadata class
+
+ @abstractmethod
+ async def execute(self, **inputs: Any) -> Dict[str, Any]:
+ """Execute the tool with given inputs"""
+ raise NotImplementedError("Tool must implement execute method")
diff --git a/examples/agent/startup-simulator-3000/agent_framework/tools/registry.py b/examples/agent/startup-simulator-3000/agent_framework/tools/registry.py
new file mode 100644
index 00000000..adb9bb39
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/tools/registry.py
@@ -0,0 +1,47 @@
+from typing import Dict, List, Optional, Type, TypeVar
+from ..models import Tool, ToolMetadata
+from ..tools.base import BaseTool
+
+T = TypeVar("T", bound=ToolMetadata)
+
+
+class ToolRegistry:
+ """Central registry for tool management"""
+
+ def __init__(self):
+ self.tools: Dict[str, Tool] = {}
+ self._implementations: Dict[str, Type["BaseTool"]] = {}
+
+ def register(self, *, metadata: T, implementation: Type["BaseTool"]) -> None:
+ """Register a tool and its implementation"""
+ if metadata.name in self.tools:
+ raise ValueError(f"Tool {metadata.name} is already registered")
+
+ # Convert metadata to Tool model
+ tool = Tool(
+ name=metadata.name,
+ description=metadata.description,
+ tags=metadata.tags,
+ input_schema=metadata.input_schema,
+ output_schema=metadata.output_schema,
+ hooks=None, # Hooks will be set by the agent
+ )
+
+ self.tools[metadata.name] = tool
+ self._implementations[metadata.name] = implementation
+
+ def get_tool(self, name: str) -> Optional[Tool]:
+ """Get tool by name"""
+ return self.tools.get(name)
+
+ def get_implementation(self, name: str) -> Optional[Type["BaseTool"]]:
+ """Get tool implementation by name"""
+ return self._implementations.get(name)
+
+ def list_tools(self) -> List[Tool]:
+ """Get list of all registered tools"""
+ return list(self.tools.values())
+
+ def get_tools_by_tags(self, tags: List[str]) -> List[Tool]:
+ """Get tools that have all specified tags"""
+ return [tool for tool in self.tools.values() if all(tag in tool.tags for tag in tags)]
diff --git a/examples/agent/startup-simulator-3000/agent_framework/utils/formatting.py b/examples/agent/startup-simulator-3000/agent_framework/utils/formatting.py
new file mode 100644
index 00000000..c3c001e6
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/utils/formatting.py
@@ -0,0 +1,83 @@
+"""Utilities for formatting and displaying output"""
+
+import json
+from typing import Any, Dict, List
+from rich.console import Console
+from rich.panel import Panel
+from rich.markdown import Markdown
+from rich.table import Table
+from rich.syntax import Syntax
+
+console = Console()
+
+
+def format_json(data: Any) -> str:
+ """Format JSON data for pretty printing"""
+ return json.dumps(data, indent=2, default=str)
+
+
+def display_task_header(task: str):
+ """Display a task header"""
+ console.print(
+ Panel(
+ f"[bold blue]Task:[/bold blue] {task}",
+ title="🤖 Agent Task",
+ border_style="blue",
+ )
+ )
+
+
+def display_analysis(analysis: str):
+ """Display task analysis"""
+ console.print(Panel(Markdown(analysis), title="📋 Task Analysis", border_style="green"))
+
+
+def display_chain_of_thought(steps: List[str]):
+ """Display chain of thought reasoning"""
+ table = Table(title="🤔 Chain of Thought", show_header=False, border_style="cyan")
+ table.add_column("Step", style="dim")
+ table.add_column("Reasoning")
+
+ for i, step in enumerate(steps, 1):
+ table.add_row(f"Step {i}", Markdown(step))
+
+ console.print(table)
+
+
+def display_execution_plan(plan: List[Dict[str, Any]]):
+ """Display execution plan"""
+ table = Table(title="📝 Execution Plan", border_style="magenta")
+ table.add_column("Tool", style="bold cyan")
+ table.add_column("Reasoning")
+
+ for step in plan:
+ table.add_row(step["tool"], Markdown(step["reasoning"]))
+
+ console.print(table)
+
+
+def display_tool_result(tool_name: str, result: Dict[str, Any]):
+ """Display tool execution result"""
+ if isinstance(result, (dict, list)):
+ result_display = Syntax(format_json(result), "json", theme="monokai", word_wrap=True)
+ else:
+ result_display = Markdown(str(result))
+
+ console.print(Panel(result_display, title=f"🔧 {tool_name} Result", border_style="yellow"))
+
+
+def display_final_result(result: str):
+ """Display final combined result"""
+ console.print(
+ Panel(
+ Markdown(result),
+ title="✨ Final Result",
+ border_style="green",
+ padding=(1, 2),
+ )
+ )
+
+
+def display_error(error: str):
+ """Display error message"""
+ console.print(Panel(f"[bold red]Error:[/bold red] {error}", title="❌ Error", border_style="red"))
diff --git a/examples/agent/startup-simulator-3000/agent_framework/utils/hooks.py b/examples/agent/startup-simulator-3000/agent_framework/utils/hooks.py
new file mode 100644
index 00000000..b5e37087
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/utils/hooks.py
@@ -0,0 +1,50 @@
+from typing import Any, Dict, List, Optional
+from dataclasses import dataclass, field
+from datetime import datetime
+from abc import ABC, abstractmethod
+
+
+@dataclass
+class ToolContext:
+ """Context passed to tool hooks containing execution history and metadata"""
+
+ task: str = field(metadata={"description": "The current task being executed"})
+ tool_name: str = field(metadata={"description": "Name of the tool being executed"})
+ inputs: Dict[str, Any] = field(metadata={"description": "Input parameters for the tool"})
+ previous_tools: List[str] = field(metadata={"description": "List of tools that were previously executed in this task"})
+ previous_results: List[Dict[str, Any]] = field(metadata={"description": "Results from previous tool executions"})
+ previous_errors: List[str] = field(metadata={"description": "Errors from previous tool executions"})
+ message_history: List[Dict[str, Any]] = field(metadata={"description": "Complete history of messages and tool executions"})
+ agent_id: str = field(metadata={"description": "ID of the agent executing the tool"})
+ task_id: str = field(metadata={"description": "ID of the current task"})
+ start_time: datetime = field(metadata={"description": "When the task started"})
+ metadata: Dict[str, Any] = field(metadata={"description": "Additional metadata from agent configuration"})
+
+
+class ToolHooks(ABC):
+ """Hooks for tool execution lifecycle"""
+
+ @abstractmethod
+ async def before_execution(self, context: ToolContext) -> None:
+ """Called before tool execution with full context"""
+ pass
+
+ @abstractmethod
+ async def after_execution(self, context: ToolContext, result: Any, error: Optional[Exception] = None) -> None:
+ """Called after tool execution with the result or error"""
+ pass
+
+
+class ToolSelectionHooks(ABC):
+ """Hooks for tool selection lifecycle"""
+
+ @abstractmethod
+ async def after_selection(
+ self,
+ context: ToolContext,
+ selected_tool: str,
+ confidence: float,
+ reasoning: List[str],
+ ) -> None:
+ """Called after tool selection with selection details"""
+ pass
diff --git a/examples/agent/startup-simulator-3000/agent_framework/utils/logging.py b/examples/agent/startup-simulator-3000/agent_framework/utils/logging.py
new file mode 100644
index 00000000..aaf4fa9b
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/utils/logging.py
@@ -0,0 +1,178 @@
+from typing import Any, Dict, List
+from datetime import datetime
+from rich.console import Console
+from rich.panel import Panel
+from rich.theme import Theme
+import json
+from abc import ABC, abstractmethod
+from agent_framework.utils.hooks import ToolHooks, ToolSelectionHooks
+
+# Create a custom theme for our logger
+theme = Theme(
+ {
+ "info": "cyan",
+ "warning": "yellow",
+ "error": "red",
+ "success": "green",
+ "timestamp": "dim cyan",
+ "tool": "magenta",
+ "reasoning": "blue",
+ "confidence": "yellow",
+ }
+)
+
+console = Console(theme=theme)
+
+# 👀 GALILEO GLOBAL VARIABLE: This holds the centralized Splunk AO logger instance
+# This ensures all parts of the application use the same Splunk AO connection
+_global_galileo_logger = None
+
+
+def get_galileo_logger():
+ """Get the global Splunk AO logger instance, initializing it if needed"""
+ global _global_galileo_logger
+
+ if _global_galileo_logger is None:
+ import os
+ from dotenv import load_dotenv
+
+ # Load environment variables
+ load_dotenv()
+
+ # 👀 GALILEO API KEY CHECK: Get the Splunk AO API key from environment variables
+ # This key is required to authenticate with the Splunk AO service
+ api_key = os.getenv("SPLUNK_AO_API_KEY")
+
+ if api_key:
+ try:
+ # 👀 GALILEO IMPORT: Import the SplunkAOLogger class from the galileo library
+ # This is the main class that handles all Splunk AO logging functionality
+ from splunk_ao import SplunkAOLogger
+
+ # 👀 GALILEO INITIALIZATION: Create a new SplunkAOLogger instance
+ # This logger will automatically use environment variables for configuration:
+ # - SPLUNK_AO_API_KEY: Your API key for authentication
+ # - SPLUNK_AO_PROJECT: Your project name/ID
+ # - SPLUNK_AO_LOG_STREAM: The log stream to use
+ _global_galileo_logger = SplunkAOLogger()
+ print("✅ Splunk AO logger initialized successfully using environment variables")
+ except Exception as e:
+ print(f"⚠️ Warning: Could not initialize Splunk AO logger: {e}")
+ _global_galileo_logger = None
+ else:
+ print("⚠️ Warning: SPLUNK_AO_API_KEY not set. Splunk AO logging will be disabled.")
+ _global_galileo_logger = None
+
+ return _global_galileo_logger
+
+
+class AgentLogger(ABC):
+ """Abstract base class for agent logging"""
+
+ def __init__(self, agent_id: str):
+ self.agent_id = agent_id
+ self._tool_hooks = None
+ self._tool_selection_hooks = None
+
+ @abstractmethod
+ def info(self, message: str, **kwargs) -> None:
+ """Log an informational message"""
+ pass
+
+ @abstractmethod
+ def warning(self, message: str, **kwargs) -> None:
+ """Log a warning message"""
+ pass
+
+ @abstractmethod
+ def error(self, message: str, **kwargs) -> None:
+ """Log an error message"""
+ pass
+
+ @abstractmethod
+ def debug(self, message: str, **kwargs) -> None:
+ """Log a debug message"""
+ pass
+
+ @abstractmethod
+ def _write_log(self, log_entry: Dict[str, Any]) -> None:
+ """Write a log entry"""
+ pass
+
+ @abstractmethod
+ def _sanitize_for_json(self, obj: Any) -> Any:
+ """Sanitize an object for JSON serialization"""
+ pass
+
+ @abstractmethod
+ async def on_agent_planning(self, planning_prompt: str) -> None:
+ """Log the agent planning prompt"""
+ pass
+
+ @abstractmethod
+ def on_agent_start(self, initial_task: str) -> None:
+ """Log the agent execution prompt"""
+ pass
+
+ @abstractmethod
+ async def on_agent_done(self, result: str, message_history: List[Dict[str, Any]]) -> None:
+ """Log the agent completion"""
+ pass
+
+ def get_tool_hooks(self) -> ToolHooks:
+ """Get tool hooks for this logger"""
+ return self._tool_hooks
+
+ def get_tool_selection_hooks(self) -> ToolSelectionHooks:
+ """Get tool selection hooks for this logger"""
+ return self._tool_selection_hooks
+
+
+class ConsoleAgentLogger(AgentLogger):
+ """Console implementation of agent logger"""
+
+ def info(self, message: str, **kwargs) -> None:
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+ console.print(f"[timestamp]{timestamp}[/timestamp] [info]INFO[/info]: {message}")
+ if kwargs:
+ console.print(Panel(json.dumps(kwargs, indent=2), title="Additional Info"))
+
+ def warning(self, message: str, **kwargs) -> None:
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+ console.print(f"[timestamp]{timestamp}[/timestamp] [warning]WARNING[/warning]: {message}")
+ if kwargs:
+ console.print(Panel(json.dumps(kwargs, indent=2), title="Additional Info"))
+
+ def error(self, message: str, **kwargs) -> None:
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+ console.print(f"[timestamp]{timestamp}[/timestamp] [error]ERROR[/error]: {message}")
+ if kwargs:
+ console.print(Panel(json.dumps(kwargs, indent=2), title="Additional Info"))
+
+ def debug(self, message: str, **kwargs) -> None:
+ timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+ console.print(f"[timestamp]{timestamp}[/timestamp] [dim]DEBUG[/dim]: {message}")
+ if kwargs:
+ console.print(Panel(json.dumps(kwargs, indent=2), title="Additional Info"))
+
+ def _write_log(self, log_entry: Dict[str, Any]) -> None:
+ pass # Console logger doesn't need to write to file
+
+ def _sanitize_for_json(self, obj: Any) -> Any:
+ if isinstance(obj, (str, int, float, bool, type(None))):
+ return obj
+ elif isinstance(obj, (list, tuple)):
+ return [self._sanitize_for_json(item) for item in obj]
+ elif isinstance(obj, dict):
+ return {str(k): self._sanitize_for_json(v) for k, v in obj.items()}
+ else:
+ return str(obj)
+
+ async def on_agent_planning(self, planning_prompt: str) -> None:
+ self.info(f"Planning: {planning_prompt}")
+
+ def on_agent_start(self, initial_task: str) -> None:
+ self.info(f"Starting task: {initial_task}")
+
+ async def on_agent_done(self, result: str, message_history: List[Dict[str, Any]]) -> None:
+ self.info(f"Task completed: {result}")
diff --git a/examples/agent/startup-simulator-3000/agent_framework/utils/tool_hooks.py b/examples/agent/startup-simulator-3000/agent_framework/utils/tool_hooks.py
new file mode 100644
index 00000000..0e7f0400
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/utils/tool_hooks.py
@@ -0,0 +1,62 @@
+from typing import Any, List, Optional
+from .hooks import ToolContext, ToolHooks, ToolSelectionHooks
+from .logging import AgentLogger
+
+
+class LoggingToolHooks(ToolHooks):
+ """Tool hooks that delegate to a logger"""
+
+ def __init__(self, logger: AgentLogger):
+ self.logger = logger
+
+ async def before_execution(self, context: ToolContext) -> None:
+ self.logger.info(
+ f"Executing tool: {context.tool_name}",
+ inputs=context.inputs,
+ task_id=context.task_id,
+ )
+
+ async def after_execution(self, context: ToolContext, result: Any, error: Optional[Exception] = None) -> None:
+ if error:
+ self.logger.error(
+ f"Tool execution failed: {context.tool_name}",
+ error=str(error),
+ task_id=context.task_id,
+ )
+ else:
+ self.logger.info(
+ f"Tool execution completed: {context.tool_name}",
+ result=result,
+ task_id=context.task_id,
+ )
+
+
+class LoggingToolSelectionHooks(ToolSelectionHooks):
+ """Tool selection hooks that delegate to a logger"""
+
+ def __init__(self, logger: AgentLogger):
+ self.logger = logger
+
+ async def after_selection(
+ self,
+ context: ToolContext,
+ selected_tool: str,
+ confidence: float,
+ reasoning: List[str],
+ ) -> None:
+ self.logger.info(
+ f"Selected tool: {selected_tool}",
+ confidence=confidence,
+ reasoning=reasoning,
+ task_id=context.task_id,
+ )
+
+
+def create_tool_hooks(logger: AgentLogger) -> ToolHooks:
+ """Create tool hooks for a logger"""
+ return LoggingToolHooks(logger)
+
+
+def create_tool_selection_hooks(logger: AgentLogger) -> ToolSelectionHooks:
+ """Create tool selection hooks for a logger"""
+ return LoggingToolSelectionHooks(logger)
diff --git a/examples/agent/startup-simulator-3000/agent_framework/utils/tool_registry.py b/examples/agent/startup-simulator-3000/agent_framework/utils/tool_registry.py
new file mode 100644
index 00000000..e1b15690
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/utils/tool_registry.py
@@ -0,0 +1,86 @@
+from typing import Dict, List, Optional, Type, Any
+from dataclasses import dataclass, field
+from ..models import Tool, ToolMetadata
+from ..tools.base import BaseTool
+
+
+@dataclass
+class ToolRegistry:
+ """Central registry for tool management"""
+
+ tools: Dict[str, Tool] = field(default_factory=dict)
+ _implementations: Dict[str, Type["BaseTool"]] = field(default_factory=dict)
+
+ def register(self, *, metadata: ToolMetadata, implementation: Type["BaseTool"]) -> None:
+ """Register a tool and its implementation"""
+ if metadata.name in self.tools:
+ raise ValueError(f"Tool {metadata.name} is already registered")
+
+ # Convert metadata to Tool model
+ tool = Tool(
+ name=metadata.name,
+ description=metadata.description,
+ tags=metadata.tags,
+ input_schema=metadata.input_schema,
+ output_schema=metadata.output_schema,
+ hooks=None, # Hooks will be set by the agent
+ )
+
+ self.tools[metadata.name] = tool
+ self._implementations[metadata.name] = implementation
+
+ def get_tool(self, name: str) -> Optional[Tool]:
+ """Get tool by name"""
+ return self.tools.get(name)
+
+ def get_implementation(self, name: str) -> Optional[Type["BaseTool"]]:
+ """Get tool implementation by name"""
+ return self._implementations.get(name)
+
+ def list_tools(self) -> List[Tool]:
+ """Get list of all registered tools"""
+ return list(self.tools.values())
+
+ def get_tools_by_tags(self, tags: List[str]) -> List[Tool]:
+ """Get tools that have all specified tags"""
+ return [tool for tool in self.tools.values() if all(tag in tool.tags for tag in tags)]
+
+ def get_all_tools(self) -> Dict[str, Tool]:
+ """Get all registered tools"""
+ return self.tools.copy()
+
+ def get_formatted_tools(self) -> List[Dict[str, Any]]:
+ """Format tools into OpenAI function calling format
+
+ Returns a list of tools formatted as:
+ {
+ "type": "function",
+ "function": {
+ "name": tool.name,
+ "description": tool.description,
+ "parameters": {
+ "type": "object",
+ "properties": tool_schema.properties,
+ "required": tool_schema.required
+ }
+ }
+ }
+ """
+ formatted_tools = []
+ for tool in self.list_tools():
+ tool_schema = tool.input_schema
+ formatted_tools.append(
+ {
+ "type": "function",
+ "function": {
+ "name": tool.name,
+ "description": tool.description,
+ "parameters": {
+ "type": "object",
+ "properties": tool_schema.get("properties", {}),
+ "required": tool_schema.get("required", []),
+ },
+ },
+ }
+ )
+ return formatted_tools
diff --git a/examples/agent/startup-simulator-3000/agent_framework/utils/validation.py b/examples/agent/startup-simulator-3000/agent_framework/utils/validation.py
new file mode 100644
index 00000000..7952e315
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/agent_framework/utils/validation.py
@@ -0,0 +1,29 @@
+from typing import Any
+import json
+from agent_framework.llm.models import LLMMessage
+from datetime import datetime
+
+
+def ensure_valid_io(data: Any) -> str:
+ """Ensure data is in a valid format for Splunk AO Step IO"""
+ if data is None:
+ return "{}"
+ if isinstance(data, str):
+ return data
+ if isinstance(data, datetime):
+ return json.dumps(data.isoformat())
+ if isinstance(data, (dict, list)):
+ # Handle nested structures that might contain datetime objects
+ def format_value(v: Any) -> Any:
+ if isinstance(v, datetime):
+ return v.isoformat()
+ if isinstance(v, dict):
+ return {k: format_value(v) for k, v in v.items()}
+ if isinstance(v, list):
+ return [format_value(x) for x in v]
+ return v
+
+ return json.dumps(format_value(data))
+ if isinstance(data, LLMMessage):
+ return json.dumps({"role": data.role, "content": data.content})
+ return json.dumps({"content": str(data)})
diff --git a/examples/agent/startup-simulator-3000/app.py b/examples/agent/startup-simulator-3000/app.py
new file mode 100644
index 00000000..9b403880
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/app.py
@@ -0,0 +1,188 @@
+#!/usr/bin/env python3
+
+import asyncio
+import json
+import os
+from dotenv import load_dotenv
+from flask import Flask, render_template, request, jsonify
+from flask_cors import CORS
+from agent import SimpleAgent
+from agent_framework.llm.openai_provider import OpenAIProvider
+from agent_framework.llm.models import LLMConfig
+from agent_framework.utils.logging import get_galileo_logger
+
+# Load environment variables
+load_dotenv()
+
+app = Flask(__name__)
+CORS(app)
+
+
+@app.route("/")
+def index():
+ """Serve the main page"""
+ return render_template("index.html")
+
+
+@app.route("/api/generate", methods=["POST"])
+def generate_startup():
+ """API endpoint to generate startup pitch with individual Splunk AO trace"""
+ try:
+ data = request.json
+ industry = data.get("industry", "").strip()
+ audience = data.get("audience", "").strip()
+ random_word = data.get("randomWord", "").strip()
+ mode = data.get("mode", "silly").strip() # Default to silly mode
+
+ # Log API request as JSON
+ api_request = {
+ "endpoint": "/api/generate",
+ "method": "POST",
+ "inputs": {
+ "industry": industry,
+ "audience": audience,
+ "random_word": random_word,
+ "mode": mode,
+ },
+ }
+ print(f"API Request: {json.dumps(api_request, indent=2)}")
+
+ if not industry or not audience or not random_word:
+ return jsonify({"error": "All fields are required"}), 400
+
+ # Get the centralized Splunk AO logger instance
+ logger = get_galileo_logger()
+
+ # Start individual trace for this request if logger is available
+ if logger:
+ logger.start_trace(f"Generate startup pitch - {mode} mode - {industry} targeting {audience}")
+
+ try:
+ # Add LLM span for request processing if logger is available
+ if logger:
+ logger.add_llm_span(
+ input=f"API request received for {mode} mode startup generation",
+ output="Request validated and processing started",
+ model="flask_api",
+ num_input_tokens=len(str(api_request)),
+ num_output_tokens=0,
+ total_tokens=len(str(api_request)),
+ duration_ns=0,
+ )
+
+ # Run the agent asynchronously with proper event loop handling
+ loop = asyncio.new_event_loop()
+ asyncio.set_event_loop(loop)
+ try:
+ agent_result = loop.run_until_complete(run_agent(industry, audience, random_word, mode))
+ finally:
+ loop.close()
+
+ # Parse the structured JSON result from agent
+ try:
+ parsed_result = json.loads(agent_result)
+ final_output = parsed_result.get("final_output", "No output generated")
+ except json.JSONDecodeError:
+ # Fallback if result is not JSON
+ final_output = str(agent_result)
+
+ # Log API response as JSON
+ api_response = {
+ "endpoint": "/api/generate",
+ "status": "success",
+ "result_length": len(final_output),
+ "mode": mode,
+ "agent_result_preview": (str(agent_result)[:200] + "..." if len(str(agent_result)) > 200 else str(agent_result)),
+ }
+ print(f"API Response: {json.dumps(api_response, indent=2)}")
+
+ # Add LLM span for successful completion if logger is available
+ if logger:
+ logger.add_llm_span(
+ input="Agent execution completed successfully",
+ output=final_output,
+ model="flask_api",
+ num_input_tokens=len(str(api_request)),
+ num_output_tokens=len(final_output),
+ total_tokens=len(str(api_request)) + len(final_output),
+ duration_ns=0,
+ )
+
+ # Conclude the trace successfully and flush immediately
+ logger.conclude(output=final_output, duration_ns=0)
+ logger.flush()
+
+ return jsonify({"result": final_output})
+
+ except Exception as e:
+ # Add LLM span for error if logger is available
+ if logger:
+ logger.add_llm_span(
+ input="Agent execution failed",
+ output=str(e),
+ model="flask_api",
+ num_input_tokens=len(str(api_request)),
+ num_output_tokens=len(str(e)),
+ total_tokens=len(str(api_request)) + len(str(e)),
+ duration_ns=0,
+ )
+
+ # Conclude the trace with error and flush immediately
+ logger.conclude(output=str(e), duration_ns=0)
+ logger.flush()
+
+ raise e
+
+ except Exception as e:
+ print(f"Error generating startup: {e}")
+ return jsonify({"error": str(e)}), 500
+
+
+async def run_agent(industry: str, audience: str, random_word: str, mode: str = "silly") -> str:
+ """Run the agent to generate startup pitch"""
+ # Set up LLM provider (this could be updated to use the Splunk AO-wrapped OpenAI client if desired)
+ llm_provider = OpenAIProvider(config=LLMConfig(model="gpt-4", temperature=0.7))
+
+ # Create agent instance with mode
+ agent = SimpleAgent(llm_provider=llm_provider, mode=mode)
+
+ # Create different task descriptions based on mode
+ if mode == "serious":
+ task = (
+ f"First, get recent business news context from NewsAPI to understand current market trends, then "
+ f"generate a professional startup business plan for a {industry} company targeting {audience} "
+ f"that incorporates the concept '{random_word}'. Use the news context to inform market analysis "
+ f"and competitive landscape. Make this extremely professional and corporate."
+ )
+ else: # silly mode
+ task = (
+ f"First, get some inspiration from recent HackerNews stories, then "
+ f"generate a startup pitch for a {industry} company targeting {audience} "
+ f"that includes the word '{random_word}'. Make the pitch creative and "
+ f"incorporate relevant trends from the HackerNews stories."
+ )
+
+ # Run the agent with individual parameters (Splunk AO logging handled by individual traces)
+ result = await agent.run(task, industry=industry, audience=audience, random_word=random_word)
+ return result
+
+
+if __name__ == "__main__":
+ # Verify Splunk AO configuration
+ project_id = os.environ.get("SPLUNK_AO_PROJECT")
+ log_stream = os.environ.get("SPLUNK_AO_LOG_STREAM")
+ api_key = os.environ.get("SPLUNK_AO_API_KEY")
+
+ print("🔍 Splunk AO Configuration:")
+ print(f" Project: {project_id}")
+ print(f" Log Stream: {log_stream}")
+ print(f" API Key: {'✅ Set' if api_key else '❌ Not Set'}")
+
+ if not os.environ.get("OPENAI_API_KEY"):
+ print("Error: OPENAI_API_KEY not set. Please set this environment variable.")
+ exit(1)
+
+ if not api_key:
+ print("Warning: SPLUNK_AO_API_KEY not set. Splunk AO logging will be disabled.")
+
+ app.run(debug=True, host="0.0.0.0", port=2021)
diff --git a/examples/agent/startup-simulator-3000/demo.py b/examples/agent/startup-simulator-3000/demo.py
new file mode 100644
index 00000000..30de2f94
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/demo.py
@@ -0,0 +1,206 @@
+#!/usr/bin/env python3
+"""
+Demo script for Startup Simulator 3000
+This script demonstrates how to use the application programmatically
+"""
+
+import asyncio
+import json
+import os
+from dotenv import load_dotenv
+from agent import SimpleAgent
+from agent_framework.llm.openai_provider import OpenAIProvider
+from agent_framework.llm.models import LLMConfig
+
+# Load environment variables
+load_dotenv()
+
+
+async def demo_silly_mode():
+ """Demonstrate silly mode startup generation"""
+ print("🎭 DEMO: Silly Mode Startup Generation")
+ print("=" * 50)
+
+ # Set up the agent
+ llm_provider = OpenAIProvider(config=LLMConfig(model="gpt-4", temperature=0.7))
+ agent = SimpleAgent(llm_provider=llm_provider, mode="silly")
+
+ # Test parameters
+ industry = "fintech"
+ audience = "millennials"
+ random_word = "blockchain"
+
+ print(f"Industry: {industry}")
+ print(f"Audience: {audience}")
+ print(f"Random Word: {random_word}")
+ print("Mode: Silly")
+ print()
+
+ # Create task
+ task = (
+ f"Generate a startup pitch for a {industry} company targeting {audience} "
+ f"that includes the word '{random_word}'. Make the pitch creative and "
+ f"incorporate relevant trends from HackerNews stories."
+ )
+
+ try:
+ # Run the agent
+ result = await agent.run(task, industry=industry, audience=audience, random_word=random_word)
+
+ # Parse and display result
+ try:
+ parsed_result = json.loads(result)
+ final_output = parsed_result.get("final_output", result)
+ except json.JSONDecodeError:
+ final_output = result
+
+ print("🎉 Generated Startup Pitch:")
+ print("-" * 30)
+ print(final_output)
+ print("-" * 30)
+
+ except Exception as e:
+ print(f"❌ Error: {e}")
+
+
+async def demo_serious_mode():
+ """Demonstrate serious mode startup generation"""
+ print("\n💼 DEMO: Serious Mode Startup Generation")
+ print("=" * 50)
+
+ # Set up the agent
+ llm_provider = OpenAIProvider(config=LLMConfig(model="gpt-4", temperature=0.7))
+ agent = SimpleAgent(llm_provider=llm_provider, mode="serious")
+
+ # Test parameters
+ industry = "healthcare"
+ audience = "small businesses"
+ random_word = "AI"
+
+ print(f"Industry: {industry}")
+ print(f"Audience: {audience}")
+ print(f"Random Word: {random_word}")
+ print("Mode: Serious")
+ print()
+
+ # Create task
+ task = (
+ f"Generate a professional startup business plan for a {industry} company "
+ f"targeting {audience} that incorporates the concept '{random_word}'. "
+ f"Use current business news for market analysis and make this extremely professional."
+ )
+
+ try:
+ # Run the agent
+ result = await agent.run(task, industry=industry, audience=audience, random_word=random_word)
+
+ # Parse and display result
+ try:
+ parsed_result = json.loads(result)
+ final_output = parsed_result.get("final_output", result)
+ except json.JSONDecodeError:
+ final_output = result
+
+ print("🎉 Generated Business Plan:")
+ print("-" * 30)
+ print(final_output)
+ print("-" * 30)
+
+ except Exception as e:
+ print(f"❌ Error: {e}")
+
+
+async def demo_individual_tools():
+ """Demonstrate individual tool usage"""
+ print("\n🔧 DEMO: Individual Tool Usage")
+ print("=" * 50)
+
+ # Test startup simulator tool directly
+ from tools.startup_simulator import StartupSimulatorTool
+
+ print("Testing Startup Simulator Tool:")
+ print("-" * 30)
+
+ try:
+ tool = StartupSimulatorTool()
+ result = await tool.execute(industry="education", audience="students", random_word="gamification")
+
+ # Parse result
+ parsed_result = json.loads(result)
+ pitch = parsed_result.get("pitch", "No pitch generated")
+
+ print(f"Generated Pitch: {pitch}")
+ print(f"Character Count: {parsed_result.get('character_count', 0)}")
+ print(f"Timestamp: {parsed_result.get('timestamp', 'N/A')}")
+
+ except Exception as e:
+ print(f"❌ Error: {e}")
+
+
+def check_environment():
+ """Check if environment is properly configured"""
+ print("🔍 Environment Check")
+ print("=" * 50)
+
+ # Check required environment variables
+ required_vars = ["OPENAI_API_KEY"]
+ optional_vars = ["NEWS_API_KEY", "SPLUNK_AO_API_KEY", "SPLUNK_AO_PROJECT"]
+
+ print("Required Variables:")
+ for var in required_vars:
+ value = os.getenv(var)
+ if value and not value.startswith("your-"):
+ print(f" ✅ {var}: Configured")
+ else:
+ print(f" ❌ {var}: Not configured")
+
+ print("\nOptional Variables:")
+ for var in optional_vars:
+ value = os.getenv(var)
+ if value and not value.startswith("your"):
+ print(f" ✅ {var}: Configured")
+ else:
+ print(f" ⚠️ {var}: Not configured (optional)")
+
+ print()
+
+
+async def main():
+ """Run all demos"""
+ print("🚀 Startup Simulator 3000 - Demo Script")
+ print("=" * 60)
+ print("This script demonstrates the capabilities of the application")
+ print("Make sure you have configured your API keys in .env file")
+ print()
+
+ # Check environment
+ check_environment()
+
+ # Check if OpenAI API key is available
+ if not os.getenv("OPENAI_API_KEY") or os.getenv("OPENAI_API_KEY").startswith("your-"):
+ print("❌ OPENAI_API_KEY not configured. Please edit .env file with your API key.")
+ print("Get your API key at: https://platform.openai.com/api-keys")
+ return
+
+ # Run demos
+ try:
+ await demo_silly_mode()
+ await demo_serious_mode()
+ await demo_individual_tools()
+
+ print("\n🎉 Demo completed successfully!")
+ print("\n💡 Next steps:")
+ print(" 1. Run 'python app.py' to start the web interface")
+ print(" 2. Open http://localhost:2021 in your browser")
+ print(" 3. Try generating your own startup pitches!")
+
+ except Exception as e:
+ print(f"\n❌ Demo failed with error: {e}")
+ print("\n💡 Troubleshooting:")
+ print(" 1. Check your API keys in .env file")
+ print(" 2. Run 'python test_setup.py' to verify setup")
+ print(" 3. Make sure all dependencies are installed")
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/examples/agent/startup-simulator-3000/requirements.txt b/examples/agent/startup-simulator-3000/requirements.txt
new file mode 100644
index 00000000..5a7c2cbf
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/requirements.txt
@@ -0,0 +1,57 @@
+annotated-types==0.7.0
+anyio==4.9.0
+aiohttp==3.9.3
+attrs==25.3.0
+certifi==2025.4.26
+charset-normalizer==3.4.2
+distro==1.9.0
+galileo==1.5.1
+galileo-core
+h11==0.16.0
+httpcore==1.0.9
+httpx==0.28.1
+idna==3.10
+jinja2==3.1.6
+jiter==0.10.0
+jsonpatch==1.33
+jsonpointer==3.0.0
+langchain==0.3.25
+langchain-core==0.3.63
+langchain-openai==0.3.19
+langchain-text-splitters==0.3.8
+langgraph==0.4.8
+langgraph-checkpoint==2.0.26
+langgraph-prebuilt==0.2.2
+langgraph-sdk==0.1.70
+langsmith==0.3.44
+markupsafe==3.0.2
+openai==1.84.0
+orjson==3.10.18
+ormsgpack==1.10.0
+packaging==24.2
+pydantic
+pydantic-core
+pydantic-settings
+pyjwt==2.10.1
+python-dateutil==2.9.0.post0
+python-dotenv==1.1.0
+pyyaml==6.0.2
+regex==2024.11.6
+requests==2.32.3
+requests-toolbelt==1.0.0
+six==1.17.0
+sniffio==1.3.1
+sqlalchemy==2.0.41
+tenacity==9.1.2
+tiktoken==0.9.0
+tqdm==4.67.1
+typing-extensions==4.14.0
+typing-inspection==0.4.1
+urllib3==2.4.0
+wrapt==1.17.2
+xxhash==3.5.0
+zstandard==0.23.0
+rich
+flask
+flask-cors
+aiohttp
\ No newline at end of file
diff --git a/examples/agent/startup-simulator-3000/run_startup_sim.py b/examples/agent/startup-simulator-3000/run_startup_sim.py
new file mode 100644
index 00000000..2c340650
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/run_startup_sim.py
@@ -0,0 +1,44 @@
+import asyncio
+from agent import SimpleAgent
+from agent_framework.llm.openai_provider import OpenAIProvider
+from agent_framework.llm.models import LLMConfig
+from splunk_ao import splunk_ao_context
+import os
+from dotenv import load_dotenv
+
+# Load environment variables
+load_dotenv()
+
+
+async def main():
+ # Ensure Splunk AO environment variables are set
+ if not os.getenv("SPLUNK_AO_API_KEY"):
+ print("Warning: SPLUNK_AO_API_KEY not set. Splunk AO logging will be disabled.")
+
+ # Prompt user for input
+ industry = input("Enter an industry: ")
+ audience = input("Enter a target audience: ")
+ random_word = input("Enter a random word: ")
+
+ # Set up LLM provider
+ llm_provider = OpenAIProvider(config=LLMConfig(model="gpt-4", temperature=0.7))
+
+ # Create agent instance
+ agent = SimpleAgent(llm_provider=llm_provider)
+
+ # Create the task description that includes getting HackerNews context
+ task = (
+ f"First, get some inspiration from recent HackerNews stories, then "
+ f"generate a startup pitch for a {industry} company targeting {audience} "
+ f"that includes the word '{random_word}'. Make the pitch creative and "
+ f"incorporate relevant trends from the HackerNews stories."
+ )
+
+ # Run the agent within Splunk AO context for proper trace management
+ with splunk_ao_context():
+ result = await agent.run(task)
+ print(result)
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/examples/agent/startup-simulator-3000/start.bat b/examples/agent/startup-simulator-3000/start.bat
new file mode 100644
index 00000000..c6648b19
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/start.bat
@@ -0,0 +1,64 @@
+@echo off
+REM Startup Simulator 3000 - Quick Start Script for Windows
+REM This script helps you get the application running quickly on Windows
+
+echo 🚀 Startup Simulator 3000 - Quick Start
+echo ========================================
+
+REM Check if Python is installed
+python --version >nul 2>&1
+if errorlevel 1 (
+ echo ❌ Python is not installed or not in PATH. Please install Python 3.8+ first.
+ pause
+ exit /b 1
+)
+
+echo ✅ Python detected
+
+REM Check if virtual environment exists
+if not exist "venv" (
+ echo 📦 Creating virtual environment...
+ python -m venv venv
+)
+
+REM Activate virtual environment
+echo 🔧 Activating virtual environment...
+call venv\Scripts\activate.bat
+
+REM Install dependencies
+echo 📥 Installing dependencies...
+pip install -r requirements.txt
+
+REM Check if .env file exists
+if not exist ".env" (
+ echo ⚠️ No .env file found!
+ echo 📝 Creating .env file from template...
+ copy .env.example .env
+ echo 🔑 Please edit .env file with your API keys:
+ echo - OPENAI_API_KEY (required)
+ echo - NEWS_API_KEY (for serious mode)
+ echo - SPLUNK_AO_API_KEY (optional, for observability)
+ echo.
+ echo You can edit it with: notepad .env
+ echo.
+ pause
+)
+
+REM Check if OpenAI API key is set
+findstr /C:"OPENAI_API_KEY=sk-" .env >nul 2>&1
+if errorlevel 1 (
+ echo ❌ OPENAI_API_KEY not properly configured in .env file
+ echo Please edit .env and add your OpenAI API key
+ pause
+ exit /b 1
+)
+
+echo ✅ Environment configured
+
+REM Start the application
+echo 🌐 Starting Startup Simulator 3000...
+echo 📱 Open your browser to: http://localhost:2021
+echo 🛑 Press Ctrl+C to stop the server
+echo.
+
+python app.py
\ No newline at end of file
diff --git a/examples/agent/startup-simulator-3000/start.sh b/examples/agent/startup-simulator-3000/start.sh
new file mode 100755
index 00000000..9bf18d28
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/start.sh
@@ -0,0 +1,70 @@
+#!/bin/bash
+
+# Startup Simulator 3000 - Quick Start Script
+# This script helps you get the application running quickly
+
+echo "🚀 Startup Simulator 3000 - Quick Start"
+echo "========================================"
+
+# Check if Python is installed
+if ! command -v python3 &> /dev/null; then
+ echo "❌ Python 3 is not installed. Please install Python 3.8+ first."
+ exit 1
+fi
+
+# Check Python version
+python_version=$(python3 -c 'import sys; print(".".join(map(str, sys.version_info[:2])))')
+required_version="3.8"
+
+if [ "$(printf '%s\n' "$required_version" "$python_version" | sort -V | head -n1)" != "$required_version" ]; then
+ echo "❌ Python version $python_version is too old. Please install Python 3.8+"
+ exit 1
+fi
+
+echo "✅ Python $python_version detected"
+
+# Check if virtual environment exists
+if [ ! -d "venv" ]; then
+ echo "📦 Creating virtual environment..."
+ python3 -m venv venv
+fi
+
+# Activate virtual environment
+echo "🔧 Activating virtual environment..."
+source venv/bin/activate
+
+# Install dependencies
+echo "📥 Installing dependencies..."
+pip install -r requirements.txt
+
+# Check if .env file exists
+if [ ! -f ".env" ]; then
+ echo "⚠️ No .env file found!"
+ echo "📝 Creating .env file from template..."
+ cp .env.example .env
+ echo "🔑 Please edit .env file with your API keys:"
+ echo " - OPENAI_API_KEY (required)"
+ echo " - NEWS_API_KEY (for serious mode)"
+ echo " - SPLUNK_AO_API_KEY (optional, for observability)"
+ echo ""
+ echo "You can edit it with: nano .env"
+ echo ""
+ read -p "Press Enter after you've configured your API keys..."
+fi
+
+# Check if OpenAI API key is set
+if ! grep -q "OPENAI_API_KEY=sk-" .env 2>/dev/null; then
+ echo "❌ OPENAI_API_KEY not properly configured in .env file"
+ echo "Please edit .env and add your OpenAI API key"
+ exit 1
+fi
+
+echo "✅ Environment configured"
+
+# Start the application
+echo "🌐 Starting Startup Simulator 3000..."
+echo "📱 Open your browser to: http://localhost:2021"
+echo "🛑 Press Ctrl+C to stop the server"
+echo ""
+
+python app.py
\ No newline at end of file
diff --git a/examples/agent/startup-simulator-3000/static/css/style.css b/examples/agent/startup-simulator-3000/static/css/style.css
new file mode 100644
index 00000000..25711f40
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/static/css/style.css
@@ -0,0 +1,637 @@
+/* 8-bit Game Styling with Theme Support */
+:root {
+ --blue: #3498db;
+ --red: #e74c3c;
+ --orange: #f39c12;
+ --orange-red: #e67e22;
+ --green: #2ecc71;
+ --gray: #95a5a6;
+
+ /* Dark theme (default) */
+ --bg-primary: #1a1a2e;
+ --bg-secondary: #2c3e50;
+ --text-primary: #ecf0f1;
+ --text-secondary: #95a5a6;
+ --surface: #2c3e50;
+ --surface-hover: #34495e;
+ --border: #4a5568;
+ --shadow: rgba(0, 0, 0, 0.5);
+}
+
+/* Light theme */
+[data-theme="light"] {
+ --bg-primary: #f8f9fa;
+ --bg-secondary: #e9ecef;
+ --text-primary: #1a202c;
+ --text-secondary: #4a5568;
+ --surface: #ffffff;
+ --surface-hover: #f7fafc;
+ --border: #e2e8f0;
+ --shadow: rgba(0, 0, 0, 0.15);
+}
+
+/* Light theme specific adjustments */
+[data-theme="light"] .title h1 {
+ text-shadow:
+ 2px 2px 0px var(--bg-secondary),
+ 4px 4px 0px var(--shadow);
+}
+
+[data-theme="light"] .splunk-ao-logo img {
+ filter: brightness(0.8) contrast(1.2);
+}
+
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ font-family: 'Press Start 2P', monospace;
+ background: var(--bg-primary);
+ color: var(--text-primary);
+ overflow: hidden;
+ height: 100vh;
+ user-select: none;
+ transition: background-color 0.3s ease, color 0.3s ease;
+}
+
+.game-container {
+ width: 100vw;
+ height: 100vh;
+ position: relative;
+ background: linear-gradient(135deg, var(--bg-primary) 0%, var(--bg-secondary) 100%);
+ transition: background 0.3s ease;
+}
+
+.screen {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ display: none;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ padding: 2rem;
+ text-align: center;
+}
+
+.screen.active {
+ display: flex;
+}
+
+/* Theme Toggle */
+.theme-toggle {
+ position: absolute;
+ top: 2rem;
+ left: 2rem;
+ z-index: 1000;
+}
+
+.theme-btn {
+ background: var(--surface);
+ border: 2px solid var(--border);
+ border-radius: 50px;
+ width: 60px;
+ height: 60px;
+ cursor: pointer;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 1.5rem;
+ transition: all 0.3s ease;
+ box-shadow: 0 4px 8px var(--shadow);
+}
+
+.theme-btn:hover {
+ background: var(--surface-hover);
+ transform: translateY(-2px);
+ box-shadow: 0 6px 12px var(--shadow);
+}
+
+.theme-btn:focus {
+ outline: 3px solid var(--blue);
+ outline-offset: 2px;
+}
+
+.theme-btn:active {
+ transform: translateY(0px) scale(0.95);
+ box-shadow: 0 2px 4px var(--shadow);
+}
+
+/* Splunk AO Logo */
+.splunk-ao-logo {
+ position: absolute;
+ top: 2rem;
+ right: 2rem;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ opacity: 0.8;
+}
+
+.splunk-ao-logo img {
+ height: 40px;
+ width: auto;
+ filter: brightness(1.2);
+}
+
+.powered-by {
+ font-size: 0.5rem;
+ color: var(--text-secondary);
+ margin-top: 0.5rem;
+ letter-spacing: 1px;
+}
+
+/* Start Screen */
+.title h1 {
+ font-size: clamp(2rem, 8vw, 4rem);
+ color: var(--blue);
+ text-shadow:
+ 2px 2px 0px var(--bg-secondary),
+ 4px 4px 0px var(--shadow);
+ margin-bottom: 1rem;
+}
+
+.subtitle {
+ font-size: clamp(0.5rem, 2vw, 1rem);
+ color: var(--orange);
+ margin-bottom: 3rem;
+}
+
+.menu {
+ margin-bottom: 3rem;
+}
+
+.menu-item {
+ font-size: clamp(0.8rem, 2.5vw, 1.2rem);
+ color: var(--text-primary);
+ margin: 1rem 0;
+ cursor: pointer;
+ transition: all 0.3s ease;
+}
+
+.menu-item.active,
+.menu-item:hover {
+ color: var(--green);
+ text-shadow: 0 0 10px var(--green);
+ transform: scale(1.1);
+}
+
+.footer {
+ position: absolute;
+ bottom: 2rem;
+ font-size: clamp(0.6rem, 1.5vw, 0.8rem);
+ color: var(--orange);
+}
+
+.blink {
+ animation: blink 1s infinite;
+}
+
+@keyframes blink {
+ 0%, 50% { opacity: 1; }
+ 51%, 100% { opacity: 0; }
+}
+
+/* Mode Selection Screen */
+.mode-container {
+ max-width: 800px;
+ width: 100%;
+}
+
+.mode-container h2 {
+ font-size: clamp(1.5rem, 4vw, 2.5rem);
+ color: var(--blue);
+ margin-bottom: 3rem;
+ text-align: center;
+}
+
+.mode-options {
+ display: flex;
+ gap: 3rem;
+ justify-content: center;
+ flex-wrap: wrap;
+}
+
+.mode-option {
+ background: var(--surface);
+ border: 2px solid var(--border);
+ border-radius: 15px;
+ padding: 2rem;
+ min-width: 280px;
+ text-align: center;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ box-shadow: 0 8px 20px var(--shadow);
+}
+
+.mode-option:hover {
+ border-color: var(--blue);
+ background: var(--surface-hover);
+ transform: translateY(-5px) scale(1.02);
+ box-shadow:
+ 0 15px 30px var(--shadow),
+ 0 0 30px rgba(52, 152, 219, 0.3);
+}
+
+.mode-option.selected {
+ border-color: var(--green);
+ background: var(--surface-hover);
+ box-shadow:
+ 0 15px 30px var(--shadow),
+ 0 0 30px rgba(46, 204, 113, 0.4);
+}
+
+.mode-icon {
+ font-size: 3rem;
+ margin-bottom: 1rem;
+ filter: grayscale(1);
+ transition: filter 0.3s ease;
+}
+
+.mode-option:hover .mode-icon,
+.mode-option.selected .mode-icon {
+ filter: grayscale(0);
+}
+
+.mode-title {
+ font-size: clamp(1rem, 2.5vw, 1.3rem);
+ color: var(--text-primary);
+ margin-bottom: 1rem;
+ font-weight: bold;
+}
+
+.mode-desc {
+ font-size: clamp(0.7rem, 1.5vw, 0.9rem);
+ color: var(--text-secondary);
+ line-height: 1.4;
+}
+
+/* Input Screen */
+.header {
+ position: absolute;
+ top: 2rem;
+ left: 2rem;
+ right: 2rem;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex-wrap: wrap;
+}
+
+.header h2 {
+ font-size: clamp(1rem, 3vw, 1.5rem);
+ color: var(--blue);
+}
+
+.stats {
+ display: flex;
+ gap: 2rem;
+ font-size: clamp(0.6rem, 1.5vw, 0.8rem);
+ color: var(--orange);
+}
+
+.form-container {
+ max-width: 600px;
+ width: 100%;
+}
+
+.input-group {
+ margin: 2rem 0;
+ text-align: left;
+ position: relative;
+}
+
+.input-group label {
+ display: block;
+ font-size: clamp(0.8rem, 2vw, 1rem);
+ color: var(--green);
+ margin-bottom: 0.5rem;
+ text-shadow: 0 0 10px var(--green);
+}
+
+.input-group input {
+ width: 100%;
+ padding: 1rem;
+ font-family: 'Press Start 2P', monospace;
+ font-size: clamp(0.6rem, 1.5vw, 0.8rem);
+ background: var(--surface);
+ border: 2px solid var(--green);
+ color: var(--text-primary);
+ outline: none;
+ box-shadow:
+ inset 0 0 10px rgba(46, 204, 113, 0.2),
+ 0 0 20px rgba(46, 204, 113, 0.3);
+ transition: all 0.3s ease;
+}
+
+.input-group input:focus {
+ border-color: var(--blue);
+ box-shadow:
+ inset 0 0 10px rgba(52, 152, 219, 0.3),
+ 0 0 30px rgba(52, 152, 219, 0.5);
+ color: var(--blue);
+}
+
+.input-group input::placeholder {
+ color: var(--text-secondary);
+}
+
+.controls {
+ margin-top: 3rem;
+ text-align: center;
+}
+
+.control-hint {
+ font-size: clamp(0.5rem, 1.2vw, 0.6rem);
+ color: var(--text-secondary);
+ margin-bottom: 1rem;
+}
+
+.pixel-button {
+ font-family: 'Press Start 2P', monospace;
+ font-size: clamp(0.7rem, 1.8vw, 1rem);
+ padding: 1rem 2rem;
+ background: linear-gradient(45deg, var(--green), #2ecc71);
+ border: 2px solid var(--green);
+ color: var(--navy);
+ cursor: pointer;
+ text-transform: uppercase;
+ box-shadow:
+ 0 4px 0 #27ae60,
+ 0 6px 0 #229954,
+ 0 8px 20px rgba(0, 0, 0, 0.5);
+ transition: all 0.2s ease;
+ margin: 0.5rem;
+ min-width: 200px;
+}
+
+.pixel-button:hover {
+ transform: translateY(-2px);
+ box-shadow:
+ 0 6px 0 #27ae60,
+ 0 8px 0 #229954,
+ 0 12px 25px rgba(0, 0, 0, 0.7);
+}
+
+.pixel-button:active {
+ transform: translateY(2px);
+ box-shadow:
+ 0 2px 0 #27ae60,
+ 0 4px 0 #229954,
+ 0 6px 15px rgba(0, 0, 0, 0.3);
+}
+
+.pixel-button.secondary {
+ background: linear-gradient(45deg, var(--orange), #f39c12);
+ border-color: var(--orange);
+ color: var(--navy);
+ box-shadow:
+ 0 4px 0 #e67e22,
+ 0 6px 0 #d68910,
+ 0 8px 20px rgba(0, 0, 0, 0.5);
+}
+
+.pixel-button.secondary:hover {
+ box-shadow:
+ 0 6px 0 #e67e22,
+ 0 8px 0 #d68910,
+ 0 12px 25px rgba(0, 0, 0, 0.7);
+}
+
+/* Loading Screen */
+.loading-container {
+ max-width: 600px;
+ width: 100%;
+}
+
+.loading-container h2 {
+ font-size: clamp(1.2rem, 3vw, 2rem);
+ color: var(--orange);
+ margin-bottom: 2rem;
+ animation: pulse 1s infinite;
+}
+
+@keyframes pulse {
+ 0%, 100% { transform: scale(1); }
+ 50% { transform: scale(1.05); }
+}
+
+.loading-bar {
+ width: 100%;
+ height: 20px;
+ background: var(--surface);
+ border: 2px solid var(--green);
+ margin: 2rem 0;
+ position: relative;
+ overflow: hidden;
+}
+
+.loading-progress {
+ height: 100%;
+ background: linear-gradient(90deg, var(--green), var(--blue), var(--green));
+ width: 0%;
+ animation: loadingProgress 3s ease-in-out infinite;
+}
+
+@keyframes loadingProgress {
+ 0% { width: 0%; }
+ 100% { width: 100%; }
+}
+
+.loading-text {
+ text-align: left;
+ margin: 2rem 0;
+}
+
+.loading-step {
+ font-size: clamp(0.7rem, 1.8vw, 1rem);
+ color: var(--text-secondary);
+ margin: 0.5rem 0;
+ transition: color 0.5s ease;
+}
+
+.loading-step.active {
+ color: var(--green);
+ animation: typewriter 2s ease-in-out;
+}
+
+@keyframes typewriter {
+ 0% { width: 0; }
+ 100% { width: 100%; }
+}
+
+.spinner {
+ display: flex;
+ justify-content: center;
+ margin-top: 2rem;
+}
+
+.pixel-spinner {
+ width: 40px;
+ height: 40px;
+ border: 4px solid var(--text-secondary);
+ border-top: 4px solid var(--green);
+ border-radius: 50%;
+ animation: spin 1s linear infinite;
+}
+
+@keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
+
+/* Result Screen */
+.result-container {
+ max-width: 800px;
+ width: 100%;
+}
+
+.result-container h2 {
+ font-size: clamp(1.5rem, 4vw, 2.5rem);
+ color: var(--blue);
+ margin-bottom: 2rem;
+ animation: celebration 2s ease-in-out;
+}
+
+@keyframes celebration {
+ 0%, 100% { transform: scale(1) rotate(0deg); }
+ 25% { transform: scale(1.1) rotate(-2deg); }
+ 75% { transform: scale(1.1) rotate(2deg); }
+}
+
+.result-content {
+ background: var(--surface);
+ border: 2px solid var(--green);
+ padding: 2rem;
+ margin: 2rem 0;
+ border-radius: 10px;
+ box-shadow:
+ inset 0 0 20px rgba(46, 204, 113, 0.2),
+ 0 0 30px rgba(46, 204, 113, 0.3);
+ max-height: 60vh;
+ overflow-y: auto;
+ overflow-x: hidden;
+}
+
+.result-text {
+ font-family: 'Segoe UI', 'Arial', sans-serif;
+ font-size: clamp(0.9rem, 2vw, 1.1rem);
+ color: var(--text-primary);
+ line-height: 1.6;
+ text-align: left;
+ white-space: pre-wrap;
+ font-weight: 400;
+ letter-spacing: 0.3px;
+ word-wrap: break-word;
+ overflow-wrap: break-word;
+ max-width: 100%;
+ display: block;
+}
+
+.result-actions {
+ display: flex;
+ justify-content: center;
+ gap: 1rem;
+ flex-wrap: wrap;
+}
+
+/* Error Screen */
+.error-container {
+ max-width: 600px;
+ width: 100%;
+}
+
+.error-container h2 {
+ font-size: clamp(1.5rem, 4vw, 2.5rem);
+ color: var(--red);
+ margin-bottom: 2rem;
+ animation: shake 0.5s ease-in-out infinite;
+}
+
+@keyframes shake {
+ 0%, 100% { transform: translateX(0); }
+ 25% { transform: translateX(-5px); }
+ 75% { transform: translateX(5px); }
+}
+
+.error-message {
+ font-size: clamp(0.8rem, 2vw, 1rem);
+ color: var(--text-primary);
+ margin-bottom: 2rem;
+ padding: 1rem;
+ background: rgba(231, 76, 60, 0.2);
+ border: 1px solid var(--red);
+ border-radius: 5px;
+}
+
+/* Responsive Design */
+@media (max-width: 768px) {
+ .game-container {
+ padding: 1rem;
+ }
+
+ .header {
+ position: relative;
+ top: 0;
+ left: 0;
+ right: 0;
+ margin-bottom: 2rem;
+ text-align: center;
+ }
+
+ .stats {
+ justify-content: center;
+ margin-top: 1rem;
+ }
+
+ .result-content {
+ max-height: 50vh;
+ padding: 1.5rem;
+ }
+
+ .result-text {
+ font-size: clamp(0.8rem, 1.8vw, 1rem);
+ line-height: 1.5;
+ }
+
+ .result-actions {
+ flex-direction: column;
+ align-items: center;
+ }
+
+ .pixel-button {
+ min-width: 250px;
+ }
+
+ .mode-options {
+ flex-direction: column;
+ gap: 2rem;
+ }
+
+ .mode-option {
+ min-width: 250px;
+ }
+}
+
+/* Custom Scrollbar */
+::-webkit-scrollbar {
+ width: 12px;
+}
+
+::-webkit-scrollbar-track {
+ background: var(--bg-secondary);
+}
+
+::-webkit-scrollbar-thumb {
+ background: var(--green);
+ border-radius: 6px;
+}
+
+::-webkit-scrollbar-thumb:hover {
+ background: var(--blue);
+}
diff --git a/examples/agent/startup-simulator-3000/static/images/05-25-Galileo-Logo-Primary-Horizontal-Light.png b/examples/agent/startup-simulator-3000/static/images/05-25-Galileo-Logo-Primary-Horizontal-Light.png
new file mode 100644
index 00000000..f796edd0
Binary files /dev/null and b/examples/agent/startup-simulator-3000/static/images/05-25-Galileo-Logo-Primary-Horizontal-Light.png differ
diff --git a/examples/agent/startup-simulator-3000/static/js/app.js b/examples/agent/startup-simulator-3000/static/js/app.js
new file mode 100644
index 00000000..a21d8fa5
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/static/js/app.js
@@ -0,0 +1,478 @@
+// Startum Sim 3000 - 8-bit Frontend
+class StartumSim {
+ constructor() {
+ this.currentScreen = 'start-screen';
+ this.selectedMode = null;
+ this.inputs = {
+ industry: '',
+ audience: '',
+ randomWord: ''
+ };
+ this.loadingSteps = {
+ silly: [
+ '► Fetching HackerNews trends...',
+ '► Analyzing startup ecosystem...',
+ '► Generating silly pitch...',
+ '► Finalizing absurd results...'
+ ],
+ serious: [
+ '► Fetching market news...',
+ '► Analyzing competitive landscape...',
+ '► Generating business plan...',
+ '► Finalizing professional pitch...'
+ ]
+ };
+
+ this.init();
+ }
+
+ init() {
+ this.bindEvents();
+ this.initTheme();
+ this.playStartupSound();
+ }
+
+ bindEvents() {
+ // Start button
+ document.getElementById('start-button').addEventListener('click', () => {
+ this.showScreen('mode-screen');
+ this.playSound('beep');
+ });
+
+ // Mode selection
+ document.getElementById('silly-mode').addEventListener('click', () => {
+ this.selectMode('silly');
+ });
+
+ document.getElementById('serious-mode').addEventListener('click', () => {
+ this.selectMode('serious');
+ });
+
+ // Generate button
+ document.getElementById('generate-btn').addEventListener('click', () => {
+ this.handleGenerate();
+ });
+
+ // New game button
+ document.getElementById('new-game-btn').addEventListener('click', () => {
+ this.resetGame();
+ });
+
+ // Copy button
+ document.getElementById('copy-btn').addEventListener('click', () => {
+ this.copyResult();
+ });
+
+ // Retry button
+ document.getElementById('retry-btn').addEventListener('click', () => {
+ this.showScreen('input-screen');
+ });
+
+ // Theme toggle button
+ document.getElementById('theme-toggle-btn').addEventListener('click', () => {
+ this.toggleTheme();
+ });
+
+ // Keyboard navigation
+ document.addEventListener('keydown', (e) => {
+ this.handleKeypress(e);
+ });
+
+ // Input validation
+ const inputs = ['industry', 'audience', 'randomWord'];
+ inputs.forEach(inputId => {
+ const input = document.getElementById(inputId);
+ input.addEventListener('input', (e) => {
+ this.inputs[inputId] = e.target.value.trim();
+ this.updateGenerateButton();
+ this.playSound('type');
+ });
+
+ input.addEventListener('focus', () => {
+ this.playSound('focus');
+ });
+ });
+ }
+
+ handleKeypress(e) {
+ switch(e.key) {
+ case 'Enter':
+ if (this.currentScreen === 'start-screen') {
+ this.showScreen('mode-screen');
+ this.playSound('beep');
+ } else if (this.currentScreen === 'input-screen') {
+ this.handleGenerate();
+ }
+ break;
+ case 'Escape':
+ if (this.currentScreen !== 'start-screen') {
+ this.resetGame();
+ }
+ break;
+ case 't':
+ case 'T':
+ // Toggle theme with 't' key
+ if (e.ctrlKey || e.metaKey) {
+ e.preventDefault();
+ this.toggleTheme();
+ }
+ break;
+ }
+ }
+
+ selectMode(mode) {
+ this.selectedMode = mode;
+
+ // Update visual selection
+ document.querySelectorAll('.mode-option').forEach(option => {
+ option.classList.remove('selected');
+ });
+ document.getElementById(`${mode}-mode`).classList.add('selected');
+
+ // Update the generator title and mode status
+ const title = mode === 'serious' ? 'PROFESSIONAL STARTUP GENERATOR v3.0' : 'SILLY STARTUP GENERATOR v3.0';
+ document.getElementById('generator-title').textContent = title;
+
+ // Update mode status
+ const modeStatus = mode === 'serious' ? 'MODE: PROFESSIONAL' : 'MODE: SILLY';
+ document.querySelector('.stats span').textContent = modeStatus;
+
+ // Go to input screen after a brief delay
+ setTimeout(() => {
+ this.showScreen('input-screen');
+ this.playSound('beep');
+ }, 500);
+ }
+
+ showScreen(screenId) {
+ // Hide all screens
+ document.querySelectorAll('.screen').forEach(screen => {
+ screen.classList.remove('active');
+ });
+
+ // Show target screen
+ document.getElementById(screenId).classList.add('active');
+ this.currentScreen = screenId;
+
+ // Focus first input if on input screen
+ if (screenId === 'input-screen') {
+ setTimeout(() => {
+ document.getElementById('industry').focus();
+ }, 100);
+ }
+ }
+
+ updateGenerateButton() {
+ const btn = document.getElementById('generate-btn');
+ const allFilled = this.inputs.industry && this.inputs.audience && this.inputs.randomWord;
+
+ btn.disabled = !allFilled;
+ btn.style.opacity = allFilled ? '1' : '0.5';
+ }
+
+ async handleGenerate() {
+ if (!this.inputs.industry || !this.inputs.audience || !this.inputs.randomWord) {
+ this.showError('Please fill in all fields!');
+ return;
+ }
+
+ this.showScreen('loading-screen');
+ this.playSound('power-up');
+ this.startLoadingAnimation();
+
+ try {
+ const requestData = {
+ ...this.inputs,
+ mode: this.selectedMode || 'silly'
+ };
+
+ const response = await fetch('/api/generate', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify(requestData)
+ });
+
+ const data = await response.json();
+
+ if (!response.ok) {
+ throw new Error(data.error || 'Unknown error occurred');
+ }
+
+ // Ensure loading animation runs for at least 3 seconds
+ await this.waitForLoadingComplete();
+
+ this.showResult(data.result);
+ this.playSound('success');
+
+ } catch (error) {
+ console.error('Error:', error);
+ this.showError(error.message || 'Something went wrong. Please try again.');
+ this.playSound('error');
+ }
+ }
+
+ startLoadingAnimation() {
+ const progressBar = document.querySelector('.loading-progress');
+ const steps = document.querySelectorAll('.loading-step');
+
+ // Update loading steps based on mode
+ const currentSteps = this.loadingSteps[this.selectedMode || 'silly'];
+ steps.forEach((step, index) => {
+ if (currentSteps[index]) {
+ step.textContent = currentSteps[index];
+ }
+ });
+
+ // Reset animation
+ progressBar.style.width = '0%';
+ steps.forEach(step => step.classList.remove('active'));
+
+ let currentStep = 0;
+ const stepDuration = 750; // 3 seconds / 4 steps
+
+ const animateStep = () => {
+ if (currentStep < steps.length) {
+ // Deactivate previous step
+ if (currentStep > 0) {
+ steps[currentStep - 1].classList.remove('active');
+ }
+
+ // Activate current step
+ steps[currentStep].classList.add('active');
+ currentStep++;
+
+ setTimeout(animateStep, stepDuration);
+ }
+ };
+
+ animateStep();
+
+ // Animate progress bar
+ setTimeout(() => {
+ progressBar.style.transition = 'width 3s ease-in-out';
+ progressBar.style.width = '100%';
+ }, 100);
+ }
+
+ waitForLoadingComplete() {
+ return new Promise(resolve => {
+ setTimeout(resolve, 3000); // Minimum 3 seconds loading
+ });
+ }
+
+ showResult(result) {
+ document.getElementById('result-text').textContent = result;
+ this.showScreen('result-screen');
+ }
+
+ showError(message) {
+ document.getElementById('error-message').textContent = message;
+ this.showScreen('error-screen');
+ }
+
+ async copyResult() {
+ try {
+ const resultText = document.getElementById('result-text').textContent;
+ await navigator.clipboard.writeText(resultText);
+
+ // Show feedback
+ const btn = document.getElementById('copy-btn');
+ const originalText = btn.textContent;
+ btn.textContent = 'COPIED!';
+ btn.style.background = 'linear-gradient(45deg, #00aa00, #00ff00)';
+
+ setTimeout(() => {
+ btn.textContent = originalText;
+ btn.style.background = 'linear-gradient(45deg, #666666, #999999)';
+ }, 2000);
+
+ this.playSound('beep');
+ } catch (error) {
+ console.error('Failed to copy text:', error);
+ this.playSound('error');
+ }
+ }
+
+ resetGame() {
+ this.inputs = {
+ industry: '',
+ audience: '',
+ randomWord: ''
+ };
+ this.selectedMode = null;
+
+ // Clear inputs
+ document.getElementById('industry').value = '';
+ document.getElementById('audience').value = '';
+ document.getElementById('randomWord').value = '';
+
+ // Clear mode selection
+ document.querySelectorAll('.mode-option').forEach(option => {
+ option.classList.remove('selected');
+ });
+
+ // Reset mode status
+ document.querySelector('.stats span').textContent = 'MODE: READY';
+
+ this.updateGenerateButton();
+ this.showScreen('mode-screen');
+ this.playSound('beep');
+ }
+
+ // Sound effects using Web Audio API
+ playSound(type) {
+ if (!this.audioContext) {
+ try {
+ this.audioContext = new (window.AudioContext || window.webkitAudioContext)();
+ } catch (e) {
+ return; // Audio not supported
+ }
+ }
+
+ const oscillator = this.audioContext.createOscillator();
+ const gainNode = this.audioContext.createGain();
+
+ oscillator.connect(gainNode);
+ gainNode.connect(this.audioContext.destination);
+
+ // Different sound patterns for different actions
+ switch(type) {
+ case 'beep':
+ oscillator.frequency.setValueAtTime(800, this.audioContext.currentTime);
+ oscillator.frequency.exponentialRampToValueAtTime(400, this.audioContext.currentTime + 0.1);
+ gainNode.gain.setValueAtTime(0.1, this.audioContext.currentTime);
+ gainNode.gain.exponentialRampToValueAtTime(0.01, this.audioContext.currentTime + 0.1);
+ oscillator.start();
+ oscillator.stop(this.audioContext.currentTime + 0.1);
+ break;
+
+ case 'type':
+ oscillator.frequency.setValueAtTime(600, this.audioContext.currentTime);
+ gainNode.gain.setValueAtTime(0.05, this.audioContext.currentTime);
+ gainNode.gain.exponentialRampToValueAtTime(0.01, this.audioContext.currentTime + 0.05);
+ oscillator.start();
+ oscillator.stop(this.audioContext.currentTime + 0.05);
+ break;
+
+ case 'focus':
+ oscillator.frequency.setValueAtTime(1000, this.audioContext.currentTime);
+ oscillator.frequency.exponentialRampToValueAtTime(1200, this.audioContext.currentTime + 0.05);
+ gainNode.gain.setValueAtTime(0.08, this.audioContext.currentTime);
+ gainNode.gain.exponentialRampToValueAtTime(0.01, this.audioContext.currentTime + 0.05);
+ oscillator.start();
+ oscillator.stop(this.audioContext.currentTime + 0.05);
+ break;
+
+ case 'power-up':
+ oscillator.frequency.setValueAtTime(200, this.audioContext.currentTime);
+ oscillator.frequency.exponentialRampToValueAtTime(800, this.audioContext.currentTime + 0.3);
+ gainNode.gain.setValueAtTime(0.1, this.audioContext.currentTime);
+ gainNode.gain.exponentialRampToValueAtTime(0.01, this.audioContext.currentTime + 0.3);
+ oscillator.start();
+ oscillator.stop(this.audioContext.currentTime + 0.3);
+ break;
+
+ case 'success':
+ // Play a success melody
+ this.playSuccessMelody();
+ return;
+
+ case 'error':
+ oscillator.frequency.setValueAtTime(150, this.audioContext.currentTime);
+ oscillator.frequency.exponentialRampToValueAtTime(100, this.audioContext.currentTime + 0.3);
+ gainNode.gain.setValueAtTime(0.1, this.audioContext.currentTime);
+ gainNode.gain.exponentialRampToValueAtTime(0.01, this.audioContext.currentTime + 0.3);
+ oscillator.start();
+ oscillator.stop(this.audioContext.currentTime + 0.3);
+ break;
+ }
+ }
+
+ playSuccessMelody() {
+ const notes = [440, 554, 659, 880]; // A4, C#5, E5, A5
+ const duration = 0.15;
+
+ notes.forEach((freq, index) => {
+ setTimeout(() => {
+ const osc = this.audioContext.createOscillator();
+ const gain = this.audioContext.createGain();
+
+ osc.connect(gain);
+ gain.connect(this.audioContext.destination);
+
+ osc.frequency.setValueAtTime(freq, this.audioContext.currentTime);
+ gain.gain.setValueAtTime(0.1, this.audioContext.currentTime);
+ gain.gain.exponentialRampToValueAtTime(0.01, this.audioContext.currentTime + duration);
+
+ osc.start();
+ osc.stop(this.audioContext.currentTime + duration);
+ }, index * duration * 1000);
+ });
+ }
+
+ playStartupSound() {
+ // Play startup sound after a brief delay
+ setTimeout(() => {
+ this.playSound('power-up');
+ }, 500);
+ }
+
+ initTheme() {
+ // Get saved theme or default to dark
+ const savedTheme = localStorage.getItem('startup-sim-theme') || 'dark';
+ this.setTheme(savedTheme);
+ }
+
+ toggleTheme() {
+ const currentTheme = document.documentElement.getAttribute('data-theme') || 'dark';
+ const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
+ this.setTheme(newTheme);
+ this.playSound('beep');
+ }
+
+ setTheme(theme) {
+ // Update document attribute
+ if (theme === 'light') {
+ document.documentElement.setAttribute('data-theme', 'light');
+ } else {
+ document.documentElement.removeAttribute('data-theme');
+ }
+
+ // Update theme toggle button icon
+ const themeIcon = document.querySelector('.theme-icon');
+ if (themeIcon) {
+ themeIcon.textContent = theme === 'dark' ? '🌙' : '☀️';
+ }
+
+ // Save preference
+ localStorage.setItem('startup-sim-theme', theme);
+
+ console.log(`Theme switched to: ${theme}`);
+ }
+}
+
+// Initialize the game when page loads
+document.addEventListener('DOMContentLoaded', () => {
+ new StartumSim();
+});
+
+// Add some fun easter eggs
+let konamiCode = [];
+const konamiSequence = ['ArrowUp', 'ArrowUp', 'ArrowDown', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'ArrowLeft', 'ArrowRight', 'KeyB', 'KeyA'];
+
+document.addEventListener('keydown', (e) => {
+ konamiCode.push(e.code);
+ if (konamiCode.length > konamiSequence.length) {
+ konamiCode.shift();
+ }
+
+ if (konamiCode.join(',') === konamiSequence.join(',')) {
+ // Easter egg activated!
+ document.body.style.filter = 'hue-rotate(180deg)';
+ setTimeout(() => {
+ document.body.style.filter = '';
+ }, 3000);
+ }
+});
diff --git a/examples/agent/startup-simulator-3000/templates/credits.html b/examples/agent/startup-simulator-3000/templates/credits.html
new file mode 100644
index 00000000..2d62ab0e
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/templates/credits.html
@@ -0,0 +1,30 @@
+
+
+
+
+
+ Credits - Startup Sim 3000
+
+
+
+
+
+
+
+
Credits + Contributors
+
The magic behind the scenes
+
This project was originally built for the Databricks Data + AI Summit 2025 by Erin Mikail Staples.
+
+
Tools Used
+
+ Splunk AO : For providing the observability infrastructure.
+ DataBricks Data + AI Summit : For giving me a chance to present my work.
+ OpenAI : For the GPT-4 language model capabilities.
+ NewsAPI : For real-time business news data.
+ HackerNews : For startup ecosystem insights.
+
+
+
Back to Home
+
+
+
\ No newline at end of file
diff --git a/examples/agent/startup-simulator-3000/templates/index.html b/examples/agent/startup-simulator-3000/templates/index.html
new file mode 100644
index 00000000..eb0a8f52
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/templates/index.html
@@ -0,0 +1,144 @@
+
+
+
+
+
+ Startup Sim 3000 🚀
+
+
+
+
+
+
+
+
+
+
+ 🌙
+
+
+
+
+
+
+
+
POWERED BY
+
+
+
STARTUP SIM 3000
+
The Ultimate Startup Pitch Generator
+
+
+
+
+
+
+
+
+
SELECT MODE
+
+
+
🎭
+
SILLY MODE
+
Generate absurd and fun startup ideas
+
+
+
💼
+
SERIOUS MODE
+
Generate professional business concepts
+
+
+
+
+
+
+
+
+
+
+
+
GENERATING STARTUP...
+
+
+
► Fetching HackerNews trends...
+
► Analyzing market data...
+
► Generating pitch...
+
► Finalizing results...
+
+
+
+
+
+
+
+
+
STARTUP GENERATED!
+
+
+ NEW STARTUP
+ COPY TEXT
+
+
+
+
+
+
+
+
ERROR!
+
+ Something went wrong...
+
+
TRY AGAIN
+
+
+
+
+
+
+
diff --git a/examples/agent/startup-simulator-3000/templates/instructions.html b/examples/agent/startup-simulator-3000/templates/instructions.html
new file mode 100644
index 00000000..df123228
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/templates/instructions.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+ Instructions - Startum Sim 3000
+
+
+
+
+
+
+
+
Instructions
+
What is Startup Sim 3000?
+
Startup Sim 3000 is an AI-powered startup pitch generator that creates either silly, creative pitches or professional business proposals. It is built with an agentic framework powered by OpenAI and monitored with Splunk AO observability.
+
+
How the Agent Works
+
The agent uses a multi-tool architecture to generate startup pitches. It dynamically selects tools based on the execution mode (silly or serious) and fetches context from external APIs to enhance the pitch generation process.
+
+
Tools Used
+
+ HackerNews Tool : Fetches trending stories from HackerNews to inspire silly pitches.
+ NewsAPI Tool : Retrieves recent news articles to provide market analysis for serious pitches.
+ Startup Simulator : Generates creative and absurd startup pitches.
+ Serious Startup Simulator : Creates professional business proposals with market analysis.
+
+
+
APIs Used
+
+ OpenAI API : Powers the language model for generating pitches.
+ NewsAPI : Provides real-time business news data for market analysis.
+ HackerNews API : Offers insights into the startup ecosystem.
+ Splunk AO : Monitors and logs the execution of the agent and tools.
+
+
+
Back to Home
+
+
+
\ No newline at end of file
diff --git a/examples/agent/startup-simulator-3000/test_setup.py b/examples/agent/startup-simulator-3000/test_setup.py
new file mode 100644
index 00000000..a37e8510
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/test_setup.py
@@ -0,0 +1,207 @@
+#!/usr/bin/env python3
+"""
+Test script to verify Startup Simulator 3000 setup
+Run this script to check if everything is configured correctly
+"""
+
+import os
+import sys
+import importlib
+from dotenv import load_dotenv
+
+
+def test_python_version():
+ """Test if Python version is compatible"""
+ print("🐍 Testing Python version...")
+ version = sys.version_info
+ if version.major < 3 or (version.major == 3 and version.minor < 8):
+ print(f"❌ Python {version.major}.{version.minor} is too old. Need Python 3.8+")
+ return False
+ print(f"✅ Python {version.major}.{version.minor}.{version.micro} is compatible")
+ return True
+
+
+def test_dependencies():
+ """Test if all required dependencies are installed"""
+ print("\n📦 Testing dependencies...")
+ required_packages = [
+ "flask",
+ "openai",
+ "galileo",
+ "requests",
+ "python-dotenv",
+ "aiohttp",
+ "langchain",
+ ]
+
+ missing_packages = []
+ for package in required_packages:
+ try:
+ importlib.import_module(package)
+ print(f"✅ {package}")
+ except ImportError:
+ print(f"❌ {package} - not installed")
+ missing_packages.append(package)
+
+ if missing_packages:
+ print(f"\n⚠️ Missing packages: {', '.join(missing_packages)}")
+ print("Run: pip install -r requirements.txt")
+ return False
+
+ print("✅ All dependencies installed")
+ return True
+
+
+def test_environment():
+ """Test environment configuration"""
+ print("\n🔧 Testing environment configuration...")
+
+ # Load .env file
+ load_dotenv()
+
+ # Check required environment variables
+ required_vars = ["OPENAI_API_KEY"]
+ optional_vars = ["NEWS_API_KEY", "SPLUNK_AO_API_KEY", "SPLUNK_AO_PROJECT"]
+
+ missing_required = []
+ for var in required_vars:
+ value = os.getenv(var)
+ if not value or value == f"your-{var.lower().replace('_', '-')}-here":
+ print(f"❌ {var} - not set or using placeholder")
+ missing_required.append(var)
+ else:
+ print(f"✅ {var} - configured")
+
+ if missing_required:
+ print(f"\n⚠️ Missing required environment variables: {', '.join(missing_required)}")
+ print("Please edit .env file with your API keys")
+ return False
+
+ # Check optional variables
+ for var in optional_vars:
+ value = os.getenv(var)
+ if value and value != f"your {var.lower().replace('_', ' ')} here":
+ print(f"✅ {var} - configured")
+ else:
+ print(f"⚠️ {var} - not set (optional)")
+
+ return True
+
+
+def test_imports():
+ """Test if all project modules can be imported"""
+ print("\n📚 Testing project imports...")
+
+ try:
+ from agent_framework.llm.openai_provider import OpenAIProvider
+
+ _ = OpenAIProvider
+ print("✅ agent_framework.llm.openai_provider")
+ except ImportError as e:
+ print(f"❌ agent_framework.llm.openai_provider - {e}")
+ return False
+
+ try:
+ from tools.startup_simulator import StartupSimulatorTool
+
+ _ = StartupSimulatorTool
+ print("✅ tools.startup_simulator")
+ except ImportError as e:
+ print(f"❌ tools.startup_simulator - {e}")
+ return False
+
+ try:
+ from agent import SimpleAgent
+
+ _ = SimpleAgent
+ print("✅ agent")
+ except ImportError as e:
+ print(f"❌ agent - {e}")
+ return False
+
+ try:
+ from splunk_ao import SplunkAOLogger
+
+ _ = SplunkAOLogger
+ print("✅ splunk_ao")
+ except ImportError as e:
+ print(f"❌ splunk_ao - {e}")
+ return False
+
+ return True
+
+
+def test_files():
+ """Test if all required files exist"""
+ print("\n📁 Testing file structure...")
+
+ required_files = [
+ "app.py",
+ "agent.py",
+ "requirements.txt",
+ ".env.example",
+ "tools.json",
+ "templates/index.html",
+ "static/css/style.css",
+ "static/js/app.js",
+ ]
+
+ missing_files = []
+ for file_path in required_files:
+ if os.path.exists(file_path):
+ print(f"✅ {file_path}")
+ else:
+ print(f"❌ {file_path} - missing")
+ missing_files.append(file_path)
+
+ if missing_files:
+ print(f"\n⚠️ Missing files: {', '.join(missing_files)}")
+ return False
+
+ return True
+
+
+def main():
+ """Run all tests"""
+ print("🚀 Startup Simulator 3000 - Setup Test")
+ print("=" * 50)
+
+ tests = [
+ test_python_version,
+ test_dependencies,
+ test_environment,
+ test_imports,
+ test_files,
+ ]
+
+ passed = 0
+ total = len(tests)
+
+ for test in tests:
+ try:
+ if test():
+ passed += 1
+ except Exception as e:
+ print(f"❌ Test failed with error: {e}")
+
+ print("\n" + "=" * 50)
+ print(f"📊 Test Results: {passed}/{total} tests passed")
+
+ if passed == total:
+ print("🎉 All tests passed! Your setup is ready.")
+ print("\n🚀 To start the application:")
+ print(" python app.py")
+ print(" Then open: http://localhost:2021")
+ else:
+ print("⚠️ Some tests failed. Please fix the issues above.")
+ print("\n💡 Common solutions:")
+ print(" 1. Install dependencies: pip install -r requirements.txt")
+ print(" 2. Configure API keys in .env file")
+ print(" 3. Make sure you're in the virtual environment")
+
+ return passed == total
+
+
+if __name__ == "__main__":
+ success = main()
+ sys.exit(0 if success else 1)
diff --git a/examples/agent/startup-simulator-3000/tools.json b/examples/agent/startup-simulator-3000/tools.json
new file mode 100644
index 00000000..1b6dfe4c
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/tools.json
@@ -0,0 +1,145 @@
+[
+ {
+ "type": "function",
+ "function": {
+ "name": "startup_simulator",
+ "description": "Generates a creative and silly startup pitch based on industry, audience, and a random word. Uses HackerNews context for inspiration.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "industry": {
+ "type": "string",
+ "description": "The industry for the startup (e.g., 'tech', 'healthcare', 'food')"
+ },
+ "audience": {
+ "type": "string",
+ "description": "The target audience for the startup (e.g., 'millennials', 'small businesses', 'parents')"
+ },
+ "random_word": {
+ "type": "string",
+ "description": "A random word that must be included naturally in the pitch"
+ },
+ "hn_context": {
+ "type": "string",
+ "description": "Recent HackerNews stories for creative inspiration (optional)"
+ }
+ },
+ "required": ["industry", "audience", "random_word"]
+ }
+ }
+ },
+ {
+ "type": "function",
+ "function": {
+ "name": "serious_startup_simulator",
+ "description": "Generates a professional, business-focused startup plan based on industry, audience, and market trends. Uses business news for market analysis.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "industry": {
+ "type": "string",
+ "description": "The industry for the startup (e.g., 'fintech', 'healthcare', 'e-commerce')"
+ },
+ "audience": {
+ "type": "string",
+ "description": "The target audience for the startup (e.g., 'enterprise', 'SMBs', 'consumers')"
+ },
+ "random_word": {
+ "type": "string",
+ "description": "A concept or word to incorporate naturally into the business plan"
+ },
+ "news_context": {
+ "type": "string",
+ "description": "Recent business news for market analysis and trends (optional)"
+ }
+ },
+ "required": ["industry", "audience", "random_word"]
+ }
+ }
+ },
+ {
+ "type": "function",
+ "function": {
+ "name": "hackernews_tool",
+ "description": "Fetches trending stories from HackerNews for creative inspiration and context.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "limit": {
+ "type": "integer",
+ "description": "Number of stories to fetch (default: 3)",
+ "default": 3
+ }
+ },
+ "required": []
+ }
+ }
+ },
+ {
+ "type": "function",
+ "function": {
+ "name": "news_api_tool",
+ "description": "Fetches business news articles for market analysis and professional context.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "category": {
+ "type": "string",
+ "description": "News category to fetch (e.g., 'business', 'technology')",
+ "default": "business"
+ },
+ "limit": {
+ "type": "integer",
+ "description": "Number of articles to fetch (default: 5)",
+ "default": 5
+ }
+ },
+ "required": []
+ }
+ }
+ },
+ {
+ "type": "function",
+ "function": {
+ "name": "text_analyzer",
+ "description": "Analyzes text content for sentiment, key themes, and insights.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "text": {
+ "type": "string",
+ "description": "The text content to analyze"
+ },
+ "analysis_type": {
+ "type": "string",
+ "description": "Type of analysis to perform (sentiment, themes, summary)",
+ "default": "sentiment"
+ }
+ },
+ "required": ["text"]
+ }
+ }
+ },
+ {
+ "type": "function",
+ "function": {
+ "name": "keyword_extractor",
+ "description": "Extracts key terms and phrases from text content.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "text": {
+ "type": "string",
+ "description": "The text content to extract keywords from"
+ },
+ "max_keywords": {
+ "type": "integer",
+ "description": "Maximum number of keywords to extract",
+ "default": 10
+ }
+ },
+ "required": ["text"]
+ }
+ }
+ }
+]
\ No newline at end of file
diff --git a/examples/agent/startup-simulator-3000/tools/__init__.py b/examples/agent/startup-simulator-3000/tools/__init__.py
new file mode 100644
index 00000000..02ec6709
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/tools/__init__.py
@@ -0,0 +1,7 @@
+"""Tools used by the simple agent"""
+
+from .text_analysis import TextAnalyzerTool
+from .keyword_extraction import KeywordExtractorTool
+from .hackernews_tool import HackerNewsTool
+
+__all__ = ["TextAnalyzerTool", "KeywordExtractorTool", "HackerNewsTool"]
diff --git a/examples/agent/startup-simulator-3000/tools/hackernews_tool.py b/examples/agent/startup-simulator-3000/tools/hackernews_tool.py
new file mode 100644
index 00000000..9d4a6286
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/tools/hackernews_tool.py
@@ -0,0 +1,232 @@
+import json
+import aiohttp
+from splunk_ao import log # 🔍 Splunk AO decorator import for tool spans
+from agent_framework.tools.base import BaseTool
+from agent_framework.models import ToolMetadata
+from agent_framework.utils.logging import (
+ get_galileo_logger,
+) # 🔍 Splunk AO helper import - gets centralized logger
+from dotenv import load_dotenv
+from datetime import datetime
+
+# Load environment variables
+load_dotenv()
+
+
+class HackerNewsTool(BaseTool):
+ """Tool for fetching trending stories from HackerNews"""
+
+ def __init__(self):
+ super().__init__()
+ self.name = "hackernews_tool"
+ self.description = "Fetch trending stories from HackerNews for creative inspiration"
+ # 👀 GALILEO INITIALIZATION: Get the centralized Splunk AO logger instance
+ # This ensures all tools use the same Splunk AO configuration and connection
+ self.galileo_logger = get_galileo_logger()
+
+ @classmethod
+ def get_metadata(cls) -> ToolMetadata:
+ return ToolMetadata(
+ name="hackernews_tool",
+ description="Fetches trending stories from HackerNews for creative inspiration and context",
+ tags=["news", "inspiration", "tech", "trending"],
+ input_schema={
+ "type": "object",
+ "properties": {
+ "limit": {
+ "type": "integer",
+ "description": "Number of stories to fetch",
+ "default": 3,
+ }
+ },
+ "required": [],
+ },
+ output_schema={
+ "type": "string",
+ "description": "JSON string containing HackerNews stories with metadata",
+ },
+ )
+
+ # 👀 GALILEO TOOL SPAN DECORATOR: This decorator creates a tool span for HTTP API calls
+ # Since this tool makes HTTP requests to HackerNews API (not LLM calls), we use span_type="tool"
+ # The name "Tool-HackerNews" will appear in your Splunk AO dashboard as a tool span
+ @log(span_type="tool", name="Tool-HackerNews")
+ async def execute(self, limit: int = 3) -> str:
+ """Fetch trending stories from HackerNews"""
+
+ # Log inputs
+ inputs = {"limit": limit, "timestamp": datetime.now().isoformat()}
+ print(f"HackerNews Tool Inputs: {json.dumps(inputs, indent=2)}")
+
+ # 👀 GALILEO LOGGER SETUP: Get the Splunk AO logger for this execution
+ # This logger will be used to create traces and spans for observability
+ logger = self.galileo_logger
+ if not logger:
+ print("⚠️ Warning: Splunk AO logger not available, proceeding without logging")
+ # ℹ️ FALLBACK: If Splunk AO is not available, use the non-logging version
+ return await self._execute_without_galileo(limit)
+
+ # 👀 GALILEO TRACE START: Create a new trace for this tool execution
+ # A trace represents the entire lifecycle of this tool call
+ # This will appear as a top-level trace in your Splunk AO dashboard
+ logger.start_trace(f"HackerNews Tool - Fetching {limit} stories")
+
+ try:
+ # 🔧 TOOL EXECUTION: This tool makes HTTP API calls to HackerNews
+ # Since it's not an LLM call, we don't need LLM spans here
+ # The @log decorator above automatically creates the tool span
+
+ # Fetch top story IDs
+ async with aiohttp.ClientSession() as session:
+ async with session.get("https://hacker-news.firebaseio.com/v0/topstories.json") as response:
+ if response.status != 200:
+ raise Exception(f"Failed to fetch top stories: {response.status}")
+
+ story_ids = await response.json()
+ story_ids = story_ids[:limit] # Get only the requested number
+
+ # Fetch individual story details
+ stories = []
+ for story_id in story_ids:
+ async with session.get(f"https://hacker-news.firebaseio.com/v0/item/{story_id}.json") as story_response:
+ if story_response.status == 200:
+ story_data = await story_response.json()
+ if story_data and "title" in story_data:
+ stories.append(
+ {
+ "id": story_data.get("id"),
+ "title": story_data.get("title"),
+ "url": story_data.get("url"),
+ "score": story_data.get("score", 0),
+ "by": story_data.get("by"),
+ "time": story_data.get("time"),
+ }
+ )
+
+ # Format stories for context
+ formatted_stories = []
+ for story in stories:
+ formatted_stories.append(f"• {story['title']} (Score: {story['score']})")
+
+ context = "\n".join(formatted_stories)
+
+ # Create structured output
+ output = {
+ "stories": stories,
+ "formatted_context": context,
+ "story_count": len(stories),
+ "requested_limit": limit,
+ "timestamp": datetime.now().isoformat(),
+ "source": "hackernews",
+ }
+
+ # Log output as JSON
+ output_log = {
+ "tool_execution": "hackernews_tool",
+ "inputs": inputs,
+ "output": output,
+ "metadata": {
+ "story_count": output["story_count"],
+ "requested_limit": output["requested_limit"],
+ "timestamp": output["timestamp"],
+ },
+ }
+ print(f"HackerNews Tool Output: {json.dumps(output_log, indent=2)}")
+
+ # 👀 GALILEO TRACE CONCLUSION: Successfully conclude the trace
+ # This marks the trace as completed successfully in Splunk AO
+ # The trace will show as "success" in your dashboard
+ logger.conclude(output=context, duration_ns=0)
+ logger.flush()
+
+ # Return JSON string for proper Splunk AO logging display
+ galileo_output = {
+ "tool_result": "hackernews_tool",
+ "formatted_output": json.dumps(output, indent=2),
+ "context": context,
+ "metadata": output,
+ }
+
+ return json.dumps(galileo_output, indent=2)
+
+ except Exception as e:
+ # 👀 GALILEO ERROR HANDLING: Conclude the trace with error status
+ # This marks the trace as failed in Splunk AO and includes the error message
+ # The trace will show as "error" in your dashboard with error details
+ if logger:
+ logger.conclude(output=str(e), duration_ns=0, error=True)
+ logger.flush()
+
+ raise e
+
+ async def _execute_without_galileo(self, limit: int = 3) -> str:
+ """Fallback execution without Splunk AO logging"""
+ # ℹ️ FALLBACK METHOD: This method runs when Splunk AO is not available
+ # It performs the same functionality but without any observability logging
+ # Fetch top story IDs
+ async with aiohttp.ClientSession() as session:
+ async with session.get("https://hacker-news.firebaseio.com/v0/topstories.json") as response:
+ if response.status != 200:
+ raise Exception(f"Failed to fetch top stories: {response.status}")
+
+ story_ids = await response.json()
+ story_ids = story_ids[:limit] # Get only the requested number
+
+ # Fetch individual story details
+ stories = []
+ for story_id in story_ids:
+ async with session.get(f"https://hacker-news.firebaseio.com/v0/item/{story_id}.json") as story_response:
+ if story_response.status == 200:
+ story_data = await story_response.json()
+ if story_data and "title" in story_data:
+ stories.append(
+ {
+ "id": story_data.get("id"),
+ "title": story_data.get("title"),
+ "url": story_data.get("url"),
+ "score": story_data.get("score", 0),
+ "by": story_data.get("by"),
+ "time": story_data.get("time"),
+ }
+ )
+
+ # Format stories for context
+ formatted_stories = []
+ for story in stories:
+ formatted_stories.append(f"• {story['title']} (Score: {story['score']})")
+
+ context = "\n".join(formatted_stories)
+
+ # Create structured output
+ output = {
+ "stories": stories,
+ "formatted_context": context,
+ "story_count": len(stories),
+ "requested_limit": limit,
+ "timestamp": datetime.now().isoformat(),
+ "source": "hackernews",
+ }
+
+ # Return JSON string for proper Splunk AO logging display
+ galileo_output = {
+ "tool_result": "hackernews_tool",
+ "formatted_output": json.dumps(output, indent=2),
+ "context": context,
+ "metadata": output,
+ }
+
+ return json.dumps(galileo_output, indent=2)
+
+
+# ℹ️ TEST FUNCTION: This function can be used to test the tool independently
+async def main():
+ """Test the HackerNews tool"""
+ tool = HackerNewsTool()
+ result = await tool.execute(limit=3)
+ print(f"Result: {result}")
+
+
+if __name__ == "__main__":
+ import asyncio
+
+ asyncio.run(main())
diff --git a/examples/agent/startup-simulator-3000/tools/keyword_extraction.py b/examples/agent/startup-simulator-3000/tools/keyword_extraction.py
new file mode 100644
index 00000000..5d4bb6ea
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/tools/keyword_extraction.py
@@ -0,0 +1,59 @@
+from typing import Dict, Any
+from agent_framework.tools.base import BaseTool
+from agent_framework.models import ToolMetadata
+
+
+class KeywordExtractorTool(BaseTool):
+ """Tool for extracting keywords from text"""
+
+ @classmethod
+ def get_metadata(cls) -> ToolMetadata:
+ """Get tool metadata"""
+ return ToolMetadata(
+ name="keyword_extractor",
+ description="Extracts important keywords and phrases from text",
+ tags=["text", "keywords", "extraction"],
+ input_schema={
+ "type": "object",
+ "properties": {
+ "text": {
+ "type": "string",
+ "description": "Text to extract keywords from",
+ }
+ },
+ "required": ["text"],
+ },
+ output_schema={
+ "type": "object",
+ "properties": {
+ "keywords": {"type": "array", "items": {"type": "string"}},
+ "importance_scores": {
+ "type": "object",
+ "additionalProperties": {"type": "number"},
+ },
+ },
+ },
+ )
+
+ async def execute(self, text: str) -> Dict[str, Any]:
+ """Extract keywords from text"""
+ # Simple implementation - in real world would use NLP
+ words = text.lower().split()
+ word_freq = {}
+
+ # Count word frequencies
+ for word in words:
+ if len(word) > 3: # Only consider words longer than 3 chars
+ word_freq[word] = word_freq.get(word, 0) + 1
+
+ # Get top keywords by frequency
+ keywords = sorted(word_freq.items(), key=lambda x: x[1], reverse=True)[:5]
+
+ # Calculate importance scores (normalized frequencies)
+ max_freq = max(freq for _, freq in keywords) if keywords else 1
+ importance_scores = {word: freq / max_freq for word, freq in keywords}
+
+ return {
+ "keywords": [word for word, _ in keywords],
+ "importance_scores": importance_scores,
+ }
diff --git a/examples/agent/startup-simulator-3000/tools/news_api_tool.py b/examples/agent/startup-simulator-3000/tools/news_api_tool.py
new file mode 100644
index 00000000..9e493b44
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/tools/news_api_tool.py
@@ -0,0 +1,249 @@
+import os
+import json
+import aiohttp
+from splunk_ao import log # 🔍 Splunk AO decorator import for tool spans
+from agent_framework.tools.base import BaseTool
+from agent_framework.models import ToolMetadata
+from agent_framework.utils.logging import (
+ get_galileo_logger,
+) # 🔍 Splunk AO helper import - gets centralized logger
+from dotenv import load_dotenv
+from datetime import datetime
+
+# Load environment variables
+load_dotenv()
+
+
+class NewsAPITool(BaseTool):
+ """Tool for fetching business news from NewsAPI"""
+
+ def __init__(self):
+ super().__init__()
+ self.name = "news_api_tool"
+ self.description = "Fetch business news from NewsAPI for market analysis"
+ # 👀 GALILEO INITIALIZATION: Get the centralized Splunk AO logger instance
+ # This ensures all tools use the same Splunk AO configuration and connection
+ self.galileo_logger = get_galileo_logger()
+
+ @classmethod
+ def get_metadata(cls) -> ToolMetadata:
+ return ToolMetadata(
+ name="news_api_tool",
+ description="Fetches business news from NewsAPI for market analysis and professional context",
+ tags=["news", "business", "market", "analysis"],
+ input_schema={
+ "type": "object",
+ "properties": {
+ "category": {
+ "type": "string",
+ "description": "News category to fetch",
+ "default": "business",
+ },
+ "limit": {
+ "type": "integer",
+ "description": "Number of articles to fetch",
+ "default": 5,
+ },
+ },
+ "required": [],
+ },
+ output_schema={
+ "type": "string",
+ "description": "JSON string containing news articles with metadata",
+ },
+ )
+
+ # 👀 GALILEO TOOL SPAN DECORATOR: This decorator creates a tool span for HTTP API calls
+ # Since this tool makes HTTP requests to NewsAPI (not LLM calls), we use span_type="tool"
+ # The name "Tool-NewsAPI" will appear in your Splunk AO dashboard as a tool span
+ @log(span_type="tool", name="Tool-NewsAPI")
+ async def execute(self, category: str = "business", limit: int = 5) -> str:
+ """Fetch business news from NewsAPI"""
+
+ # Log inputs
+ inputs = {
+ "category": category,
+ "limit": limit,
+ "timestamp": datetime.now().isoformat(),
+ }
+ print(f"News API Tool Inputs: {json.dumps(inputs, indent=2)}")
+
+ # 👀 GALILEO LOGGER SETUP: Get the Splunk AO logger for this execution
+ # This logger will be used to create traces and spans for observability
+ logger = self.galileo_logger
+ if not logger:
+ print("⚠️ Warning: Splunk AO logger not available, proceeding without logging")
+ # ℹ️ FALLBACK: If Splunk AO is not available, use the non-logging version
+ return await self._execute_without_galileo(category, limit)
+
+ # 👀 GALILEO TRACE START: Create a new trace for this tool execution
+ # A trace represents the entire lifecycle of this tool call
+ # This will appear as a top-level trace in your Splunk AO dashboard
+ logger.start_trace(f"News API Tool - Fetching {category} news")
+
+ try:
+ # 🔧 TOOL EXECUTION: This tool makes HTTP API calls to NewsAPI
+ # Since it's not an LLM call, we don't need LLM spans here
+ # The @log decorator above automatically creates the tool span
+
+ # Get API key from environment
+ api_key = os.environ.get("NEWS_API_KEY")
+ if not api_key:
+ raise Exception("NEWS_API_KEY not found in environment variables")
+
+ # Fetch news from NewsAPI
+ url = "https://newsapi.org/v2/top-headlines"
+ params = {
+ "country": "us",
+ "category": category,
+ "apiKey": api_key,
+ "pageSize": limit,
+ }
+
+ async with aiohttp.ClientSession() as session:
+ async with session.get(url, params=params) as response:
+ if response.status != 200:
+ raise Exception(f"Failed to fetch news: {response.status}")
+
+ data = await response.json()
+
+ if data.get("status") != "ok":
+ raise Exception(f"NewsAPI error: {data.get('message', 'Unknown error')}")
+
+ articles = data.get("articles", [])
+
+ # Format articles for context
+ formatted_articles = []
+ for article in articles[:limit]:
+ title = article.get("title", "No title")
+ description = article.get("description", "No description")
+ source = article.get("source", {}).get("name", "Unknown source")
+ formatted_articles.append(f"• {title} ({source}) - {description}")
+
+ context = "\n".join(formatted_articles)
+
+ # Create structured output
+ output = {
+ "articles": articles[:limit],
+ "formatted_context": context,
+ "article_count": len(articles[:limit]),
+ "requested_limit": limit,
+ "category": category,
+ "timestamp": datetime.now().isoformat(),
+ "source": "newsapi",
+ }
+
+ # Log output as JSON
+ output_log = {
+ "tool_execution": "news_api_tool",
+ "inputs": inputs,
+ "output": output,
+ "metadata": {
+ "article_count": output["article_count"],
+ "requested_limit": output["requested_limit"],
+ "category": output["category"],
+ "timestamp": output["timestamp"],
+ },
+ }
+ print(f"News API Tool Output: {json.dumps(output_log, indent=2)}")
+
+ # 👀 GALILEO TRACE CONCLUSION: Successfully conclude the trace
+ # This marks the trace as completed successfully in Splunk AO
+ # The trace will show as "success" in your dashboard
+ logger.conclude(output=context, duration_ns=0)
+ logger.flush()
+
+ # Return JSON string for proper Splunk AO logging display
+ galileo_output = {
+ "tool_result": "news_api_tool",
+ "formatted_output": json.dumps(output, indent=2),
+ "context": context,
+ "metadata": output,
+ }
+
+ return json.dumps(galileo_output, indent=2)
+
+ except Exception as e:
+ # 👀 GALILEO ERROR HANDLING: Conclude the trace with error status
+ # This marks the trace as failed in Splunk AO and includes the error message
+ # The trace will show as "error" in your dashboard with error details
+ if logger:
+ logger.conclude(output=str(e), duration_ns=0, error=True)
+ logger.flush()
+
+ raise e
+
+ async def _execute_without_galileo(self, category: str = "business", limit: int = 5) -> str:
+ """Fallback execution without Splunk AO logging"""
+ # ℹ️ FALLBACK METHOD: This method runs when Splunk AO is not available
+ # It performs the same functionality but without any observability logging
+ # Get API key from environment
+ api_key = os.environ.get("NEWS_API_KEY")
+ if not api_key:
+ raise Exception("NEWS_API_KEY not found in environment variables")
+
+ # Fetch news from NewsAPI
+ url = "https://newsapi.org/v2/top-headlines"
+ params = {
+ "country": "us",
+ "category": category,
+ "apiKey": api_key,
+ "pageSize": limit,
+ }
+
+ async with aiohttp.ClientSession() as session:
+ async with session.get(url, params=params) as response:
+ if response.status != 200:
+ raise Exception(f"Failed to fetch news: {response.status}")
+
+ data = await response.json()
+
+ if data.get("status") != "ok":
+ raise Exception(f"NewsAPI error: {data.get('message', 'Unknown error')}")
+
+ articles = data.get("articles", [])
+
+ # Format articles for context
+ formatted_articles = []
+ for article in articles[:limit]:
+ title = article.get("title", "No title")
+ description = article.get("description", "No description")
+ source = article.get("source", {}).get("name", "Unknown source")
+ formatted_articles.append(f"• {title} ({source}) - {description}")
+
+ context = "\n".join(formatted_articles)
+
+ # Create structured output
+ output = {
+ "articles": articles[:limit],
+ "formatted_context": context,
+ "article_count": len(articles[:limit]),
+ "requested_limit": limit,
+ "category": category,
+ "timestamp": datetime.now().isoformat(),
+ "source": "newsapi",
+ }
+
+ # Return JSON string for proper Splunk AO logging display
+ galileo_output = {
+ "tool_result": "news_api_tool",
+ "formatted_output": json.dumps(output, indent=2),
+ "context": context,
+ "metadata": output,
+ }
+
+ return json.dumps(galileo_output, indent=2)
+
+
+# ℹ️ TEST FUNCTION: This function can be used to test the tool independently
+async def main():
+ """Test the News API tool"""
+ tool = NewsAPITool()
+ result = await tool.execute(category="business", limit=3)
+ print(f"Result: {result}")
+
+
+if __name__ == "__main__":
+ import asyncio
+
+ asyncio.run(main())
diff --git a/examples/agent/startup-simulator-3000/tools/serious_startup_simulator.py b/examples/agent/startup-simulator-3000/tools/serious_startup_simulator.py
new file mode 100644
index 00000000..d3fbc4ec
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/tools/serious_startup_simulator.py
@@ -0,0 +1,274 @@
+import os
+import json
+from splunk_ao.openai import (
+ openai,
+) # 🔍 Splunk AO-wrapped OpenAI client for automatic logging
+from typing import Dict
+from agent_framework.tools.base import BaseTool
+from agent_framework.models import ToolMetadata
+from agent_framework.utils.logging import (
+ get_galileo_logger,
+) # 🔍 Splunk AO helper import - gets centralized logger
+import asyncio
+from dotenv import load_dotenv
+from datetime import datetime
+
+# Load environment variables
+load_dotenv()
+
+# 👀 GALILEO-WRAPPED OPENAI CLIENT: Use Splunk AO's OpenAI wrapper for automatic LLM logging
+# This automatically logs all OpenAI API calls to Splunk AO with detailed metrics
+client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
+
+
+class SeriousStartupSimulatorTool(BaseTool):
+ """Tool for generating serious, professional startup pitches"""
+
+ def __init__(self):
+ super().__init__()
+ self.name = "serious_startup_simulator"
+ self.description = "Generate a professional startup business plan based on industry, audience, and market trends"
+ # 👀 GALILEO INITIALIZATION: Get the centralized Splunk AO logger instance
+ # This ensures all tools use the same Splunk AO configuration and connection
+ self.galileo_logger = get_galileo_logger()
+
+ @classmethod
+ def get_metadata(cls) -> ToolMetadata:
+ return ToolMetadata(
+ name="serious_startup_simulator",
+ description="Generates professional, dry, and boring startup pitches for serious business contexts",
+ tags=["startup", "generator", "business", "professional", "serious"],
+ input_schema={
+ "type": "object",
+ "properties": {
+ "industry": {
+ "type": "string",
+ "description": "Industry for the startup",
+ },
+ "audience": {"type": "string", "description": "Target audience"},
+ "random_word": {
+ "type": "string",
+ "description": "A word to incorporate",
+ },
+ "news_context": {
+ "type": "string",
+ "description": "Recent news context for market analysis",
+ },
+ },
+ "required": ["industry", "audience", "random_word"],
+ },
+ output_schema={
+ "type": "string",
+ "description": "JSON string containing professional startup pitch data with metadata",
+ },
+ )
+
+ async def execute(self, industry: str, audience: str, random_word: str, news_context: str = "") -> str:
+ """Execute the serious startup simulator tool with individual Splunk AO trace"""
+
+ # Log inputs as JSON
+ inputs = {
+ "industry": industry,
+ "audience": audience,
+ "random_word": random_word,
+ "news_context": (news_context[:200] + "..." if len(news_context) > 200 else news_context),
+ "mode": "serious",
+ }
+ print(f"Serious Startup Simulator Inputs: {json.dumps(inputs, indent=2)}")
+
+ # 👀 GALILEO LOGGER SETUP: Get the Splunk AO logger for this execution
+ # This logger will be used to create traces and spans for observability
+ logger = self.galileo_logger
+ if not logger:
+ print("⚠️ Warning: Splunk AO logger not available, proceeding without logging")
+ # ℹ️ FALLBACK: If Splunk AO is not available, use the non-logging version
+ return await self._execute_without_galileo(industry, audience, random_word, news_context)
+
+ # 👀 GALILEO TRACE START: Create a new trace for this tool execution
+ # A trace represents the entire lifecycle of this tool call
+ # This will appear as a top-level trace in your Splunk AO dashboard
+ logger.start_trace(f"Serious Startup Simulator - {industry} targeting {audience}")
+
+ try:
+ # 👀 GALILEO SPAN START: Add an LLM span to mark the beginning of tool execution
+ # This span shows when the tool started working and what inputs it received
+ logger.add_llm_span(
+ input=f"Generate business plan for {industry} targeting {audience} with concept '{random_word}'",
+ output="Tool execution started",
+ model="serious_startup_simulator",
+ num_input_tokens=len(str(inputs)),
+ num_output_tokens=0,
+ total_tokens=len(str(inputs)),
+ duration_ns=0,
+ )
+
+ # Create the prompt with news context
+ news_context_prompt = ""
+ if news_context:
+ news_context_prompt = f"\n\nUse these recent business news trends for market analysis:\n{news_context}"
+
+ prompt = (
+ f"Generate a professional startup business plan for a {industry} company "
+ f"targeting {audience}. The plan must incorporate the concept '{random_word}' naturally. "
+ f"Be formal, avoid humor, and keep it under 500 characters total."
+ f"{news_context_prompt}"
+ )
+
+ # Create messages
+ messages = [{"role": "user", "content": prompt}]
+
+ # 👀 GALILEO-ENHANCED API CALL: Execute the API call using Splunk AO-wrapped OpenAI client
+ # This automatically logs the LLM call to Splunk AO with detailed metrics
+ # You'll see input/output tokens, model used, and response in your Splunk AO dashboard
+ response = client.chat.completions.create(
+ messages=messages,
+ model="gpt-4",
+ temperature=0.3, # Lower temperature for more professional output
+ )
+
+ # Extract the response
+ pitch = response.choices[0].message.content.strip()
+
+ # Create structured output
+ output = {
+ "pitch": pitch,
+ "character_count": len(pitch),
+ "mode": "serious",
+ "news_context_used": bool(news_context),
+ "timestamp": datetime.now().isoformat(),
+ "model": "gpt-4",
+ "input_tokens": (response.usage.prompt_tokens if hasattr(response.usage, "prompt_tokens") else 0),
+ "output_tokens": (response.usage.completion_tokens if hasattr(response.usage, "completion_tokens") else 0),
+ "total_tokens": (response.usage.total_tokens if hasattr(response.usage, "total_tokens") else 0),
+ }
+
+ # Log output as JSON to console and for Splunk AO observability
+ output_log = {
+ "tool_execution": "serious_startup_simulator",
+ "inputs": inputs,
+ "output": output,
+ "metadata": {
+ "character_count": output["character_count"],
+ "mode": output["mode"],
+ "news_context_used": output["news_context_used"],
+ "timestamp": output["timestamp"],
+ },
+ }
+ print(f"Serious Startup Simulator Output: {json.dumps(output_log, indent=2)}")
+
+ # 👀 GALILEO SPAN COMPLETION: Add an LLM span to mark successful completion
+ # This span shows the final output and completion status
+ # It includes token counts and the actual result for observability
+ logger.add_llm_span(
+ input="Business plan generation completed",
+ output=pitch,
+ model="gpt-4",
+ num_input_tokens=output["input_tokens"],
+ num_output_tokens=output["output_tokens"],
+ total_tokens=output["total_tokens"],
+ duration_ns=0,
+ )
+
+ # 👀 GALILEO TRACE CONCLUSION: Successfully conclude the trace
+ # This marks the trace as completed successfully in Splunk AO
+ # The trace will show as "success" in your dashboard
+ logger.conclude(output=pitch, duration_ns=0)
+ logger.flush()
+
+ # Return JSON string for proper Splunk AO logging display
+ galileo_output = {
+ "tool_result": "serious_startup_simulator",
+ "formatted_output": json.dumps(output, indent=2),
+ "pitch": output["pitch"],
+ "metadata": output,
+ }
+
+ return json.dumps(galileo_output, indent=2)
+
+ except Exception as e:
+ # 👀 GALILEO ERROR HANDLING: Conclude the trace with error status
+ # This marks the trace as failed in Splunk AO and includes the error message
+ # The trace will show as "error" in your dashboard with error details
+ if logger:
+ logger.conclude(output=str(e), duration_ns=0, error=True)
+ logger.flush()
+
+ raise e
+
+ async def _execute_without_galileo(self, industry: str, audience: str, random_word: str, news_context: str = "") -> str:
+ """Fallback execution without Splunk AO logging"""
+ # ℹ️ FALLBACK METHOD: This method runs when Splunk AO is not available
+ # It performs the same functionality but without any observability logging
+ # Create the prompt with news context
+ news_context_prompt = ""
+ if news_context:
+ news_context_prompt = f"\n\nUse these recent business news trends for market analysis:\n{news_context}"
+
+ prompt = (
+ f"Generate a professional startup business plan for a {industry} company "
+ f"targeting {audience}. The plan must incorporate the concept '{random_word}' naturally. "
+ f"Be formal, avoid humor, and keep it under 500 characters total."
+ f"{news_context_prompt}"
+ )
+
+ # Create messages
+ messages = [{"role": "user", "content": prompt}]
+
+ # Execute the API call
+ response = client.chat.completions.create(
+ messages=messages,
+ model="gpt-4",
+ temperature=0.3, # Lower temperature for more professional output
+ )
+
+ # Extract the response
+ pitch = response.choices[0].message.content.strip()
+
+ # Create structured output
+ output = {
+ "pitch": pitch,
+ "character_count": len(pitch),
+ "mode": "serious",
+ "news_context_used": bool(news_context),
+ "timestamp": datetime.now().isoformat(),
+ "model": "gpt-4",
+ "input_tokens": (response.usage.prompt_tokens if hasattr(response.usage, "prompt_tokens") else 0),
+ "output_tokens": (response.usage.completion_tokens if hasattr(response.usage, "completion_tokens") else 0),
+ "total_tokens": (response.usage.total_tokens if hasattr(response.usage, "total_tokens") else 0),
+ }
+
+ # Return JSON string for proper Splunk AO logging display
+ galileo_output = {
+ "tool_result": "serious_startup_simulator",
+ "formatted_output": json.dumps(output, indent=2),
+ "pitch": output["pitch"],
+ "metadata": output,
+ }
+
+ return json.dumps(galileo_output, indent=2)
+
+ def _parse_business_pitch(self, content: str) -> Dict[str, str]:
+ """Parse the business pitch into structured components"""
+ # This method could be enhanced to extract specific business plan sections
+ # For now, it returns a simple structure
+ return {
+ "executive_summary": (content[:200] + "..." if len(content) > 200 else content),
+ "full_pitch": content,
+ }
+
+
+# ℹ️ TEST FUNCTION: This function can be used to test the tool independently
+async def main():
+ """Test the Serious Startup Simulator tool"""
+ tool = SeriousStartupSimulatorTool()
+ result = await tool.execute(
+ industry="Finance",
+ audience="Investors",
+ random_word="fintech",
+ news_context="Sample news context for testing",
+ )
+ print(f"Result: {result}")
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/examples/agent/startup-simulator-3000/tools/startup_simulator.py b/examples/agent/startup-simulator-3000/tools/startup_simulator.py
new file mode 100644
index 00000000..2f7a8d49
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/tools/startup_simulator.py
@@ -0,0 +1,257 @@
+import os
+import json
+from splunk_ao.openai import (
+ openai,
+) # 🔍 Splunk AO-wrapped OpenAI client for automatic logging
+from agent_framework.tools.base import BaseTool
+from agent_framework.models import ToolMetadata
+from agent_framework.utils.logging import (
+ get_galileo_logger,
+) # 🔍 Splunk AO helper import - gets centralized logger
+import asyncio
+from dotenv import load_dotenv
+from datetime import datetime
+
+# Load environment variables
+load_dotenv()
+
+# 👀 GALILEO-WRAPPED OPENAI CLIENT: Use Splunk AO's OpenAI wrapper for automatic LLM logging
+# This automatically logs all OpenAI API calls to Splunk AO with detailed metrics
+client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
+
+
+class StartupSimulatorTool(BaseTool):
+ """Tool for generating a silly startup pitch using OpenAI's API"""
+
+ def __init__(self):
+ super().__init__()
+ self.name = "startup_simulator"
+ self.description = "Generate a creative startup pitch based on industry, audience, and a random word"
+ # 👀 GALILEO INITIALIZATION: Get the centralized Splunk AO logger instance
+ # This ensures all tools use the same Splunk AO configuration and connection
+ self.galileo_logger = get_galileo_logger()
+
+ @classmethod
+ def get_metadata(cls) -> ToolMetadata:
+ return ToolMetadata(
+ name="startup_simulator",
+ description="Generates a silly startup pitch using OpenAI's API, based on user input.",
+ tags=["startup", "generator", "openai", "fun"],
+ input_schema={
+ "type": "object",
+ "properties": {
+ "industry": {
+ "type": "string",
+ "description": "Industry for the startup",
+ },
+ "audience": {"type": "string", "description": "Target audience"},
+ "random_word": {
+ "type": "string",
+ "description": "A random word to include",
+ },
+ "hn_context": {
+ "type": "string",
+ "description": "Recent HackerNews context for inspiration",
+ },
+ },
+ "required": ["industry", "audience", "random_word"],
+ },
+ output_schema={
+ "type": "string",
+ "description": "JSON string containing silly startup pitch data with metadata",
+ },
+ )
+
+ async def execute(self, industry: str, audience: str, random_word: str, hn_context: str = "") -> str:
+ """Execute the startup simulator tool with individual Splunk AO trace"""
+
+ # Log inputs as JSON
+ inputs = {
+ "industry": industry,
+ "audience": audience,
+ "random_word": random_word,
+ "hn_context": (hn_context[:200] + "..." if len(hn_context) > 200 else hn_context),
+ "mode": "silly",
+ }
+ print(f"Startup Simulator Inputs: {json.dumps(inputs, indent=2)}")
+
+ # 👀 GALILEO LOGGER SETUP: Get the Splunk AO logger for this execution
+ # This logger will be used to create traces and spans for observability
+ logger = self.galileo_logger
+ if not logger:
+ print("⚠️ Warning: Splunk AO logger not available, proceeding without logging")
+ # ℹ️ FALLBACK: If Splunk AO is not available, use the non-logging version
+ return await self._execute_without_galileo(industry, audience, random_word, hn_context)
+
+ # 👀 GALILEO TRACE START: Create a new trace for this tool execution
+ # A trace represents the entire lifecycle of this tool call
+ # This will appear as a top-level trace in your Splunk AO dashboard
+ logger.start_trace(f"Startup Simulator - {industry} targeting {audience}")
+
+ try:
+ # 👀 GALILEO SPAN START: Add an LLM span to mark the beginning of tool execution
+ # This span shows when the tool started working and what inputs it received
+ logger.add_llm_span(
+ input=f"Generate startup pitch for {industry} targeting {audience} with word '{random_word}'",
+ output="Tool execution started",
+ model="startup_simulator",
+ num_input_tokens=len(str(inputs)),
+ num_output_tokens=0,
+ total_tokens=len(str(inputs)),
+ duration_ns=0,
+ )
+
+ # Create the prompt with HackerNews context
+ hn_context_prompt = ""
+ if hn_context:
+ hn_context_prompt = f"\n\nUse these recent HackerNews stories for inspiration:\n{hn_context}"
+
+ prompt = (
+ f"Generate a creative and engaging startup pitch for a {industry} company "
+ f"targeting {audience}. The pitch must include the word '{random_word}' naturally. "
+ f"Make it fun, innovative, and memorable. Keep it under 500 characters total."
+ f"{hn_context_prompt}"
+ )
+
+ # Create messages with Splunk AO context
+ messages = [{"role": "user", "content": prompt}]
+
+ # 👀 GALILEO-ENHANCED API CALL: Execute the API call using Splunk AO-wrapped OpenAI client
+ # This automatically logs the LLM call to Splunk AO with detailed metrics
+ # You'll see input/output tokens, model used, and response in your Splunk AO dashboard
+ response = client.chat.completions.create(messages=messages, model="gpt-4")
+
+ # Extract the response
+ pitch = response.choices[0].message.content.strip()
+
+ # Create structured output
+ output = {
+ "pitch": pitch,
+ "character_count": len(pitch),
+ "mode": "silly",
+ "hn_context_used": bool(hn_context),
+ "timestamp": datetime.now().isoformat(),
+ "model": "gpt-4",
+ "input_tokens": (response.usage.prompt_tokens if hasattr(response.usage, "prompt_tokens") else 0),
+ "output_tokens": (response.usage.completion_tokens if hasattr(response.usage, "completion_tokens") else 0),
+ "total_tokens": (response.usage.total_tokens if hasattr(response.usage, "total_tokens") else 0),
+ }
+
+ # Log output as JSON to console and for Splunk AO observability
+ output_log = {
+ "tool_execution": "startup_simulator",
+ "inputs": inputs,
+ "output": output,
+ "metadata": {
+ "character_count": output["character_count"],
+ "mode": output["mode"],
+ "hn_context_used": output["hn_context_used"],
+ "timestamp": output["timestamp"],
+ },
+ }
+ print(f"Startup Simulator Output: {json.dumps(output_log, indent=2)}")
+
+ # 👀 GALILEO SPAN COMPLETION: Add an LLM span to mark successful completion
+ # This span shows the final output and completion status
+ # It includes token counts and the actual result for observability
+ logger.add_llm_span(
+ input="Startup pitch generation completed",
+ output=pitch,
+ model="gpt-4",
+ num_input_tokens=output["input_tokens"],
+ num_output_tokens=output["output_tokens"],
+ total_tokens=output["total_tokens"],
+ duration_ns=0,
+ )
+
+ # 👀 GALILEO TRACE CONCLUSION: Successfully conclude the trace
+ # This marks the trace as completed successfully in Splunk AO
+ # The trace will show as "success" in your dashboard
+ logger.conclude(output=pitch, duration_ns=0)
+ logger.flush()
+
+ # Return JSON string for proper Splunk AO logging display
+ galileo_output = {
+ "tool_result": "startup_simulator",
+ "formatted_output": json.dumps(output, indent=2),
+ "pitch": output["pitch"],
+ "metadata": output,
+ }
+
+ # Return as formatted JSON string for Splunk AO
+ return json.dumps(galileo_output, indent=2)
+
+ except Exception as e:
+ # 👀 GALILEO ERROR HANDLING: Conclude the trace with error status
+ # This marks the trace as failed in Splunk AO and includes the error message
+ # The trace will show as "error" in your dashboard with error details
+ if logger:
+ logger.conclude(output=str(e), duration_ns=0, error=True)
+ logger.flush()
+
+ raise e
+
+ async def _execute_without_galileo(self, industry: str, audience: str, random_word: str, hn_context: str = "") -> str:
+ """Fallback execution without Splunk AO logging"""
+ # ℹ️ FALLBACK METHOD: This method runs when Splunk AO is not available
+ # It performs the same functionality but without any observability logging
+ # Create the prompt with HackerNews context
+ hn_context_prompt = ""
+ if hn_context:
+ hn_context_prompt = f"\n\nUse these recent HackerNews stories for inspiration:\n{hn_context}"
+
+ prompt = (
+ f"Generate a creative and engaging startup pitch for a {industry} company "
+ f"targeting {audience}. The pitch must include the word '{random_word}' naturally. "
+ f"Make it fun, innovative, and memorable. Keep it under 500 characters total."
+ f"{hn_context_prompt}"
+ )
+
+ # Create messages
+ messages = [{"role": "user", "content": prompt}]
+
+ # Execute the API call
+ response = client.chat.completions.create(messages=messages, model="gpt-4")
+
+ # Extract the response
+ pitch = response.choices[0].message.content.strip()
+
+ # Create structured output
+ output = {
+ "pitch": pitch,
+ "character_count": len(pitch),
+ "mode": "silly",
+ "hn_context_used": bool(hn_context),
+ "timestamp": datetime.now().isoformat(),
+ "model": "gpt-4",
+ "input_tokens": (response.usage.prompt_tokens if hasattr(response.usage, "prompt_tokens") else 0),
+ "output_tokens": (response.usage.completion_tokens if hasattr(response.usage, "completion_tokens") else 0),
+ "total_tokens": (response.usage.total_tokens if hasattr(response.usage, "total_tokens") else 0),
+ }
+
+ # Return JSON string for proper Splunk AO logging display
+ galileo_output = {
+ "tool_result": "startup_simulator",
+ "formatted_output": json.dumps(output, indent=2),
+ "pitch": output["pitch"],
+ "metadata": output,
+ }
+
+ return json.dumps(galileo_output, indent=2)
+
+
+# ℹ️ TEST FUNCTION: This function can be used to test the tool independently
+async def main():
+ """Test the Startup Simulator tool"""
+ tool = StartupSimulatorTool()
+ result = await tool.execute(
+ industry="Tech",
+ audience="Developers",
+ random_word="blockchain",
+ hn_context="Sample HN context for testing",
+ )
+ print(f"Result: {result}")
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/examples/agent/startup-simulator-3000/tools/text_analysis.py b/examples/agent/startup-simulator-3000/tools/text_analysis.py
new file mode 100644
index 00000000..a6f40bb8
--- /dev/null
+++ b/examples/agent/startup-simulator-3000/tools/text_analysis.py
@@ -0,0 +1,52 @@
+from typing import Dict, Any
+from agent_framework.tools.base import BaseTool
+from agent_framework.models import ToolMetadata
+
+
+class TextAnalyzerTool(BaseTool):
+ """Tool for analyzing text complexity"""
+
+ @classmethod
+ def get_metadata(cls) -> ToolMetadata:
+ """Get tool metadata"""
+ return ToolMetadata(
+ name="text_analyzer",
+ description="Analyzes text for complexity and readability",
+ tags=["text", "analysis", "complexity"],
+ input_schema={
+ "type": "object",
+ "properties": {"text": {"type": "string", "description": "Text to analyze"}},
+ "required": ["text"],
+ },
+ output_schema={
+ "type": "object",
+ "properties": {
+ "complexity_score": {"type": "number"},
+ "readability_level": {"type": "string"},
+ "analysis": {"type": "string"},
+ },
+ },
+ )
+
+ async def execute(self, text: str) -> Dict[str, Any]:
+ """Analyze text complexity"""
+ # Simple implementation - in real world would use NLP
+ word_count = len(text.split())
+ avg_word_length = sum(len(word) for word in text.split()) / word_count if word_count > 0 else 0
+
+ # Calculate complexity score (0-10)
+ complexity_score = min(10, (avg_word_length - 3) * 2)
+
+ # Determine readability level
+ if complexity_score < 4:
+ level = "Easy"
+ elif complexity_score < 7:
+ level = "Moderate"
+ else:
+ level = "Complex"
+
+ return {
+ "complexity_score": complexity_score,
+ "readability_level": level,
+ "analysis": f"Text contains {word_count} words with average length of {avg_word_length:.1f} characters.",
+ }
diff --git a/examples/agent/strands-agents/.env.example b/examples/agent/strands-agents/.env.example
new file mode 100644
index 00000000..facc3863
--- /dev/null
+++ b/examples/agent/strands-agents/.env.example
@@ -0,0 +1,8 @@
+# AWS environment variables
+AWS_BEARER_TOKEN_BEDROCK=
+
+# Galileo environment variables
+GALILEO_API_ENDPOINT=
+GALILEO_API_KEY=
+GALILEO_PROJECT=
+GALILEO_LOG_STREAM=
\ No newline at end of file
diff --git a/examples/agent/strands-agents/README.md b/examples/agent/strands-agents/README.md
new file mode 100644
index 00000000..3b5c9094
--- /dev/null
+++ b/examples/agent/strands-agents/README.md
@@ -0,0 +1,50 @@
+# Strands Agents + OpenTelemetry Example Project
+
+This is an example project demonstrating how to use Splunk AO with the [Strands Agent SDK](https://strandsagents.com/latest/), using AWS Bedrock as the LLM provider. This uses the simple [quickstart from the Strands Agents documentation](https://strandsagents.com/latest/documentation/docs/user-guide/quickstart/), and adds Splunk AO logging.
+
+## Getting Started
+
+To get started with this project, you'll need to have Python 3.10 or later installed. You can then install the required dependencies in a virtual environment:
+
+```bash
+pip install -r requirements.txt
+```
+
+## Configure environment variables
+
+You will need to configure environment variables to use this project. Copy the `.env.example` file to `.env`, then update the environment variables in the `.env` file with your AWS and Splunk AO values:
+
+```ini
+# AWS environment variables
+AWS_BEARER_TOKEN_BEDROCK=
+
+# Splunk AO environment variables
+# SPLUNK_AO_API_ENDPOINT= # Optional, only set this if you are using a custom Splunk AO deployment
+SPLUNK_AO_API_KEY=
+SPLUNK_AO_PROJECT=
+SPLUNK_AO_LOG_STREAM=
+```
+
+For the `SPLUNK_AO_API_ENDPOINT`, you only need to set this if you are using a custom Splunk AO deployment. There is no need to set this if you ae using [app.galileo.ai](https://app.galileo.ai). This endpoint is different to the console URL that you would normally use. See the [Splunk AO OpenTelemetry documentation](https://docs.galileo.ai/sdk-api/third-party-integrations/opentelemetry-and-openinference#self-hosted-deployments) for more details.
+
+## Usage
+
+Once the dependencies are installed, you can run the example application:
+
+```bash
+python agent.py
+```
+
+Traces will be captured and logged to Splunk AO.
+
+## Project Structure
+
+The project structure is as follows:
+
+```folder
+strands-agents/
+├─ env.example # List of environment variables
+├── agent.py # The main agent application
+├── requirements.txt # Python project requirements
+└── README.md # Project documentation
+```
diff --git a/examples/agent/strands-agents/agent.py b/examples/agent/strands-agents/agent.py
new file mode 100644
index 00000000..9411445f
--- /dev/null
+++ b/examples/agent/strands-agents/agent.py
@@ -0,0 +1,71 @@
+import os
+
+from strands import Agent, tool
+from strands.telemetry import StrandsTelemetry
+from strands_tools import calculator, current_time
+
+# Load environment variables from the .env file
+from dotenv import load_dotenv
+
+load_dotenv(override=True)
+
+# Export the Splunk AO OTel API endpoint for OTel
+os.environ["OTEL_EXPORTER_OTLP_TRACES_ENDPOINT"] = os.environ.get("SPLUNK_AO_API_ENDPOINT", "https://api.galileo.ai/otel/traces")
+
+# Export the Splunk AO OTel headers pointing to the correct API key, project, and log stream
+headers = {
+ "Galileo-API-Key": os.environ["SPLUNK_AO_API_KEY"],
+ "project": os.environ["SPLUNK_AO_PROJECT"],
+ "logstream": os.environ["SPLUNK_AO_LOG_STREAM"],
+}
+
+os.environ["OTEL_EXPORTER_OTLP_HEADERS"] = ",".join([f"{k}={v}" for k, v in headers.items()])
+
+# Setup telemetry for the Strands agent using Splunk AO as the OTel backend
+strands_telemetry = StrandsTelemetry()
+strands_telemetry.setup_otlp_exporter()
+
+# Uncomment this line to see the OTel output in the console
+# strands_telemetry.setup_console_exporter()
+
+
+# This agent code is from the simple quickstart from the
+# Strands Agents documentation
+# https://strandsagents.com/latest/documentation/docs/user-guide/quickstart/
+
+
+# Define a custom tool as a Python function using the @tool decorator
+@tool
+def letter_counter(word: str, letter: str) -> int:
+ """
+ Count occurrences of a specific letter in a word.
+
+ Args:
+ word (str): The input word to search in
+ letter (str): The specific letter to count
+
+ Returns:
+ int: The number of occurrences of the letter in the word
+ """
+ if not isinstance(word, str) or not isinstance(letter, str):
+ return 0
+
+ if len(letter) != 1:
+ raise ValueError("The 'letter' parameter must be a single character")
+
+ return word.lower().count(letter.lower())
+
+
+# Create an agent with tools from the community-driven strands-tools package
+# as well as our custom letter_counter tool
+agent = Agent(tools=[calculator, current_time, letter_counter])
+
+# Ask the agent a question that uses the available tools
+message = """
+I have 4 requests:
+
+1. What is the time right now?
+2. Calculate 3111696 / 74088
+3. Tell me how many letter R's are in the word "strawberry" 🍓
+"""
+agent(message)
diff --git a/examples/agent/strands-agents/requirements.txt b/examples/agent/strands-agents/requirements.txt
new file mode 100644
index 00000000..cee82cf2
--- /dev/null
+++ b/examples/agent/strands-agents/requirements.txt
@@ -0,0 +1,6 @@
+opentelemetry-api
+opentelemetry-exporter-otlp
+opentelemetry-sdk
+python-dotenv
+strands-agents
+strands-agents-tools
\ No newline at end of file
diff --git a/examples/agent/weather-vibes-agent/.env.example b/examples/agent/weather-vibes-agent/.env.example
new file mode 100644
index 00000000..41b66fdc
--- /dev/null
+++ b/examples/agent/weather-vibes-agent/.env.example
@@ -0,0 +1,12 @@
+# Galileo Environment Variables
+GALILEO_API_KEY=your-galileo-api-key # Your Galileo API key.
+GALILEO_PROJECT=your-galileo-project-name # Your Galileo project name.
+GALILEO_LOG_STREAM=your-galileo-log-stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# GALILEO_CONSOLE_URL=your-galileo-console-url # Optional if you are using a hosted version of Galileo
+
+# API Keys
+OPENAI_API_KEY=your_openai_api_key_here
+WEATHERAPI_KEY=your_weatherapi_key_here
+YOUTUBE_API_KEY=your_youtube_api_key_here
diff --git a/examples/agent/weather-vibes-agent/00-tutorial/01-weather-vibes-overview.md b/examples/agent/weather-vibes-agent/00-tutorial/01-weather-vibes-overview.md
new file mode 100644
index 00000000..5b465296
--- /dev/null
+++ b/examples/agent/weather-vibes-agent/00-tutorial/01-weather-vibes-overview.md
@@ -0,0 +1,152 @@
+# 🌦️ Weather Vibes Agent Tutorial Overview
+
+Welcome to the Weather Vibes Agent tutorial! This guide will walk you through building and understanding an AI agent that provides weather information, clothing recommendations, and matching YouTube videos based on the current weather in a location - all while using Splunk AO to monitor and improve your agent's performance.
+
+## 🎒 What You'll Need
+
+Before we dive into the code ocean, make sure you've packed:
+
+- **Python 3.8+** installed on your system
+- **API Keys** (free options available):
+ - OpenAI API key (for agent reasoning)
+ - WeatherAPI key (for weather data)
+ - YouTube API key (for video recommendations)
+ - Splunk AO API key (for monitoring and evaluation)
+- **Development Environment**:
+ - Code editor of choice
+ - Terminal/command-line access
+ - Git (to clone the repository)
+- **Package Manager**:
+ - [uv](https://docs.astral.sh/uv/getting-started/installation/) (will be used to create the virtual environment and install dependencies)
+
+## 🧠 Helpful Background Knowledge
+Don't worry if you're not an expert in all these areas - the tutorial is designed to guide you through each step without any prior knowledge, and the code is well-documented.
+
+- **Python Basics**: Functions, async/await, and error handling
+- **API Knowledge**: RESTful APIs and how to use keys
+- **LLM Concepts**: Understanding of AI agents and large language models
+- **Terminal Skills**: Basic command-line comfort
+
+## What You'll Learn
+By completing this tutorial, you will:
+
+1. **Build a Multi-Function AI Agent**: Create an agent that combines multiple tools and APIs
+2. **Implement API Integrations**:
+ - Weather data retrieval from WeatherAPI
+ - Video recommendations from YouTube
+ - AI-based recommendations using OpenAI
+3. **Use Splunk AO for Agent Evaluation**:
+ - Instrument your agent with Splunk AO SDK
+ - Track agent performance through traces
+ - Analyze execution flow and identify bottlenecks
+ - Collect and evaluate agent outputs
+4. **Create Agent Interfaces**:
+ - Command-line interface for testing
+ - Web API for integration with other systems
+5. **Follow Best Practices**:
+ - Structured agent architecture
+ - Error handling and graceful failure
+ - Configuration management
+ - Code organization and modularity
+
+1. **Observe Your AI in Action**: See exactly what your agent is doing at each step
+ - Track every API call with precise timing
+ - Understand execution flow through hierarchical traces
+ - Identify performance bottlenecks in real-time
+
+2. **Learn to use the Splunk AO Python SDK**:
+ - Use the `log` decorator to instrument functions
+ - Create spans for different operation types (LLM, tool usage, workflows)
+ - Set up context management with `splunk_ao_context`
+ - Capture inputs and outputs across your entire agent
+ - Add metadata for richer analysis
+
+3. **Debug Like a Pro**:
+ - Pinpoint exactly where errors occur
+ - Understand the full context of failures
+ - Compare successful vs. unsuccessful runs
+ - Analyze performance patterns across multiple executions
+
+4. **Build a Robust Agent Architecture**:
+ - Combine weather data, recommendations, and video suggestions
+ - Handle errors gracefully at every step
+ - Structure your code for maintainability and clarity
+ - See how proper instrumentation makes complex agents manageable
+
+5. **Level Up Your Dev Skills**:
+ - Apply best practices for async Python
+ - Structure complex workflows with clear separation of concerns
+ - Implement professional-grade error handling and reporting
+ - Use environment variables for secure configuration management
+
+## 🎉 Let's Get Started
+
+1. **Clone the Code**:
+ ```bash
+ git clone https://github.com/rungalileo/sdk-examples.git
+ cd sdk-examples/python/agent/weather-vibes-agent
+ ```
+
+2. **Set Up Your Environment**:
+ ```bash
+ # Create a virtual environment
+ uv venv venv
+ source venv/bin/activate # On Windows: venv\Scripts\activate
+
+ # Install deps with uv
+ uv install -r requirements.txt
+ ```
+
+3. **Configure Your API Keys**:
+ Create a `.env` file in the project root:
+
+ ```
+ # Splunk AO Environment Variables
+ SPLUNK_AO_API_KEY=your-splunk-ao-api-key # Your Splunk AO API key.
+ SPLUNK_AO_PROJECT=your-splunk-ao-project-name # Your Splunk AO project name.
+ SPLUNK_AO_LOG_STREAM=weather_vibes_agent
+
+ # Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+ # SPLUNK_AO_CONSOLE_URL=your-splunk-ao-console-url # Optional if you are using a hosted version of Splunk AO
+
+ OPENAI_API_KEY=your_openai_key
+ WEATHERAPI_KEY=your_weatherapi_key
+ YOUTUBE_API_KEY=your_youtube_key
+ ```
+
+4. **Follow the Tutorial Sections**:
+ - 01-weather-vibes-overview.md (this file)
+ - 02-installation-instructions.md
+ - 03-using-galileo.md
+
+6. **Run the Weather Vibes App**:
+ ```bash
+ # Get the weather vibe for Tokyo
+ python agent.py "Tokyo"
+
+ # Get fancy with options
+ python agent.py --location "New York" --units imperial --mood relaxing --verbose
+ ```
+
+## 🔍 What to Watch in the Splunk AO Dashboard
+
+After running your agent, head over to your Splunk AO dashboard to see:
+
+1. **Complete Trace Hierarchy**: Visualize how your agent's components interact
+2. **Timing Breakdown**: See exactly how long each operation takes
+3. **Input/Output Analysis**: Explore what data flows between components
+4. **Error Insights**: If something goes wrong, see exactly where and why
+
+## 🗂️ Project Architecture
+
+- **agent.py**: Our main agent with Splunk AO instrumentation
+- **agent/weather_vibes_agent.py**: The core agent implementation
+- **tools/**: The specialized tools our agent uses
+ - **weather_tool.py**: For fetching weather data
+ - **recommendation_tool.py**: For suggesting items based on weather
+ - **youtube_tool.py**: For finding weather-appropriate videos
+- **templates/**: Web interface templates (if you're feeling fancy)
+
+Ready to build something awesome while learning how to monitor it like a pro? Let's rock this! 🌈✨
+
+Happy building!
diff --git a/examples/agent/weather-vibes-agent/00-tutorial/02-installation-instructions.md b/examples/agent/weather-vibes-agent/00-tutorial/02-installation-instructions.md
new file mode 100644
index 00000000..fe1e4db2
--- /dev/null
+++ b/examples/agent/weather-vibes-agent/00-tutorial/02-installation-instructions.md
@@ -0,0 +1,286 @@
+# 🛠️ Installation Instructions
+
+ et's get you up and running so you can start building awesome AI agents with Splunk AO!
+
+## Prerequisites
+
+Before we dive in, make sure you have:
+
+- Python 3.8 or newer installed
+- Basic terminal/command line experience
+- API keys ready (or know how to get them)
+- Git installed on your system
+
+## Step 1: Clone the Repository
+
+First, let's grab the code:
+
+```bash
+# Clone the repository
+git clone https://github.com/[organization]/sdk-examples.git
+
+# Navigate to the project folder
+cd sdk-examples/python/agent/weather-vibes-agent
+```
+
+## Step 2: Set Up Your Environment
+
+I recommend using `uv` for faster dependency management, but you can use standard Python tools if you prefer.
+
+### Option A: Using UV (Recommended)
+
+```bash
+# Install UV if you don't have it
+curl -sSf https://install.pypa.io/get-uv.py | python3 -
+
+# Create a virtual environment
+uv venv venv
+
+# Activate the virtual environment
+source venv/bin/activate # On Windows, use: venv\Scripts\activate
+
+# Install dependencies
+uv install -r requirements.txt
+```
+
+### Option B: Using Standard Python Tools
+
+```bash
+# Create a virtual environment
+python -m venv venv
+
+# Activate the virtual environment
+source venv/bin/activate # On Windows, use: venv\Scripts\activate
+
+# Install dependencies
+pip install -r requirements.txt
+```
+
+## Step 3: Get Your API Keys
+
+You'll need four API keys to make the Weather Vibes Agent work:
+
+### OpenAI API Key
+
+1. Go to [OpenAI's platform](https://platform.openai.com/signup)
+2. Create an account or sign in
+3. Navigate to API Keys in your account settings
+4. Click "Create new secret key"
+5. Copy the key (you won't see it again!)
+
+### WeatherAPI Key
+
+1. Visit [WeatherAPI](https://www.weatherapi.com)
+2. Create a free account
+3. After logging in, go to "API Keys" tab
+4. Copy your API key (or create a new one)
+5. Note: It may take a few hours for a new key to activate
+
+### YouTube Data API Key
+
+1. Go to the [Google Cloud Console](https://console.cloud.google.com/)
+2. Create a new project (or select an existing one)
+3. Enable the "YouTube Data API v3"
+4. Create credentials for an API key
+5. Copy your API key
+
+### Splunk AO API Key
+
+1. Sign up for a free account at [Splunk AO](https://app.galileo.ai/sign-up)
+2. Go to Settings → API Keys in the dashboard
+3. Create a new API key
+4. Copy your key
+
+## Step 4: Configure Environment Variables
+
+Create a `.env` file in the project root directory with your API keys:
+
+```
+# Splunk AO Environment Variables
+SPLUNK_AO_API_KEY=your-splunk-ao-api-key # Your Splunk AO API key.
+SPLUNK_AO_PROJECT=your-splunk-ao-project-name # Your Splunk AO project name.
+SPLUNK_AO_LOG_STREAM=weather_vibes_agent
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# SPLUNK_AO_CONSOLE_URL=your-splunk-ao-console-url # Optional if you are using a hosted version of Splunk AO
+
+OPENAI_API_KEY=your_openai_key_here
+WEATHERAPI_KEY=your_weatherapi_key_here
+YOUTUBE_API_KEY=your_youtube_key_here
+```
+
+Replace `your_*_key_here` with your actual API keys.
+
+## Step 5: Fix Import Paths (Important!)
+
+The project may have import path issues. Let's fix them:
+
+1. Open `agent/weather_vibes_agent.py` and check the import section.
+ If you see imports like:
+ ```python
+ from weather_vibes.tools.weather_tool import WeatherTool
+ ```
+
+2. Change them to:
+ ```python
+ from tools.weather_tool import WeatherTool
+ from tools.recommendation_tool import RecommendationsTool
+ from tools.youtube_tool import YouTubeTool
+ from agent.descriptor import WEATHER_VIBES_DESCRIPTOR
+ ```
+
+3. Also update the project root path setting:
+ ```python
+ # Change this:
+ project_root = current_dir.parent.parent
+
+ # To this:
+ project_root = current_dir.parent
+ ```
+
+## Step 6: Run the Agent
+
+Now you're ready to run the Weather Vibes Agent:
+
+```bash
+# Basic usage
+python agent.py "New York"
+
+# Advanced usage
+python agent.py --location "Tokyo" --units imperial --mood relaxing --verbose
+```
+
+This should show you weather information, recommendations, and a matching YouTube video!
+
+## 🔍 Common Troubleshooting
+
+### "ModuleNotFoundError: No module named 'weather_vibes'"
+
+**Problem**: The agent is trying to import from a module that doesn't exist in the current structure.
+
+**Solution**:
+1. Follow the import fixes in Step 5 above
+2. If issues persist, create a symbolic link:
+ ```bash
+ # From the project root directory:
+ ln -s . weather_vibes
+ ```
+
+### "ModuleNotFoundError: No module named 'agent_framework'"
+
+**Problem**: The Simple Agent Framework dependency is missing or not installed correctly.
+
+**Solution**:
+```bash
+# Install the framework from GitHub
+uv install git+https://github.com/rungalileo/simple-agent-framework.git@main
+
+# Or with pip
+pip install git+https://github.com/rungalileo/simple-agent-framework.git@main
+```
+
+### API Key Errors
+
+**Problem**: "Invalid API key", "API key not found", or similar errors.
+
+**Solutions**:
+- Double-check your `.env` file for typos
+- Make sure your `.env` file is in the correct location (project root)
+- For WeatherAPI: New API keys may take a few hours to activate
+- For YouTube: Ensure the API is enabled in Google Cloud Console
+- For OpenAI: Check your account has billing set up
+
+### "KeyError" or Missing Fields in Response
+
+**Problem**: The agent crashes when trying to access data from API responses.
+
+**Solution**: The APIs occasionally change their response format or return partial data.
+```python
+# Add defensive checks in your code:
+weather_condition = weather_result.get("condition", "unknown")
+```
+
+### Template Not Found Errors
+
+**Problem**: Jinja template errors mentioning that templates can't be found.
+
+**Solution**: Make sure the templates directory exists and contains the required template files:
+```bash
+# Check the templates directory
+ls -la templates
+
+# Create a basic system template if missing
+mkdir -p templates
+echo "You are a helpful weather agent. Help the user based on their request." > templates/system.j2
+```
+
+### Rate Limit Errors
+
+**Problem**: "Rate limit exceeded" errors from any of the APIs.
+
+**Solutions**:
+- OpenAI: Wait a minute and try again, or upgrade your plan
+- YouTube: Create a new API key with higher quotas
+- WeatherAPI: Upgrade to a paid plan for more requests
+
+### SSL Certificate Errors
+
+**Problem**: SSL/TLS certificate verification failures when making API requests.
+
+**Solution**: Update your CA certificates or adjust the request settings:
+```bash
+# Update certificates (MacOS)
+open /Applications/Python\ 3.x/Install\ Certificates.command
+
+# Update certificates (Ubuntu/Debian)
+sudo apt-get update && sudo apt-get install ca-certificates
+```
+
+### "No module named 'dotenv'"
+
+**Problem**: The python-dotenv package is missing.
+
+**Solution**:
+```bash
+uv install python-dotenv
+# or
+pip install python-dotenv
+```
+
+## Still Having Issues?
+
+Here are a few more advanced troubleshooting steps:
+
+1. **Debug Mode**: Run the agent in debug mode to see more detailed logs:
+ ```bash
+ # Set logging level to DEBUG
+ export PYTHONPATH=.
+ python -m agent --debug "New York"
+ ```
+
+2. **Check Python Version**: Ensure you're using Python 3.8 or newer:
+ ```bash
+ python --version
+ ```
+
+3. **Clean Install**: If all else fails, try a completely fresh installation:
+ ```bash
+ # Remove the virtual environment
+ rm -rf venv
+
+ # Create a new one
+ uv venv venv
+ source venv/bin/activate
+
+ # Install all dependencies fresh
+ uv install -r requirements.txt
+ ```
+
+4. **Update Dependencies**: Sometimes updating dependencies can fix compatibility issues:
+ ```bash
+ uv install -U -r requirements.txt
+ ```
+
+In the next section, we'll dive into how to use Splunk AO to monitor and improve your agent. Stay tuned!
+
+~ Erin
diff --git a/examples/agent/weather-vibes-agent/00-tutorial/03-using-galileo.md b/examples/agent/weather-vibes-agent/00-tutorial/03-using-galileo.md
new file mode 100644
index 00000000..be36a91a
--- /dev/null
+++ b/examples/agent/weather-vibes-agent/00-tutorial/03-using-galileo.md
@@ -0,0 +1,112 @@
+# Using Splunk AO with Weather Vibes Agent
+
+This document explains how to use Splunk AO for evaluating and monitoring the Weather Vibes agent.
+
+## What is Splunk AO?
+
+[Splunk AO](https://www.rungalileo.io/) is an AI observability and evaluation platform that helps you:
+
+- Track agent behavior
+- Collect and analyze traces
+- Evaluate agent performance
+- Identify areas for improvement
+- Monitor production deployments
+
+## Setup
+
+### 1. Install Splunk AO SDK
+
+```bash
+pip install -r requirements-galileo.txt
+```
+
+### 2. Configure Splunk AO details
+
+Create or edit your `.env` file and add your Splunk AO details:
+
+```
+# Splunk AO Environment Variables
+SPLUNK_AO_API_KEY=your-splunk-ao-api-key # Your Splunk AO API key.
+SPLUNK_AO_PROJECT=your-splunk-ao-project-name # Your Splunk AO project name.
+SPLUNK_AO_LOG_STREAM=your-splunk-ao-log-stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# SPLUNK_AO_CONSOLE_URL=your-splunk-ao-console-url # Optional if you are using a hosted version of Splunk AO
+```
+
+You can get your API key from the Splunk AO dashboard.
+
+## Running the Splunk AO-Instrumented Agent
+
+Run the agent with Splunk AO instrumentation:
+
+```bash
+python galileo_agent.py "San Francisco"
+```
+
+You can use all the same command-line arguments as the regular agent:
+
+```bash
+python galileo_agent.py --location "Tokyo" --units imperial --mood relaxing --verbose
+```
+
+## Understanding the Spans
+
+The Splunk AO-instrumented version of the agent includes several span types. Learn more about spans, the atomic unit of logging in Splunk AO, [here](https://docs.galileo.ai/getting-started/logging).
+
+1. **Workflow Span** (`workflow`):
+ - Captures the main agent workflow in `process_request`
+ - Shows how the agent processes the request end-to-end
+ - Also used for the main agent orchestration function
+
+2. **Tool Spans** (`tool`):
+ - Individual tool executions:
+ - `weather_tool`: WeatherAPI call
+ - `recommendations_tool`: Weather-based recommendations generation
+ - `youtube_tool`: YouTube video search
+
+3. **LLM Span** (`llm`):
+ - Used when a span invokes an LLM call
+ - Currently not used in this agent but available for future LLM integrations
+
+4. **Retriever Span** (`retriever`):
+ - Used when a span is retrieving data
+ - Currently not used in this agent but available for future retrieval operations
+
+## Viewing Traces in Splunk AO
+
+After running the agent, you can view the traces in the Splunk AO dashboard. The traces will show:
+
+- Request and response data for each span
+- Execution time for each component
+- Hierarchical view of the agent's workflow
+- Input/output data flow between components
+
+## Customizing Instrumentation
+
+You can add more spans or customize existing ones by modifying `agent.py`:
+
+1. **Adding LLM spans**: If you implement LLM-based tools, use `@log(span_type="llm")` decorators
+2. **Adding retrieval spans**: For document retrieval functions, use `@log(span_type="retriever")` decorators
+3. **Custom span names**: Modify the `name` parameter in decorators for better organization
+
+## Using Splunk AO for Evaluation
+
+You can use Splunk AO's evaluation features to:
+
+1. **Create eval datasets**: Build a set of test inputs for your agent
+2. **Define metrics**: Set up metrics to measure agent performance
+3. **Run evaluations**: Test your agent against the datasets
+4. **Analyze results**: Identify strengths and weaknesses
+5. **Improve the agent**: Make targeted improvements based on insights
+
+## Troubleshooting
+
+If you encounter issues with Splunk AO:
+
+- Check that your API key is correctly set in the environment
+- Ensure the Splunk AO SDK is properly installed
+- Verify that your spans are correctly configured
+- Check the Splunk AO documentation for more information
+
+For more information, visit the [Splunk AO documentation](https://docs.galileo.ai/what-is-galileo).
diff --git a/examples/agent/weather-vibes-agent/00-tutorial/weather-vibes-cookbook.md b/examples/agent/weather-vibes-agent/00-tutorial/weather-vibes-cookbook.md
new file mode 100644
index 00000000..4bf9702d
--- /dev/null
+++ b/examples/agent/weather-vibes-agent/00-tutorial/weather-vibes-cookbook.md
@@ -0,0 +1,490 @@
+# 🌦️ Weather Vibes Agent Cookbook
+
+A comprehensive tutorial for building a weather-based recommendation agent with Splunk AO observability.
+
+## Overview
+
+This cookbook will guide you through building, understanding, and monitoring the Weather Vibes Agent - an AI agent that combines weather data, recommendations, and video suggestions, all monitored using Splunk AO's observability platform.
+
+**What you'll build:** A command-line agent that:
+1. Fetches current weather for any location
+2. Generates item recommendations based on the weather
+3. Finds YouTube videos matching the weather mood
+4. Captures detailed traces and metrics for analysis
+
+**What you'll learn:**
+- Building multi-service AI agents
+- Integrating with external APIs
+- Instrumenting code with Splunk AO
+- Implementing proper error handling
+- Analyzing agent performance
+
+## Prerequisites
+
+- Python 3.8+
+- API keys for:
+ - OpenAI
+ - WeatherAPI
+ - YouTube Data API
+ - Splunk AO
+- Basic Python knowledge
+- Terminal/command-line familiarity
+
+## Environment Setup
+
+**Ingredients:**
+- git
+- Python environment tools
+- Package manager (pip or uv)
+
+**Steps:**
+
+1. **Clone the repository:**
+
+ ```bash
+ git clone https://github.com/[organization]/sdk-examples.git
+ cd sdk-examples/python/agent/weather-vibes-agent
+ ```
+
+2. **Create a virtual environment:**
+
+ ```bash
+ # Using standard venv
+ python -m venv venv
+ source venv/bin/activate # On Windows: venv\Scripts\activate
+
+ # OR using uv (faster)
+ uv venv venv
+ source venv/bin/activate
+ ```
+
+3. **Install dependencies:**
+ ```bash
+ # Using pip
+ pip install -r requirements.txt
+
+ # OR using uv
+ uv install -r requirements.txt
+ ```
+
+4. **Create a .env file** in the project root:
+
+ ```
+ # Splunk AO Environment Variables
+ SPLUNK_AO_API_KEY=your-splunk-ao-api-key # Your Splunk AO API key.
+ SPLUNK_AO_PROJECT=your-splunk-ao-project-name # Your Splunk AO project name.
+ SPLUNK_AO_LOG_STREAM=weather_vibes_agent
+
+ # Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+ # SPLUNK_AO_CONSOLE_URL=your-splunk-ao-console-url # Optional if you are using a hosted version of Splunk AO
+
+ OPENAI_API_KEY=your_openai_key_here
+ WeatherAPI_KEY=your_weatherapi_key_here
+ YOUTUBE_API_KEY=your_youtube_key_here
+ ```
+
+## Understanding the Agent Architecture
+
+The Weather Vibes Agent consists of several key components:
+
+### 🧠 Agent Core (`agent/weather_vibes_agent.py`)
+Handles the main agent logic, coordinates tools, and processes requests.
+
+### 🛠️ Tools
+Specialized modules for specific tasks:
+- **Weather Tool (`tools/weather_tool.py`)**: Fetches weather data from WeatherAPI.com
+- **Recommendations Tool (`tools/recommendation_tool.py`)**: Generates weather-appropriate item suggestions
+- **YouTube Tool (`tools/youtube_tool.py`)**: Finds videos matching the weather mood
+
+### 📝 Descriptor (`descriptor.py`)
+Defines the agent's capabilities, inputs, outputs, and configuration.
+
+### 🔍 Instrumentation (`agent.py`)
+Wraps the agent with Splunk AO monitoring for observability.
+
+### 📑 Templates (`templates/`)
+Contains Jinja templates for generating system prompts.
+
+## Recipe 3: The Weather Tool
+
+Let's examine the Weather Tool to understand how it works and where Splunk AO fits in.
+
+**Key Ingredients:**
+- WeatherAPI.com
+- Async HTTP requests
+- Error handling
+- Response parsing
+
+**How it works:**
+
+1. **API Integration:**
+ The tool makes requests to the WeatherAPI.com to get current weather data.
+
+2. **Request Formatting:**
+ ```python
+ url = "http://api.weatherapi.com/v1/forecast.json"
+ params = {
+ "key": api_key,
+ "q": location,
+ "days": days,
+ "aqi": "yes",
+ "alerts": "yes"
+ }
+ ```
+
+3. **Response Processing:**
+ The tool extracts and formats relevant information from the API response:
+ ```python
+ current = data["current"]
+ location_data = data["location"]
+
+ return {
+ "location": location_data["name"],
+ "region": location_data["region"],
+ "country": location_data["country"],
+ "temperature_c": current["temp_c"],
+ "temperature_f": current["temp_f"],
+ "condition": current["condition"]["text"],
+ "condition_icon": current["condition"]["icon"],
+ "humidity": current["humidity"],
+ "wind_kph": current["wind_kph"],
+ "wind_mph": current["wind_mph"],
+ "wind_direction": current["wind_dir"],
+ "feels_like_c": current["feelslike_c"],
+ "feels_like_f": current["feelslike_f"],
+ "is_day": current["is_day"] == 1,
+ }
+ ```
+
+4. **Error Handling:**
+ The tool includes robust error handling to gracefully manage API failures.
+
+**Where Splunk AO Comes In:**
+The tool itself doesn't directly use Splunk AO. Instead, the main `agent.py` wraps the tool execution with Splunk AO's `@log` decorator:
+
+```python
+@log(span_type="tool", name="weather_tool")
+async def get_weather(weather_tool, location, days=1):
+ """Get weather data with Splunk AO tracing"""
+ result = await weather_tool.execute(location=location, days=days)
+ return result
+```
+
+This creates a span in Splunk AO that:
+- Captures the input location and days parameter
+- Records the tool's output
+- Measures execution time
+- Tracks any errors
+
+## Recipe 4: The Recommendations Tool
+
+This tool generates clothing and item recommendations based on weather conditions.
+
+**Key Ingredients:**
+- OpenAI API
+- Weather condition mapping
+- JSON response parsing
+
+**How it works:**
+
+1. **Prompt Engineering:**
+ The tool constructs a prompt for the LLM using the weather data:
+ ```python
+ prompt = (
+ f"Based on the following weather conditions:\n"
+ f"Location: {weather['location']}\n"
+ f"Temperature: {weather['temperature_c']}°C ({weather['temperature_f']}°F)\n"
+ f"Condition: {weather['condition']}\n"
+ f"Humidity: {weather['humidity']}%\n"
+ f"Wind Speed: {weather['wind_kph']} km/h ({weather['wind_mph']} mph)\n\n"
+ f"Recommend {max_items} items a person should bring or wear. "
+ f"Return just a simple list of items, no explanations."
+ )
+ ```
+
+2. **LLM Integration:**
+ The tool calls OpenAI's API to generate recommendations:
+ ```python
+ response = await self.client.chat.completions.create(
+ model=self.model,
+ messages=[{"role": "user", "content": prompt}],
+ temperature=0.7,
+ max_tokens=150
+ )
+ ```
+
+3. **Response Parsing:**
+ The tool processes the LLM's response to extract a clean list of recommendations.
+
+**Splunk AO Integration:**
+Similar to the Weather Tool, recommendations are traced with:
+
+```python
+@log(span_type="tool", name="recommendations_tool")
+async def get_recommendations(recommendations_tool, weather, max_items=5):
+ """Get recommendations with Splunk AO tracing"""
+ result = await recommendations_tool.execute(weather=weather, max_items=max_items)
+ return result
+```
+
+This allows you to analyze:
+- How different weather inputs affect recommendations
+- LLM response quality
+- Processing time
+
+## Recipe 5: The YouTube Tool
+
+This tool finds videos that match the current weather condition or mood.
+
+**Key Ingredients:**
+- YouTube Data API
+- Weather-to-mood mapping
+- Search query construction
+
+**How it works:**
+
+1. **Mood Mapping:**
+ The tool maps weather conditions to appropriate moods:
+ ```python
+ WEATHER_MOOD_MAP = {
+ "Clear": ["sunny", "bright", "cheerful"],
+ "Clouds": ["relaxing", "chill", "ambient"],
+ "Rain": ["rainy", "cozy", "relaxing"],
+ "Drizzle": ["light rain", "peaceful", "gentle"],
+ "Thunderstorm": ["dramatic", "intense", "powerful"],
+ "Snow": ["winter", "snowfall", "peaceful"],
+ "Mist": ["foggy", "mysterious", "calm"],
+ "Fog": ["atmospheric", "misty", "moody"],
+ }
+ ```
+
+2. **Query Construction:**
+ The tool builds a YouTube search query:
+ ```python
+ query = f"{mood} music {weather_condition.lower()} weather"
+ ```
+
+3. **API Integration:**
+ The tool searches YouTube and selects an appropriate video.
+
+**Splunk AO Integration:**
+Like the other tools, YouTube searches are traced with:
+
+```python
+@log(span_type="tool", name="youtube_tool")
+async def find_weather_video(youtube_tool, weather_condition, mood_override=None):
+ """Find YouTube videos with Splunk AO tracing"""
+ result = await youtube_tool.execute(
+ weather_condition=weather_condition,
+ mood_override=mood_override
+ )
+ return result
+```
+
+This helps you monitor:
+- YouTube API success rate
+- Query effectiveness
+- Response times
+
+## Recipe 6: Main Agent Workflow
+
+The main workflow in `agent.py` ties everything together and adds Splunk AO instrumentation.
+
+**Key Ingredients:**
+- Splunk AO context
+- Logging decorators
+- Workflow spans
+- Error handling
+
+**How it works:**
+
+1. **Setting Up the Context:**
+ ```python
+ with splunk_ao_context(log_stream=galileo_log_stream):
+ # Agent execution happens here
+ ```
+
+2. **Creating the Main Span:**
+ ```python
+ @log(span_type="workflow", name="weather_vibes_agent")
+ async def run_agent_with_inputs(location, units, mood, recommendations, verbose):
+ # Agent execution logic
+ ```
+
+3. **Creating the Workflow Span:**
+ ```python
+ @log(span_type="workflow", name="weather_vibes_workflow")
+ async def process_request(agent, request):
+ # Core workflow logic
+ ```
+
+4. **Tool Execution:**
+ Each tool call is wrapped with its own span.
+
+5. **Result Aggregation:**
+ Results from all tools are combined into a single response.
+
+**Splunk AO's Role:**
+Splunk AO creates a hierarchical trace structure:
+- The main workflow span contains the entire agent orchestration
+- The process workflow span tracks the main agent logic
+- Individual tool spans track specific operations
+- Metadata captures important context
+
+This lets you analyze the complete flow and identify bottlenecks or errors.
+
+## Recipe 7: Running the Agent
+
+Now that you understand how it all works, let's run the agent!
+
+**Steps:**
+
+1. **Basic Usage:**
+ ```bash
+ python agent.py "New York"
+ ```
+
+2. **Advanced Options:**
+ ```bash
+ python agent.py --location "Tokyo" --units imperial --mood relaxing --verbose
+ ```
+
+3. **Expected Output:**
+ You should see:
+ - Weather information for the specified location
+ - Recommendations based on the weather
+ - A YouTube video matching the weather mood
+ - Confirmation that Splunk AO traces have been collected
+
+## Recipe 8: Viewing Traces in Splunk AO
+
+Now it's time to see the results of our instrumentation in Splunk AO!
+
+**Steps:**
+
+1. **Log into Splunk AO:**
+ Visit [app.galileo.ai](https://app.galileo.ai) and log in.
+
+2. **View Your Traces:**
+ - Navigate to the Traces section
+ - Look for the `weather_vibes_agent` log stream
+ - Click on a recent trace
+
+3. **Explore the Hierarchy:**
+ You'll see a visualization showing:
+ - The main workflow span for agent orchestration
+ - The process workflow span
+ - Individual tool spans
+
+4. **Analyze Performance:**
+ In the trace view, you can:
+ - See the execution time for each component
+ - View the input and output data
+ - Identify any errors or warnings
+ - Compare multiple runs
+
+5. **Identify Optimization Opportunities:**
+ Look for:
+ - Slow API calls
+ - Bottlenecks in the workflow
+ - Error patterns
+ - Response quality issues
+
+## Recipe 9: Common Issues and Solutions
+
+Here are some problems you might encounter and how to fix them:
+
+### Import Errors
+
+**Problem:** `ModuleNotFoundError: No module named 'weather_vibes'`
+
+**Solution:**
+- Fix the imports in `agent/weather_vibes_agent.py`
+- Or create a symbolic link: `ln -s . weather_vibes`
+
+### API Key Issues
+
+**Problem:** "Invalid API key" errors
+
+**Solution:**
+- Double-check your `.env` file
+- For WeatherAPI.com, make sure you have signed up and confirmed your email
+- For YouTube, ensure the API is enabled in Google Cloud Console
+
+### Template Issues
+
+**Problem:** Jinja template errors
+
+**Solution:**
+```bash
+mkdir -p templates
+echo "You are a helpful weather agent." > templates/system.j2
+```
+
+### Splunk AO Connection Issues
+
+**Problem:** Traces aren't showing up in Splunk AO
+
+**Solution:**
+- Confirm your API key is valid
+- Check internet connectivity
+- Ensure `flush()` is being called at the end of execution
+
+## Recipe 10: Extending the Agent
+
+Want to make the Weather Vibes Agent even better? Here are some ideas:
+
+### Add New Tools
+
+Create a new tool file in the `tools/` directory:
+```python
+class ForecastTool:
+ async def execute(self, location, days=5):
+ # Implement 5-day forecast logic
+ pass
+```
+
+### Add More Instrumentation
+
+Add custom metrics to your Splunk AO spans:
+```python
+@log(span_type="tool", name="forecast_tool", metrics={"days_requested": days})
+async def get_forecast(forecast_tool, location, days=5):
+ result = await forecast_tool.execute(location=location, days=days)
+ return result
+```
+
+### Implement Caching
+
+Add caching to improve performance:
+```python
+class WeatherTool:
+ def __init__(self):
+ self.cache = {}
+
+ async def execute(self, location, units="metric"):
+ cache_key = f"{location}_{units}"
+ if cache_key in self.cache:
+ return self.cache[cache_key]
+ # Normal API call logic
+ self.cache[cache_key] = result
+ return result
+```
+
+## Conclusion
+
+You've now learned how to build, run, and monitor the Weather Vibes Agent with Splunk AO!
+
+**Key Takeaways:**
+- Multi-tool agents can combine various APIs into a unified experience
+- Proper error handling and modular design make agents more robust
+- Splunk AO observability provides valuable insights into agent performance
+- Well-structured tracing helps identify issues and optimization opportunities
+
+**Next Steps:**
+- Try adding new features to the agent
+- Experiment with different tracing approaches
+- Analyze your traces to identify performance improvements
+- Apply these patterns to your own AI applications
+
+Happy building!
\ No newline at end of file
diff --git a/examples/agent/weather-vibes-agent/__init__.py b/examples/agent/weather-vibes-agent/__init__.py
new file mode 100644
index 00000000..0232f23f
--- /dev/null
+++ b/examples/agent/weather-vibes-agent/__init__.py
@@ -0,0 +1,20 @@
+"""
+Weather Vibes Agent Package
+"""
+
+# Import the main agent class for easy access
+try:
+ from agent.weather_vibes_agent import WeatherVibesAgent
+except ImportError:
+ pass # Handle the case if the module isn't ready yet
+
+# Import tools for easy access
+try:
+ from tools.weather_tool import WeatherTool
+ from tools.recommendation_tool import RecommendationsTool
+ from tools.youtube_tool import YouTubeTool
+except ImportError:
+ pass # Handle the case if the tools aren't ready yet
+
+# Define what's available from this package
+__all__ = ["WeatherVibesAgent", "WeatherTool", "RecommendationsTool", "YouTubeTool"]
diff --git a/examples/agent/weather-vibes-agent/agent.py b/examples/agent/weather-vibes-agent/agent.py
new file mode 100644
index 00000000..371263f2
--- /dev/null
+++ b/examples/agent/weather-vibes-agent/agent.py
@@ -0,0 +1,259 @@
+#!/usr/bin/env python
+"""
+Splunk AO-instrumented Weather Vibes Agent.
+Adds tracing and logging for performance evaluation and debugging.
+
+Usage:
+ python galileo_agent.py [location]
+ python galileo_agent.py -l "Tokyo" -u imperial -m relaxing
+"""
+
+import asyncio
+import argparse
+import os
+import sys
+from pathlib import Path
+from dotenv import load_dotenv
+from splunk_ao import log, splunk_ao_context
+
+# Load environment variables & set up path
+load_dotenv()
+sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
+
+# Quick environment check
+required_keys = [
+ "OPENAI_API_KEY",
+ "WEATHERAPI_KEY",
+ "YOUTUBE_API_KEY",
+ "SPLUNK_AO_API_KEY",
+]
+if any(not os.getenv(key) for key in required_keys):
+ missing = [key for key in required_keys if not os.getenv(key)]
+ print(f"Missing API keys: {', '.join(missing)}")
+ print("Add them to your .env file or environment variables")
+ sys.exit(1)
+
+# Check for Splunk AO log stream
+galileo_log_stream = os.getenv("SPLUNK_AO_LOG_STREAM")
+if not galileo_log_stream:
+ print("Warning: SPLUNK_AO_LOG_STREAM environment variable not set.")
+ print("Using default log stream name.")
+ galileo_log_stream = "weather_vibes_agent"
+
+# Import the agent
+from agent.weather_vibes_agent import WeatherVibesAgent
+
+
+# Tool wrappers with Splunk AO instrumentation
+@log(span_type="tool", name="weather_tool")
+async def get_weather(weather_tool, location, days=1):
+ """Get weather data with Splunk AO tracing"""
+ result = await weather_tool.execute(location=location, days=days)
+ return result
+
+
+@log(span_type="tool", name="recommendations_tool")
+async def get_recommendations(recommendations_tool, weather, max_items=5):
+ """Get recommendations with Splunk AO tracing"""
+ result = await recommendations_tool.execute(weather=weather, max_items=max_items)
+ return result
+
+
+@log(span_type="tool", name="youtube_tool")
+async def find_weather_video(youtube_tool, weather_condition, mood_override=None):
+ """Find YouTube videos with Splunk AO tracing"""
+ result = await youtube_tool.execute(weather_condition=weather_condition, mood_override=mood_override)
+ return result
+
+
+@log(span_type="workflow", name="weather_vibes_workflow")
+async def process_request(agent, request):
+ """Main workflow with Splunk AO tracing"""
+ try:
+ # Extract request data
+ input_data = request.get("input", {})
+ config = request.get("config", {})
+ metadata = request.get("metadata", {})
+
+ # Parse parameters
+ location = input_data.get("location")
+ input_data.get("units", "metric")
+ verbose = config.get("verbose", False)
+ max_recommendations = config.get("max_recommendations", 5)
+ video_mood = config.get("video_mood")
+
+ # Validate location
+ if not location:
+ return {"error": 400, "message": "Location is required"}
+
+ # Update search history
+ if not hasattr(agent.state, "search_history"):
+ agent.state.search_history = []
+
+ if location not in agent.state.search_history:
+ agent.state.search_history.append(location)
+ if len(agent.state.search_history) > 5:
+ agent.state.search_history = agent.state.search_history[-5:]
+
+ # Execute tools
+ weather_result = await get_weather(agent.weather_tool, location, days=1)
+ if "error" in weather_result:
+ return {
+ "error": 500,
+ "message": f"Weather API error: {weather_result['message']}",
+ }
+
+ recommendations = await get_recommendations(agent.recommendations_tool, weather_result, max_recommendations)
+
+ video_result = await find_weather_video(agent.youtube_tool, weather_result["condition"], video_mood)
+
+ # Prepare response
+ result = {
+ "weather": weather_result,
+ "recommendations": recommendations,
+ "video": video_result,
+ }
+
+ # Filter weather details if not verbose
+ if not verbose and "weather" in result:
+ result["weather"] = {
+ "location": weather_result["location"],
+ "temperature_c": weather_result["temperature_c"],
+ "temperature_f": weather_result["temperature_f"],
+ "condition": weather_result["condition"],
+ "humidity": weather_result["humidity"],
+ "wind_kph": weather_result["wind_kph"],
+ }
+
+ # Build final response
+ response = {"output": result}
+ if "agent_id" in request:
+ response["agent_id"] = request["agent_id"]
+ if metadata:
+ response["metadata"] = metadata
+
+ return response
+
+ except Exception as e:
+ return {"error": 500, "message": f"Error: {str(e)}"}
+
+
+# Log the inputs using the Splunk AO decorator
+@log(span_type="workflow", name="weather_vibes_agent")
+async def run_agent_with_inputs(location, units, mood, recommendations, verbose):
+ """Run the agent with specific inputs logged via the decorator"""
+ print(f"Getting weather for: {location} (with Splunk AO tracing)")
+
+ # Create agent and request
+ agent = WeatherVibesAgent()
+ request = {
+ "input": {"location": location, "units": units},
+ "config": {
+ "verbose": verbose,
+ "max_recommendations": recommendations,
+ "video_mood": mood,
+ },
+ "metadata": {
+ "user_id": "demo_user",
+ "session_id": "demo_session",
+ "galileo_instrumented": True,
+ },
+ }
+
+ try:
+ response = await process_request(agent, request)
+
+ if "error" in response:
+ print(f"\n❌ Error: {response['message']}")
+ return
+
+ output = response["output"]
+ weather = output["weather"]
+ temp_unit = "°F" if units == "imperial" else "°C"
+ temp_key = "temperature_f" if units == "imperial" else "temperature_c"
+ wind_key = "wind_mph" if units == "imperial" else "wind_kph"
+ speed_unit = "mph" if units == "imperial" else "km/h"
+
+ # Display weather
+ print(f"\n🌤️ WEATHER FOR {weather['location']} 🌤️")
+ print(f"• Temperature: {weather.get(temp_key, weather.get('temperature_c'))}{temp_unit}")
+ print(f"• Condition: {weather['condition']}")
+ print(f"• Humidity: {weather['humidity']}%")
+ print(f"• Wind Speed: {weather.get(wind_key, weather.get('wind_kph'))} {speed_unit}")
+
+ if verbose and "feels_like_c" in weather:
+ feels_like_key = "feels_like_f" if units == "imperial" else "feels_like_c"
+ print(f"• Feels Like: {weather.get(feels_like_key)}{temp_unit}")
+ print(f"• Region: {weather.get('region', '')}")
+ print(f"• Country: {weather.get('country', '')}")
+
+ # Display recommendations
+ print("\n🧳 RECOMMENDATIONS:")
+ for item in output["recommendations"]:
+ print(f"• {item}")
+
+ # Display video
+ video = output["video"]
+ print("\n🎵 MATCHING VIDEO:")
+ if "error" in video:
+ print(f"• Couldn't find a video: {video.get('error')}")
+ else:
+ print(f"• {video['title']}")
+ print(f"• By: {video['channel']}")
+ print(f"• URL: {video['url']}")
+
+ print("\n📊 Splunk AO traces have been collected for this run")
+ print("View them in your Splunk AO dashboard")
+
+ except Exception as e:
+ print(f"Error: {e}")
+ import traceback
+
+ traceback.print_exc()
+
+
+# Use splunk_ao_context to set up the trace environment with further information
+async def main():
+ """Main entry point that uses splunk_ao_context to set up the trace environment"""
+ # Parse arguments
+ parser = argparse.ArgumentParser(description="Run the Splunk AO-instrumented Weather Vibes Agent")
+ parser.add_argument("location", nargs="?", help="Location (e.g., 'Tokyo')")
+ parser.add_argument(
+ "-l",
+ "--location",
+ dest="location_alt",
+ help="Alternative location specification",
+ )
+ parser.add_argument(
+ "-u",
+ "--units",
+ choices=["metric", "imperial"],
+ default="metric",
+ help="Units (metric/imperial)",
+ )
+ parser.add_argument("-m", "--mood", help="Video mood (e.g., 'relaxing', 'upbeat')")
+ parser.add_argument("-r", "--recommendations", type=int, default=5, help="Number of recommendations")
+ parser.add_argument("-v", "--verbose", action="store_true", help="Show detailed weather info")
+ args = parser.parse_args()
+
+ # Get location
+ location = args.location or args.location_alt
+ if not location:
+ location = input("Enter location (default: New York): ") or "New York"
+
+ # Use splunk_ao_context with the log stream from environment
+ with splunk_ao_context(log_stream=galileo_log_stream):
+ # Create a dictionary of inputs as metadata
+
+ # Run the agent with the wrapped function to log inputs
+ await run_agent_with_inputs(
+ location=location,
+ units=args.units,
+ mood=args.mood,
+ recommendations=args.recommendations,
+ verbose=args.verbose,
+ )
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/examples/agent/weather-vibes-agent/agent/__init__.py b/examples/agent/weather-vibes-agent/agent/__init__.py
new file mode 100644
index 00000000..d1cfb121
--- /dev/null
+++ b/examples/agent/weather-vibes-agent/agent/__init__.py
@@ -0,0 +1,13 @@
+"""
+Weather Vibes Agent package
+"""
+
+from .weather_vibes_agent import WeatherVibesAgent
+
+__all__ = ["WeatherVibesAgent"]
+
+# Make the descriptor easily importable
+try:
+ from .descriptor import WEATHER_VIBES_DESCRIPTOR as WEATHER_VIBES_DESCRIPTOR
+except ImportError:
+ pass # Handle the case if the file doesn't exist yet
diff --git a/examples/agent/weather-vibes-agent/agent/descriptor.py b/examples/agent/weather-vibes-agent/agent/descriptor.py
new file mode 100644
index 00000000..e13cb125
--- /dev/null
+++ b/examples/agent/weather-vibes-agent/agent/descriptor.py
@@ -0,0 +1,107 @@
+"""
+Agent ACP Descriptor for the Weather Vibes agent.
+This defines the agent's capabilities, inputs, outputs, and configuration.
+"""
+
+WEATHER_VIBES_DESCRIPTOR = {
+ "metadata": {
+ "ref": {
+ "name": "org.example.weathervibes",
+ "version": "0.1.0",
+ "url": "https://github.com/agntcy/agentic-apps/weather_vibes",
+ },
+ "description": "An agent that provides weather information, item recommendations, and matching YouTube videos.",
+ },
+ "specs": {
+ "capabilities": {
+ "threads": True,
+ "interrupts": False,
+ "callbacks": False,
+ "streaming": True,
+ },
+ "input": {
+ "type": "object",
+ "description": "Input for the Weather Vibes agent",
+ "properties": {
+ "location": {
+ "type": "string",
+ "description": "The location to get weather for (city name, zip code, etc.)",
+ },
+ "units": {
+ "type": "string",
+ "enum": ["metric", "imperial"],
+ "default": "metric",
+ "description": "Unit system for temperature and measurements",
+ },
+ },
+ "required": ["location"],
+ },
+ "output": {
+ "type": "object",
+ "description": "Weather Vibes agent output",
+ "properties": {
+ "weather": {
+ "type": "object",
+ "description": "Current weather information",
+ "properties": {
+ "location": {"type": "string"},
+ "temperature": {"type": "number"},
+ "condition": {"type": "string"},
+ "humidity": {"type": "number"},
+ "wind_speed": {"type": "number"},
+ },
+ },
+ "recommendations": {
+ "type": "array",
+ "description": "Items recommended to bring based on the weather",
+ "items": {"type": "string"},
+ },
+ "video": {
+ "type": "object",
+ "description": "A YouTube video matching the weather vibe",
+ "properties": {
+ "title": {"type": "string"},
+ "url": {"type": "string"},
+ "thumbnail": {"type": "string"},
+ },
+ },
+ },
+ },
+ "config": {
+ "type": "object",
+ "description": "Configuration for the Weather Vibes agent",
+ "properties": {
+ "verbose": {
+ "type": "boolean",
+ "default": False,
+ "description": "Whether to include detailed weather information",
+ },
+ "max_recommendations": {
+ "type": "integer",
+ "default": 5,
+ "description": "Maximum number of recommendations to provide",
+ },
+ "video_mood": {
+ "type": "string",
+ "description": "Optional mood override for video selection",
+ },
+ },
+ },
+ "thread_state": {
+ "type": "object",
+ "description": "Thread state for the Weather Vibes agent",
+ "properties": {
+ "search_history": {
+ "type": "array",
+ "description": "History of previously searched locations",
+ "items": {"type": "string"},
+ },
+ "favorite_locations": {
+ "type": "array",
+ "description": "User's favorite locations",
+ "items": {"type": "string"},
+ },
+ },
+ },
+ },
+}
diff --git a/examples/agent/weather-vibes-agent/agent/weather_vibes_agent.py b/examples/agent/weather-vibes-agent/agent/weather_vibes_agent.py
new file mode 100644
index 00000000..72c53e56
--- /dev/null
+++ b/examples/agent/weather-vibes-agent/agent/weather_vibes_agent.py
@@ -0,0 +1,277 @@
+"""
+Weather Vibes Agent implementation using the Simple Agent Framework.
+"""
+
+import os
+import json
+import logging
+import sys
+from pathlib import Path
+from typing import Dict, Any
+from jinja2 import Environment, FileSystemLoader
+
+from agent_framework.agent import Agent
+from agent_framework.state import AgentState
+from agent_framework.models import ToolMetadata
+from openai import OpenAI
+
+# Configure proper path for imports
+current_dir = Path(__file__).resolve().parent
+project_root = current_dir.parent
+sys.path.insert(0, str(project_root))
+
+# import tools
+from tools.weather_tool import WeatherTool
+from tools.recommendation_tool import RecommendationsTool
+from tools.youtube_tool import YouTubeTool
+from agent.descriptor import WEATHER_VIBES_DESCRIPTOR
+
+# Configure standard logging
+logger = logging.getLogger("weather_vibes_agent")
+
+
+# Add metadata class methods to tools to match the updated API
+def create_tool_metadata(name, description, tags=None):
+ @classmethod
+ def metadata(cls):
+ return ToolMetadata(
+ name=name,
+ description=description,
+ tags=tags or [],
+ input_schema={"type": "object", "properties": {}, "required": []},
+ output_schema={"type": "object", "properties": {}, "required": []},
+ )
+
+ return metadata
+
+
+# Add metadata method to the tool classes if they don't have it
+if not hasattr(WeatherTool, "metadata"):
+ WeatherTool.metadata = create_tool_metadata(
+ "get_weather",
+ "Get the current weather conditions for a location",
+ ["weather", "utility"],
+ )
+
+if not hasattr(RecommendationsTool, "metadata"):
+ RecommendationsTool.metadata = create_tool_metadata(
+ "get_recommendations",
+ "Get recommendations for items to bring based on weather conditions",
+ ["weather", "recommendations"],
+ )
+
+if not hasattr(YouTubeTool, "metadata"):
+ YouTubeTool.metadata = create_tool_metadata(
+ "find_weather_video",
+ "Find a YouTube video that matches the weather vibe",
+ ["youtube", "entertainment"],
+ )
+
+
+class WeatherVibesAgent(Agent):
+ """
+ Agent that provides weather information, recommendations, and matching videos.
+ Implements the Agent Connect Protocol (ACP) for standardized communication.
+ """
+
+ def __init__(self, agent_id: str = "weather_vibes"):
+ super().__init__(agent_id=agent_id)
+
+ # Initialize state - the API has changed, so we use direct assignment now
+ # Changed from self.state.set() to direct attribute assignment
+ self.state = AgentState()
+
+ # Default state initialization using direct attributes
+ # Instead of self.state.set("search_history", []), use:
+ if not hasattr(self.state, "search_history"):
+ self.state.search_history = []
+ if not hasattr(self.state, "favorite_locations"):
+ self.state.favorite_locations = []
+
+ # Set up template environment
+ template_dir = Path(__file__).parent.parent / "templates"
+ self.template_env = Environment(loader=FileSystemLoader(template_dir), trim_blocks=True, lstrip_blocks=True)
+
+ # Set up OpenAI client instead of OpenAIChat
+ self.client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
+
+ # Instead of AgentLogger, use standard Python logging
+ self.agent_id = agent_id
+ logger.info(f"Initialized WeatherVibesAgent with ID: {self.agent_id}")
+
+ # Initialize tool instances directly
+ self.weather_tool = None
+ self.recommendations_tool = None
+ self.youtube_tool = None
+
+ # Register tools
+ self._register_tools()
+
+ # Store descriptor
+ self.descriptor = WEATHER_VIBES_DESCRIPTOR
+
+ def _register_tools(self) -> None:
+ """Register agent-specific tools"""
+ # First, inspect what type of object tool_registry is
+ logger.info(f"Tool registry type: {type(self.tool_registry)}")
+
+ try:
+ # Create tool instances and store them directly
+ self.weather_tool = WeatherTool()
+ self.recommendations_tool = RecommendationsTool()
+ self.youtube_tool = YouTubeTool()
+
+ # Register tools with metadata and implementation
+ self.tool_registry.register(metadata=WeatherTool.metadata(), implementation=self.weather_tool)
+
+ self.tool_registry.register(
+ metadata=RecommendationsTool.metadata(),
+ implementation=self.recommendations_tool,
+ )
+
+ self.tool_registry.register(metadata=YouTubeTool.metadata(), implementation=self.youtube_tool)
+
+ logger.info("Tools registered successfully")
+
+ except Exception as e:
+ logger.error(f"Failed to register tools: {e}")
+ raise
+
+ async def _generate_system_prompt(self) -> str:
+ """Generate the system prompt using the template"""
+ template = self.template_env.get_template("system.j2")
+ return template.render(
+ search_history=getattr(self.state, "search_history", []),
+ favorite_locations=getattr(self.state, "favorite_locations", []),
+ )
+
+ async def _format_result(self, result: Any) -> Dict[str, Any]:
+ """
+ Format the result from processing.
+
+ This is an abstract method required by the Agent base class.
+ It formats the raw result into a standard structure.
+
+ Args:
+ result: The raw result from processing
+
+ Returns:
+ A formatted result dictionary
+ """
+ if isinstance(result, dict):
+ return result
+ elif hasattr(result, "model_dump"):
+ # Handle pydantic models
+ return result.model_dump()
+ elif hasattr(result, "__dict__"):
+ # Handle objects with __dict__
+ return result.__dict__
+ else:
+ # Default case
+ return {"result": str(result)}
+
+ async def get_acp_descriptor(self) -> Dict[str, Any]:
+ """
+ Return the ACP descriptor for this agent.
+ This implements the ACP agent discovery capability.
+ """
+ return self.descriptor
+
+ async def process_acp_request(self, request: Dict[str, Any]) -> Dict[str, Any]:
+ """
+ Process an ACP request and generate a response.
+ This implements the ACP run execution capability.
+
+ Args:
+ request: The ACP request payload
+
+ Returns:
+ An ACP response payload
+ """
+ # Replace AgentLogger methods with standard logging
+ logger.info(f"Processing ACP request: {json.dumps(request)[:100]}...")
+
+ try:
+ # Extract relevant information from the request
+ input_data = request.get("input", {})
+ config = request.get("config", {})
+ metadata = request.get("metadata", {})
+
+ # Parse input and config
+ location = input_data.get("location")
+ input_data.get("units", "metric")
+ verbose = config.get("verbose", False)
+ max_recommendations = config.get("max_recommendations", 5)
+ video_mood = config.get("video_mood")
+
+ # Validate input
+ if not location:
+ logger.error("Invalid input: 'location' field is required")
+ return {
+ "error": 400,
+ "message": "Invalid input: 'location' field is required",
+ }
+
+ # Update search history
+ if not hasattr(self.state, "search_history"):
+ self.state.search_history = []
+
+ if location not in self.state.search_history:
+ self.state.search_history.append(location)
+ # Keep only last 5 items
+ if len(self.state.search_history) > 5:
+ self.state.search_history = self.state.search_history[-5:]
+
+ # Step 1: Get weather information
+ logger.info(f"Getting weather for location: {location}")
+
+ weather_result = await self.weather_tool.execute(location=location, days=1)
+ if "error" in weather_result:
+ logger.error(f"Weather API error: {weather_result['message']}")
+ return {
+ "error": 500,
+ "message": f"Weather API error: {weather_result['message']}",
+ }
+
+ # Step 2: Get recommendations
+ logger.info("Getting recommendations based on weather")
+ recommendations = await self.recommendations_tool.execute(weather=weather_result, max_items=max_recommendations)
+
+ # Step 3: Get matching YouTube video
+ logger.info(f"Finding YouTube video matching weather condition: {weather_result['condition']}")
+ video_result = await self.youtube_tool.execute(weather_condition=weather_result["condition"], mood_override=video_mood)
+
+ # Prepare the response
+ result = {
+ "weather": weather_result,
+ "recommendations": recommendations,
+ "video": video_result,
+ }
+
+ # If not verbose, filter out some weather details
+ if not verbose and "weather" in result:
+ result["weather"] = {
+ "location": weather_result["location"],
+ "temperature_c": weather_result["temperature_c"],
+ "condition": weather_result["condition"],
+ "humidity": weather_result["humidity"],
+ "wind_kph": weather_result["wind_kph"],
+ }
+
+ # Format response according to ACP standards
+ response = {"output": result}
+
+ # Add the original agent_id to the response
+ if "agent_id" in request:
+ response["agent_id"] = request["agent_id"]
+
+ # Add metadata if present in the request
+ if metadata:
+ response["metadata"] = metadata
+
+ logger.info(f"Successfully processed request for location: {location}")
+ return response
+
+ except Exception as e:
+ logger.error(f"Error processing request: {str(e)}")
+ return {"error": 500, "message": f"Error processing request: {str(e)}"}
diff --git a/examples/agent/weather-vibes-agent/descriptor.py b/examples/agent/weather-vibes-agent/descriptor.py
new file mode 100644
index 00000000..d4bb37e0
--- /dev/null
+++ b/examples/agent/weather-vibes-agent/descriptor.py
@@ -0,0 +1,107 @@
+"""
+Agent Descriptor for the Weather Vibes agent.
+This defines the agent's capabilities, inputs, outputs, and configuration.
+"""
+
+WEATHER_VIBES_DESCRIPTOR = {
+ "metadata": {
+ "ref": {
+ "name": "org.example.weathervibes",
+ "version": "0.1.0",
+ "url": "https://github.com/agntcy/agentic-apps/weather_vibes",
+ },
+ "description": "An agent that provides weather information, item recommendations, and matching YouTube videos.",
+ },
+ "specs": {
+ "capabilities": {
+ "threads": True,
+ "interrupts": False,
+ "callbacks": False,
+ "streaming": True,
+ },
+ "input": {
+ "type": "object",
+ "description": "Input for the Weather Vibes agent",
+ "properties": {
+ "location": {
+ "type": "string",
+ "description": "The location to get weather for (city name, zip code, etc.)",
+ },
+ "units": {
+ "type": "string",
+ "enum": ["metric", "imperial"],
+ "default": "metric",
+ "description": "Unit system for temperature and measurements",
+ },
+ },
+ "required": ["location"],
+ },
+ "output": {
+ "type": "object",
+ "description": "Weather Vibes agent output",
+ "properties": {
+ "weather": {
+ "type": "object",
+ "description": "Current weather information",
+ "properties": {
+ "location": {"type": "string"},
+ "temperature": {"type": "number"},
+ "condition": {"type": "string"},
+ "humidity": {"type": "number"},
+ "wind_speed": {"type": "number"},
+ },
+ },
+ "recommendations": {
+ "type": "array",
+ "description": "Items recommended to bring based on the weather",
+ "items": {"type": "string"},
+ },
+ "video": {
+ "type": "object",
+ "description": "A YouTube video matching the weather vibe",
+ "properties": {
+ "title": {"type": "string"},
+ "url": {"type": "string"},
+ "thumbnail": {"type": "string"},
+ },
+ },
+ },
+ },
+ "config": {
+ "type": "object",
+ "description": "Configuration for the Weather Vibes agent",
+ "properties": {
+ "verbose": {
+ "type": "boolean",
+ "default": False,
+ "description": "Whether to include detailed weather information",
+ },
+ "max_recommendations": {
+ "type": "integer",
+ "default": 5,
+ "description": "Maximum number of recommendations to provide",
+ },
+ "video_mood": {
+ "type": "string",
+ "description": "Optional mood override for video selection",
+ },
+ },
+ },
+ "thread_state": {
+ "type": "object",
+ "description": "Thread state for the Weather Vibes agent",
+ "properties": {
+ "search_history": {
+ "type": "array",
+ "description": "History of previously searched locations",
+ "items": {"type": "string"},
+ },
+ "favorite_locations": {
+ "type": "array",
+ "description": "User's favorite locations",
+ "items": {"type": "string"},
+ },
+ },
+ },
+ },
+}
diff --git a/examples/agent/weather-vibes-agent/requirements.txt b/examples/agent/weather-vibes-agent/requirements.txt
new file mode 100644
index 00000000..8fbb9669
--- /dev/null
+++ b/examples/agent/weather-vibes-agent/requirements.txt
@@ -0,0 +1,20 @@
+# Core dependencies
+fastapi
+uvicorn
+python-dotenv
+jinja2
+pydantic
+rich>=13.0.0
+galileo
+
+# Direct OpenAI dependency instead of relying on Simple Agent Framework's LLM utility
+openai>=1.0.0
+
+# API integrations
+requests
+google-api-python-client
+
+# Simple Agent Framework
+# Comment out if causing issues and use direct OpenAI client instead
+git+https://github.com/rungalileo/simple-agent-framework.git@main
+
diff --git a/examples/agent/weather-vibes-agent/templates/system.j2 b/examples/agent/weather-vibes-agent/templates/system.j2
new file mode 100644
index 00000000..b99ae00f
--- /dev/null
+++ b/examples/agent/weather-vibes-agent/templates/system.j2
@@ -0,0 +1,31 @@
+You are the Weather Vibes assistant, an agent that helps users get weather information, item recommendations, and matching music.
+
+Your capabilities:
+1. Get current weather for any location
+2. Recommend items to bring based on weather conditions
+3. Find YouTube videos that match the weather "vibe"
+
+Search history:
+{% if search_history %}
+Recent locations:
+{% for location in search_history %}
+- {{ location }}
+{% endfor %}
+{% else %}
+No recent searches.
+{% endif %}
+
+{% if favorite_locations %}
+Favorite locations:
+{% for location in favorite_locations %}
+- {{ location }}
+{% endfor %}
+{% endif %}
+
+When providing recommendations, consider:
+- Temperature (cold, cool, warm, hot)
+- Precipitation (rain, snow, etc.)
+- Wind conditions
+- Time of day
+
+Be friendly, helpful, and practical in your recommendations.
\ No newline at end of file
diff --git a/examples/agent/weather-vibes-agent/tools/__init__.py b/examples/agent/weather-vibes-agent/tools/__init__.py
new file mode 100644
index 00000000..8fab87da
--- /dev/null
+++ b/examples/agent/weather-vibes-agent/tools/__init__.py
@@ -0,0 +1,5 @@
+from .weather_tool import WeatherTool
+from .recommendation_tool import RecommendationsTool
+from .youtube_tool import YouTubeTool
+
+__all__ = ["WeatherTool", "RecommendationsTool", "YouTubeTool"]
diff --git a/examples/agent/weather-vibes-agent/tools/recommendation_tool.py b/examples/agent/weather-vibes-agent/tools/recommendation_tool.py
new file mode 100644
index 00000000..7246353e
--- /dev/null
+++ b/examples/agent/weather-vibes-agent/tools/recommendation_tool.py
@@ -0,0 +1,87 @@
+"""
+Tool for generating item recommendations based on weather conditions.
+"""
+
+from typing import Dict, Any, List
+from pydantic import BaseModel
+from agent_framework.tools.base import BaseTool
+
+
+class RecommendationsInput(BaseModel):
+ """Input schema for recommendations tool"""
+
+ weather: Dict[str, Any]
+ max_items: int = 5
+
+
+class RecommendationsTool(BaseTool):
+ """Tool for generating weather-based recommendations"""
+
+ name = "get_recommendations"
+ description = "Get recommendations for items to bring based on weather conditions"
+ tags = ["weather", "recommendations"]
+ input_schema = RecommendationsInput.model_json_schema()
+
+ async def execute(self, weather: Dict[str, Any], max_items: int = 5) -> List[str]:
+ """
+ Execute the tool to get recommendations.
+
+ Args:
+ weather: Weather information dictionary
+ max_items: Maximum number of recommendations to provide
+
+ Returns:
+ List of recommended items
+ """
+ recommendations = []
+
+ # Basic recommendation logic based on weather conditions
+ condition = weather.get("condition", "").lower()
+ # Use temperature_c as primary, with fallback to other temperature fields
+ temp = weather.get("temperature_c", weather.get("temp_c", weather.get("temperature", 0)))
+
+ # Rain-related recommendations
+ if any(x in condition.lower() for x in ["rain", "drizzle", "shower", "precipitation", "wet"]):
+ recommendations.extend(["☔ Umbrella", "🧥 Raincoat"])
+
+ # Sun-related recommendations
+ if any(x in condition.lower() for x in ["clear", "sun", "sunny"]):
+ recommendations.extend(["🕶️ Sunglasses", "🧴 Sunscreen", "🧢 Cap"])
+
+ # Cloud-related recommendations
+ if any(x in condition.lower() for x in ["cloud", "overcast", "fog", "mist"]):
+ recommendations.extend(["🔦 Flashlight", "📸 Camera"])
+
+ # Snow-related recommendations
+ if any(x in condition.lower() for x in ["snow", "blizzard", "sleet", "ice"]):
+ recommendations.extend(["❄️ Snow boots", "🧤 Gloves", "⛄ Snow gear"])
+
+ # Temperature-based recommendations
+ if temp < 5: # Cold
+ recommendations.extend(["🧣 Scarf", "🧥 Heavy coat", "🔥 Hand warmers"])
+ elif temp < 15: # Cool
+ recommendations.extend(["👖 Jeans", "🧦 Warm socks", "🧥 Light jacket"])
+ elif temp < 25: # Warm
+ recommendations.extend(["👕 T-shirt", "🩳 Shorts", "🧴 Sunscreen"])
+ else: # Hot
+ recommendations.extend(["👙 Swimwear", "🌴 Water bottle", "🩴 Sandals"])
+
+ # Wind-related recommendations
+ wind_speed = weather.get("wind_kph", weather.get("wind_mph", weather.get("wind_speed", 0)))
+ if wind_speed > 20:
+ recommendations.extend(["🌬️ Windbreaker", "🪁 Hat with strap"])
+
+ # Humidity-based recommendations
+ humidity = weather.get("humidity", 0)
+ if humidity > 70:
+ recommendations.append("💦 Moisture-wicking clothes")
+
+ # Check for air quality if available
+ if "air_quality" in weather and isinstance(weather["air_quality"], dict):
+ aqi = weather["air_quality"].get("us-epa-index", 0)
+ if aqi > 3: # Moderate or worse air quality
+ recommendations.append("😷 Face mask")
+
+ # Return unique recommendations, limited to max_items
+ unique_recommendations = list(set(recommendations))
+ return unique_recommendations[:max_items]
diff --git a/examples/agent/weather-vibes-agent/tools/weather_tool.py b/examples/agent/weather-vibes-agent/tools/weather_tool.py
new file mode 100644
index 00000000..8dd9de0c
--- /dev/null
+++ b/examples/agent/weather-vibes-agent/tools/weather_tool.py
@@ -0,0 +1,102 @@
+"""
+Weather tool for fetching current weather conditions using WeatherAPI.com.
+"""
+
+import os
+from typing import Dict, Any
+from pydantic import BaseModel
+from agent_framework.tools.base import BaseTool
+import requests
+
+
+class WeatherInput(BaseModel):
+ """Input schema for the weather tool"""
+
+ location: str
+ days: int = 1
+
+
+class WeatherTool(BaseTool):
+ """Tool for fetching weather information"""
+
+ name = "get_weather"
+ description = "Get the current weather conditions for a location"
+ tags = ["weather", "utility"]
+ input_schema = WeatherInput.model_json_schema()
+
+ def __init__(self):
+ self.api_key = os.getenv("WEATHERAPI_KEY")
+ if not self.api_key:
+ raise ValueError("WeatherAPI.com API key not found in environment")
+ self.base_url = "http://api.weatherapi.com/v1/forecast.json"
+
+ async def execute(self, location: str, days: int = 1) -> Dict[str, Any]:
+ """
+ Execute the tool to get current weather and forecast.
+
+ Args:
+ location: The location to get weather for (city name, zip code, lat/long, etc.)
+ days: Number of days of forecast to include (1-7)
+
+ Returns:
+ Dictionary containing weather information
+ """
+ params = {
+ "key": self.api_key,
+ "q": location,
+ "days": days,
+ "aqi": "yes", # Include air quality data
+ "alerts": "yes", # Include weather alerts
+ }
+
+ try:
+ response = requests.get(self.base_url, params=params)
+ response.raise_for_status()
+ data = response.json()
+
+ # Extract relevant weather information
+ current = data["current"]
+ location_data = data["location"]
+
+ weather_info = {
+ "location": location_data["name"],
+ "region": location_data["region"],
+ "country": location_data["country"],
+ "temperature_c": current["temp_c"],
+ "temperature_f": current["temp_f"],
+ "condition": current["condition"]["text"],
+ "condition_icon": current["condition"]["icon"],
+ "humidity": current["humidity"],
+ "wind_kph": current["wind_kph"],
+ "wind_mph": current["wind_mph"],
+ "wind_direction": current["wind_dir"],
+ "feels_like_c": current["feelslike_c"],
+ "feels_like_f": current["feelslike_f"],
+ "is_day": current["is_day"] == 1,
+ }
+
+ # Add forecast information if requested
+ if days > 1 and "forecast" in data:
+ forecast_days = []
+ for day in data["forecast"]["forecastday"]:
+ forecast_days.append(
+ {
+ "date": day["date"],
+ "max_temp_c": day["day"]["maxtemp_c"],
+ "min_temp_c": day["day"]["mintemp_c"],
+ "condition": day["day"]["condition"]["text"],
+ "chance_of_rain": day["day"]["daily_chance_of_rain"],
+ }
+ )
+ weather_info["forecast"] = forecast_days
+
+ # Add alerts if available
+ if "alerts" in data and data["alerts"].get("alert"):
+ weather_info["alerts"] = data["alerts"]["alert"]
+
+ return weather_info
+ except Exception as e:
+ return {
+ "error": str(e),
+ "message": f"Failed to get weather for location: {location}",
+ }
diff --git a/examples/agent/weather-vibes-agent/tools/youtube_tool.py b/examples/agent/weather-vibes-agent/tools/youtube_tool.py
new file mode 100644
index 00000000..4c16dfce
--- /dev/null
+++ b/examples/agent/weather-vibes-agent/tools/youtube_tool.py
@@ -0,0 +1,92 @@
+"""
+Tool for finding YouTube videos that match the weather vibe.
+"""
+
+import os
+from typing import Dict, Any, Optional
+from pydantic import BaseModel
+from agent_framework.tools.base import BaseTool
+from googleapiclient.discovery import build
+
+
+class YouTubeInput(BaseModel):
+ """Input schema for YouTube tool"""
+
+ weather_condition: str
+ mood_override: Optional[str] = None
+
+
+class YouTubeTool(BaseTool):
+ """Tool for finding YouTube videos based on weather conditions"""
+
+ name = "find_weather_video"
+ description = "Find a YouTube video that matches the weather vibe"
+ tags = ["youtube", "entertainment"]
+ input_schema = YouTubeInput.model_json_schema()
+
+ def __init__(self):
+ self.api_key = os.getenv("YOUTUBE_API_KEY")
+ if not self.api_key:
+ raise ValueError("YouTube API key not found in environment")
+ self.youtube = build("youtube", "v3", developerKey=self.api_key)
+
+ async def execute(self, weather_condition: str, mood_override: Optional[str] = None) -> Dict[str, Any]:
+ """
+ Execute the tool to find a weather-matching YouTube video.
+
+ Args:
+ weather_condition: Current weather condition
+ mood_override: Optional mood to override search query
+
+ Returns:
+ Dictionary containing video information
+ """
+ try:
+ # Generate search query based on weather condition and optional mood
+ if mood_override:
+ query = f"{weather_condition} {mood_override} music"
+ else:
+ # Map weather conditions to vibes
+ vibe_mapping = {
+ "clear": "sunny day vibes music",
+ "sun": "sunny afternoon music",
+ "clouds": "cloudy day chill music",
+ "rain": "rainy day lofi music",
+ "drizzle": "light rain ambience",
+ "thunderstorm": "thunderstorm cozy music",
+ "snow": "snowy day peaceful music",
+ "mist": "foggy morning ambient music",
+ "fog": "foggy atmosphere music",
+ }
+
+ # Find the closest matching vibe
+ for condition_key, vibe_phrase in vibe_mapping.items():
+ if condition_key in weather_condition.lower():
+ query = vibe_phrase
+ break
+ else:
+ query = f"{weather_condition} music vibes"
+
+ # Execute search
+ search_response = self.youtube.search().list(q=query, part="snippet", maxResults=1, type="video").execute()
+
+ # Extract video information
+ if search_response.get("items"):
+ video = search_response["items"][0]
+ video_id = video["id"]["videoId"]
+
+ return {
+ "title": video["snippet"]["title"],
+ "url": f"https://www.youtube.com/watch?v={video_id}",
+ "thumbnail": video["snippet"]["thumbnails"]["high"]["url"],
+ "channel": video["snippet"]["channelTitle"],
+ "query": query,
+ }
+ else:
+ return {"error": "No videos found", "query": query}
+
+ except Exception as e:
+ return {
+ "error": str(e),
+ "message": "Failed to find a matching YouTube video",
+ }
diff --git a/examples/chatbot/basic-examples/.env.example b/examples/chatbot/basic-examples/.env.example
new file mode 100644
index 00000000..be283bf4
--- /dev/null
+++ b/examples/chatbot/basic-examples/.env.example
@@ -0,0 +1,10 @@
+# Galileo Environment Variables
+GALILEO_API_KEY=your-galileo-api-key # Your Galileo API key.
+GALILEO_PROJECT=your-galileo-project-name # Your Galileo project name.
+GALILEO_LOG_STREAM=your-galileo-log-stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# GALILEO_CONSOLE_URL=your-galileo-console-url # Optional if you are using a hosted version of Galileo
+
+OPENAI_API_KEY=your-openai-api-key
+OPENAI_ORGANIZATION=your-openai-organization
diff --git a/examples/chatbot/basic-examples/README.md b/examples/chatbot/basic-examples/README.md
new file mode 100644
index 00000000..43f051ff
--- /dev/null
+++ b/examples/chatbot/basic-examples/README.md
@@ -0,0 +1,158 @@
+# Splunk AO OpenAI Integration Examples
+
+This directory contains examples of how to use Splunk AO with OpenAI in two different ways:
+
+## 1. Using the Splunk AO OpenAI Wrapper (app.py)
+
+The `app.py` file demonstrates the simplest way to use Splunk AO with OpenAI by using the Splunk AO OpenAI wrapper:
+
+```python
+from splunk_ao import openai # The Splunk AO OpenAI client wrapper is all you need!
+
+# Initialize the client
+client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
+
+# Make API calls as usual
+response = client.chat.completions.create(
+ model="gpt-4o",
+ messages=[{"role": "system", "content": prompt}],
+)
+```
+
+With this approach, all OpenAI API calls are automatically logged to Splunk AO without any additional code. This is the simplest way to integrate Splunk AO into your application.
+
+## 2. Using the Standard OpenAI Library with SplunkAOLogger (test.py)
+
+The `test.py` file demonstrates how to use the standard OpenAI library directly while manually logging to Splunk AO using the `SplunkAOLogger` class:
+
+```python
+import openai # Standard OpenAI library
+from splunk_ao import SplunkAOLogger # Import SplunkAOLogger for logging
+
+# Initialize the logger
+logger = SplunkAOLogger(project="chatbot", log_stream="test")
+
+# Initialize the standard OpenAI client
+client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
+
+# Start a trace
+trace = logger.start_trace(input=prompt)
+
+# Record the start time
+start_time = time.time_ns()
+
+# Make the OpenAI API call directly
+response = client.chat.completions.create(
+ model="gpt-4o",
+ messages=[{"role": "system", "content": prompt}],
+)
+
+# Record the end time
+end_time = time.time_ns()
+
+# Log the LLM call as a span
+logger.add_llm_span(
+ input=prompt,
+ output=response.choices[0].message.content.strip(),
+ model="gpt-4o",
+ duration_ns=end_time - start_time,
+ num_input_tokens=response.usage.prompt_tokens,
+ num_output_tokens=response.usage.completion_tokens,
+ total_tokens=response.usage.total_tokens
+)
+
+# Conclude the trace
+logger.conclude(output=response.choices[0].message.content.strip())
+
+# Flush the traces to Splunk AO
+logger.flush()
+```
+
+This approach gives you more control over what gets logged and when, allowing you to:
+
+1. Create custom traces and spans
+2. Add additional metadata to your traces
+3. Log only specific API calls
+4. Integrate with other parts of your application
+
+## When to Use Each Approach
+
+- **Use the Splunk AO OpenAI wrapper** when you want a simple drop-in replacement for the OpenAI library with automatic logging.
+- **Use the standard OpenAI library with SplunkAOLogger** when you need more control over logging or want to integrate Splunk AO with other parts of your application.
+
+## Running the Examples
+
+To run the examples, you'll need to:
+
+1. Install the required packages:
+ ```
+ pip install openai galileo python-dotenv
+ ```
+
+2. Set up your environment variables in a `.env` file:
+ ```
+ # Splunk AO Environment Variables
+ SPLUNK_AO_API_KEY=your-splunk-ao-api-key # Your Splunk AO API key.
+ SPLUNK_AO_PROJECT=your-splunk-ao-project-name # Your Splunk AO project name.
+ SPLUNK_AO_LOG_STREAM=your-splunk-ao-log-stream # The name of the log stream you want to use for logging.
+
+ # Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+ # SPLUNK_AO_CONSOLE_URL=your-splunk-ao-console-url # Optional if you are using a hosted version of Splunk AO
+
+ OPENAI_API_KEY=your_openai_api_key
+ OPENAI_ORGANIZATION=your_openai_organization # Optional
+ ```
+
+3. Run the examples:
+ ```
+ python app.py # For the Splunk AO OpenAI wrapper example
+ python test.py # For the standard OpenAI library with SplunkAOLogger example
+ ```
+
+## Hallucination Demonstration
+
+This project includes a demonstration of hallucinations in LLMs and techniques to prevent them.
+
+### What are Hallucinations?
+
+Hallucinations occur when an AI model generates factually incorrect information that is not grounded in any real-world knowledge. These are sometimes called "open-domain factual errors" and can significantly impact the reliability of your AI system.
+
+### Running the Hallucination Demo
+
+To run the hallucination demonstration:
+
+```bash
+python hallucination.py
+```
+
+This program will:
+
+1. Ask a series of questions that might lead to hallucinations
+2. Generate responses using different system prompts:
+ - Unconstrained: No specific instructions about factual accuracy
+ - Constrained: Explicit instructions to avoid speculation and guessing
+ - RAG Simulation: Simulates a retrieval-augmented generation approach with a limited knowledge base
+
+3. Use another LLM as a judge to evaluate whether hallucinations occurred in each response
+4. Demonstrate solutions to prevent hallucinations:
+ - Explicitly instructing the model to avoid guessing
+ - Adding response validation
+ - Using retrieval-augmented generation (RAG)
+ - Implementing post-processing checks
+
+### Metrics Used to Evaluate Hallucinations
+
+The judge model evaluates responses on:
+- Factual Accuracy: Whether statements are verifiably false
+- Speculation: Whether speculation is presented as fact
+- Uncertainty Handling: Whether uncertainty is appropriately expressed
+- Citation Needs: Whether claims that should be cited are cited
+
+Each response receives a hallucination score from 0-10, where 0 means no hallucination and 10 means completely hallucinated.
+
+### Solutions to Prevent Hallucinations
+
+1. **Explicitly Instruct the Model**: Add clear instructions in your system prompt to avoid guessing and speculation.
+2. **Response Validation**: Implement automated validation using a judge model or other techniques.
+3. **Retrieval-Augmented Generation (RAG)**: Ground responses in verified sources.
+4. **Post-Processing Checks**: Run additional checks for factual accuracy before serving responses.
\ No newline at end of file
diff --git a/examples/chatbot/basic-examples/app.py b/examples/chatbot/basic-examples/app.py
new file mode 100644
index 00000000..35f8b5a8
--- /dev/null
+++ b/examples/chatbot/basic-examples/app.py
@@ -0,0 +1,19 @@
+import os
+from splunk_ao import openai # The Splunk AO OpenAI client wrapper is all you need!
+
+from dotenv import load_dotenv
+
+load_dotenv()
+
+client = openai.OpenAI(
+ api_key=os.environ.get("OPENAI_API_KEY"),
+ organization=os.environ.get("OPENAI_ORGANIZATION"),
+)
+
+prompt = "Explain the following topic succinctly: Newton's First Law"
+response = client.chat.completions.create(
+ model="gpt-4o",
+ messages=[{"role": "system", "content": prompt}],
+)
+
+print(response.choices[0].message.content.strip())
diff --git a/examples/chatbot/basic-examples/context.py b/examples/chatbot/basic-examples/context.py
new file mode 100644
index 00000000..b7a168fb
--- /dev/null
+++ b/examples/chatbot/basic-examples/context.py
@@ -0,0 +1,19 @@
+import os
+
+from splunk_ao import splunk_ao_context, openai
+
+# If you've set your SPLUNK_AO_PROJECT and SPLUNK_AO_LOG_STREAM env vars, you can skip this step
+splunk_ao_context.init(project="your-project-id", log_stream="your-log-stream-id")
+
+# Initialize the Splunk AO wrapped OpenAI client
+client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
+
+
+def call_openai():
+ chat_completion = client.chat.completions.create(messages=[{"role": "user", "content": "Say this is a test"}], model="gpt-4o")
+
+ return chat_completion.choices[0].message.content
+
+
+# This will create a single span trace with the OpenAI call
+call_openai()
diff --git a/examples/chatbot/basic-examples/hallucination.py b/examples/chatbot/basic-examples/hallucination.py
new file mode 100644
index 00000000..053d98f8
--- /dev/null
+++ b/examples/chatbot/basic-examples/hallucination.py
@@ -0,0 +1,106 @@
+import os
+import json
+import time
+import openai # Using the standard OpenAI library
+from splunk_ao import SplunkAOLogger # Import SplunkAOLogger for logging
+from dotenv import load_dotenv
+
+load_dotenv()
+
+# Initialize the SplunkAOLogger
+logger = SplunkAOLogger(project="hallucination", log_stream="dev")
+
+# Initialize the standard OpenAI client
+client = openai.OpenAI(
+ api_key=os.environ.get("OPENAI_API_KEY"),
+ organization=os.environ.get("OPENAI_ORGANIZATION"),
+)
+
+# Questions that might lead to hallucinations
+QUESTIONS = [
+ "What is inside a black hole?",
+ "What will life be like in 100 years?",
+ "What was the score of the last Lakers game?",
+]
+
+# Different system prompts to test hallucination prevention
+SYSTEM_PROMPTS = {"unconstrained": "You are a helpful assistant. Answer the user's questions."}
+
+
+def generate_response(question: str, system_prompt: str) -> str:
+ """Generate a response using the OpenAI API with the given system prompt."""
+ # Record the start time for the LLM call
+ start_time = time.time_ns()
+
+ response = client.chat.completions.create(
+ model="gpt-4o",
+ messages=[
+ {"role": "system", "content": system_prompt},
+ {"role": "user", "content": question},
+ ],
+ )
+
+ # Record the end time for the LLM call
+ end_time = time.time_ns()
+
+ response_content = response.choices[0].message.content.strip()
+
+ # Log the LLM call as a span
+ logger.add_llm_span(
+ input=f"System: {system_prompt}\nUser: {question}",
+ output=response_content,
+ model="gpt-4o",
+ duration_ns=end_time - start_time,
+ num_input_tokens=response.usage.prompt_tokens,
+ num_output_tokens=response.usage.completion_tokens,
+ total_tokens=response.usage.total_tokens,
+ )
+
+ return response_content
+
+
+def run_hallucination_demo():
+ """Run the hallucination demonstration with different prompts and questions."""
+ results = []
+
+ for question in QUESTIONS:
+ # Start a trace for this question
+ logger.start_trace(input=question)
+
+ question_results = {"question": question, "responses": []}
+
+ print(f"\n\n{'='*80}\nQUESTION: {question}\n{'='*80}")
+
+ for prompt_name, system_prompt in SYSTEM_PROMPTS.items():
+ # Generate response
+ response = generate_response(question, system_prompt)
+
+ # Store results
+ question_results["responses"].append({"prompt_type": prompt_name, "response": response})
+
+ # Print results for this question
+ print(f"\n--- PROMPT TYPE: {prompt_name} ---")
+ print(f"RESPONSE: {response}")
+
+ results.append(question_results)
+
+ # Conclude the trace with a summary of responses
+ summary = {
+ "question": question,
+ "responses": {k: v["response"] for k, v in enumerate(question_results["responses"])},
+ }
+ logger.conclude(output=json.dumps(summary))
+
+ return results
+
+
+if __name__ == "__main__":
+ print("HALLUCINATION DEMONSTRATION PROGRAM")
+ print("This program demonstrates how LLMs can hallucinate and how to prevent it.")
+ print("It shows different prompting strategies to reduce hallucinations.")
+
+ # Run the main demonstration
+ results = run_hallucination_demo()
+
+ # Flush the traces to Splunk AO
+ logger.flush()
diff --git a/examples/chatbot/basic-examples/package-lock.json b/examples/chatbot/basic-examples/package-lock.json
new file mode 100644
index 00000000..6c51b889
--- /dev/null
+++ b/examples/chatbot/basic-examples/package-lock.json
@@ -0,0 +1,1042 @@
+{
+ "name": "chatbot",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "dependencies": {
+ "galileo": "^1.2.0"
+ }
+ },
+ "node_modules/@cfworker/json-schema": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/@cfworker/json-schema/-/json-schema-4.1.1.tgz",
+ "integrity": "sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/@langchain/core": {
+ "version": "0.3.42",
+ "resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.3.42.tgz",
+ "integrity": "sha512-pT/jC5lqWK3YGDq8dQwgKoa6anqAhMtG1x5JbnrOj9NdaLeBbCKBDQ+/Ykzk3nZ8o+0UMsaXNZo7IVL83VVjHg==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@cfworker/json-schema": "^4.0.2",
+ "ansi-styles": "^5.0.0",
+ "camelcase": "6",
+ "decamelize": "1.2.0",
+ "js-tiktoken": "^1.0.12",
+ "langsmith": ">=0.2.8 <0.4.0",
+ "mustache": "^4.2.0",
+ "p-queue": "^6.6.2",
+ "p-retry": "4",
+ "uuid": "^10.0.0",
+ "zod": "^3.22.4",
+ "zod-to-json-schema": "^3.22.3"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@langchain/openai": {
+ "version": "0.3.17",
+ "resolved": "https://registry.npmjs.org/@langchain/openai/-/openai-0.3.17.tgz",
+ "integrity": "sha512-uw4po32OKptVjq+CYHrumgbfh4NuD7LqyE+ZgqY9I/LrLc6bHLMc+sisHmI17vgek0K/yqtarI0alPJbzrwyag==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "js-tiktoken": "^1.0.12",
+ "openai": "^4.77.0",
+ "zod": "^3.22.4",
+ "zod-to-json-schema": "^3.22.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@langchain/core": ">=0.3.29 <0.4.0"
+ }
+ },
+ "node_modules/@rungalileo/galileo": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@rungalileo/galileo/-/galileo-1.3.0.tgz",
+ "integrity": "sha512-vciDkfMOP/BMZDspz5LpEdGuy5FsTzTmX/FADApJzKNZ5b+Y2DLZNiyfg4/EEbcVjEkQv0uKsfU89tqwY8EK1g==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "axios": "^1.6.7",
+ "form-data": "^4.0.1",
+ "jsonwebtoken": "^9.0.2",
+ "openapi-fetch": "^0.13.3",
+ "openapi-typescript-helpers": "^0.0.15"
+ },
+ "optionalDependencies": {
+ "@langchain/core": "^0.3.13",
+ "@langchain/openai": "^0.3.11",
+ "tiktoken": "^1.0.13"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "18.19.80",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.80.tgz",
+ "integrity": "sha512-kEWeMwMeIvxYkeg1gTc01awpwLbfMRZXdIhwRcakd/KlK53jmRC26LqcbIt7fnAQTu5GzlnWmzA3H6+l1u6xxQ==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "undici-types": "~5.26.4"
+ }
+ },
+ "node_modules/@types/node-fetch": {
+ "version": "2.6.12",
+ "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz",
+ "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@types/node": "*",
+ "form-data": "^4.0.0"
+ }
+ },
+ "node_modules/@types/retry": {
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
+ "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/@types/uuid": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz",
+ "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/abort-controller": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+ "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "event-target-shim": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=6.5"
+ }
+ },
+ "node_modules/agentkeepalive": {
+ "version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz",
+ "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "humanize-ms": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 8.0.0"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+ "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
+ "license": "MIT"
+ },
+ "node_modules/axios": {
+ "version": "1.8.3",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.3.tgz",
+ "integrity": "sha512-iP4DebzoNlP/YN2dpwCgb8zoCmhtkajzS48JvwmkSkXvPI3DHc7m+XYL5tGnSlJtR6nImXZmdCuN5aP8dh1d8A==",
+ "license": "MIT",
+ "dependencies": {
+ "follow-redirects": "^1.15.6",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/call-bind-apply-helpers": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
+ "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/camelcase": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
+ "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chalk/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "license": "MIT",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/console-table-printer": {
+ "version": "2.12.1",
+ "resolved": "https://registry.npmjs.org/console-table-printer/-/console-table-printer-2.12.1.tgz",
+ "integrity": "sha512-wKGOQRRvdnd89pCeH96e2Fn4wkbenSP6LMHfjfyNLMbGuHEFbMqQNuxXqd0oXG9caIOQ1FTvc5Uijp9/4jujnQ==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "simple-wcswidth": "^1.0.1"
+ }
+ },
+ "node_modules/decamelize": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
+ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/dunder-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
+ "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-object-atoms": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
+ "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-set-tostringtag": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
+ "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/event-target-shim": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+ "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/eventemitter3": {
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/follow-redirects": {
+ "version": "1.15.9",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
+ "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/RubenVerborgh"
+ }
+ ],
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.0"
+ },
+ "peerDependenciesMeta": {
+ "debug": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/form-data": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz",
+ "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==",
+ "license": "MIT",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "es-set-tostringtag": "^2.1.0",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/form-data-encoder": {
+ "version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz",
+ "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/formdata-node": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz",
+ "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "node-domexception": "1.0.0",
+ "web-streams-polyfill": "4.0.0-beta.3"
+ },
+ "engines": {
+ "node": ">= 12.20"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/galileo": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/galileo/-/galileo-1.2.0.tgz",
+ "integrity": "sha512-Zfs/NNsrR+gaG/iQFCibLvHi04dZyo3xYdg8ZpJHUV/xDYJcLVj1G6HBfsCzNaxNHkHmircL4ZrgmO0vFZCZBg==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@rungalileo/galileo": "^1.2.0"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "es-define-property": "^1.0.1",
+ "es-errors": "^1.3.0",
+ "es-object-atoms": "^1.1.1",
+ "function-bind": "^1.1.2",
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "hasown": "^2.0.2",
+ "math-intrinsics": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-proto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/humanize-ms": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
+ "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "ms": "^2.0.0"
+ }
+ },
+ "node_modules/js-tiktoken": {
+ "version": "1.0.19",
+ "resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.19.tgz",
+ "integrity": "sha512-XC63YQeEcS47Y53gg950xiZ4IWmkfMe4p2V9OSaBt26q+p47WHn18izuXzSclCI73B7yGqtfRsT6jcZQI0y08g==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "base64-js": "^1.5.1"
+ }
+ },
+ "node_modules/jsonwebtoken": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
+ "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
+ "license": "MIT",
+ "dependencies": {
+ "jws": "^3.2.2",
+ "lodash.includes": "^4.3.0",
+ "lodash.isboolean": "^3.0.3",
+ "lodash.isinteger": "^4.0.4",
+ "lodash.isnumber": "^3.0.3",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.isstring": "^4.0.1",
+ "lodash.once": "^4.0.0",
+ "ms": "^2.1.1",
+ "semver": "^7.5.4"
+ },
+ "engines": {
+ "node": ">=12",
+ "npm": ">=6"
+ }
+ },
+ "node_modules/jwa": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
+ "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer-equal-constant-time": "1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/jws": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+ "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+ "license": "MIT",
+ "dependencies": {
+ "jwa": "^1.4.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/langsmith": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/langsmith/-/langsmith-0.3.13.tgz",
+ "integrity": "sha512-iI5MO5FP1EFxU1jyQvB2cM4qKqXXwnsd124MKWWhBuV2O/EjdwzsyKPBVlBPFjAQbgCGtzqdJWbv9xld60hb+Q==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@types/uuid": "^10.0.0",
+ "chalk": "^4.1.2",
+ "console-table-printer": "^2.12.1",
+ "p-queue": "^6.6.2",
+ "p-retry": "4",
+ "semver": "^7.6.3",
+ "uuid": "^10.0.0"
+ },
+ "peerDependencies": {
+ "openai": "*"
+ },
+ "peerDependenciesMeta": {
+ "openai": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/lodash.includes": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+ "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isboolean": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+ "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isinteger": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+ "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isnumber": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+ "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.isstring": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
+ "license": "MIT"
+ },
+ "node_modules/lodash.once": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
+ "license": "MIT"
+ },
+ "node_modules/math-intrinsics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
+ "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "license": "MIT"
+ },
+ "node_modules/mustache": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz",
+ "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==",
+ "license": "MIT",
+ "optional": true,
+ "bin": {
+ "mustache": "bin/mustache"
+ }
+ },
+ "node_modules/node-domexception": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
+ "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/jimmywarting"
+ },
+ {
+ "type": "github",
+ "url": "https://paypal.me/jimmywarting"
+ }
+ ],
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=10.5.0"
+ }
+ },
+ "node_modules/node-fetch": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+ "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/openai": {
+ "version": "4.87.3",
+ "resolved": "https://registry.npmjs.org/openai/-/openai-4.87.3.tgz",
+ "integrity": "sha512-d2D54fzMuBYTxMW8wcNmhT1rYKcTfMJ8t+4KjH2KtvYenygITiGBgHoIrzHwnDQWW+C5oCA+ikIR2jgPCFqcKQ==",
+ "license": "Apache-2.0",
+ "optional": true,
+ "dependencies": {
+ "@types/node": "^18.11.18",
+ "@types/node-fetch": "^2.6.4",
+ "abort-controller": "^3.0.0",
+ "agentkeepalive": "^4.2.1",
+ "form-data-encoder": "1.7.2",
+ "formdata-node": "^4.3.2",
+ "node-fetch": "^2.6.7"
+ },
+ "bin": {
+ "openai": "bin/cli"
+ },
+ "peerDependencies": {
+ "ws": "^8.18.0",
+ "zod": "^3.23.8"
+ },
+ "peerDependenciesMeta": {
+ "ws": {
+ "optional": true
+ },
+ "zod": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/openapi-fetch": {
+ "version": "0.13.4",
+ "resolved": "https://registry.npmjs.org/openapi-fetch/-/openapi-fetch-0.13.4.tgz",
+ "integrity": "sha512-JHX7UYjLEiHuQGCPxa3CCCIqe/nc4bTIF9c4UYVC8BegAbWoS3g4gJxKX5XcG7UtYQs2060kY6DH64KkvNZahg==",
+ "license": "MIT",
+ "dependencies": {
+ "openapi-typescript-helpers": "^0.0.15"
+ }
+ },
+ "node_modules/openapi-typescript-helpers": {
+ "version": "0.0.15",
+ "resolved": "https://registry.npmjs.org/openapi-typescript-helpers/-/openapi-typescript-helpers-0.0.15.tgz",
+ "integrity": "sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw==",
+ "license": "MIT"
+ },
+ "node_modules/p-finally": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+ "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/p-queue": {
+ "version": "6.6.2",
+ "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz",
+ "integrity": "sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "eventemitter3": "^4.0.4",
+ "p-timeout": "^3.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-retry": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz",
+ "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@types/retry": "0.12.0",
+ "retry": "^0.13.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/p-timeout": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz",
+ "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "p-finally": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/proxy-from-env": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
+ "license": "MIT"
+ },
+ "node_modules/retry": {
+ "version": "0.13.1",
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
+ "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "7.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
+ "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/simple-wcswidth": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/simple-wcswidth/-/simple-wcswidth-1.0.1.tgz",
+ "integrity": "sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/tiktoken": {
+ "version": "1.0.20",
+ "resolved": "https://registry.npmjs.org/tiktoken/-/tiktoken-1.0.20.tgz",
+ "integrity": "sha512-zVIpXp84kth/Ni2me1uYlJgl2RZ2EjxwDaWLeDY/s6fZiyO9n1QoTOM5P7ZSYfToPvAvwYNMbg5LETVYVKyzfQ==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/undici-types": {
+ "version": "5.26.5",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+ "license": "MIT",
+ "optional": true
+ },
+ "node_modules/uuid": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz",
+ "integrity": "sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==",
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
+ "node_modules/web-streams-polyfill": {
+ "version": "4.0.0-beta.3",
+ "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz",
+ "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+ "license": "BSD-2-Clause",
+ "optional": true
+ },
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
+ "node_modules/zod": {
+ "version": "3.24.2",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz",
+ "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==",
+ "license": "MIT",
+ "optional": true,
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
+ },
+ "node_modules/zod-to-json-schema": {
+ "version": "3.24.3",
+ "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.3.tgz",
+ "integrity": "sha512-HIAfWdYIt1sssHfYZFCXp4rU1w2r8hVVXYIlmoa0r0gABLs5di3RCqPU5DDROogVz1pAdYBaz7HK5n9pSUNs3A==",
+ "license": "ISC",
+ "optional": true,
+ "peerDependencies": {
+ "zod": "^3.24.1"
+ }
+ }
+ }
+}
diff --git a/examples/chatbot/basic-examples/package.json b/examples/chatbot/basic-examples/package.json
new file mode 100644
index 00000000..a99e7745
--- /dev/null
+++ b/examples/chatbot/basic-examples/package.json
@@ -0,0 +1,5 @@
+{
+ "dependencies": {
+ "galileo": "^1.2.0"
+ }
+}
diff --git a/examples/chatbot/basic-examples/requirements.txt b/examples/chatbot/basic-examples/requirements.txt
new file mode 100644
index 00000000..092ade76
--- /dev/null
+++ b/examples/chatbot/basic-examples/requirements.txt
@@ -0,0 +1,3 @@
+galileo==0.0.7
+openai==1.61.1
+pydantic==2.10.6
\ No newline at end of file
diff --git a/examples/chatbot/basic-examples/test.py b/examples/chatbot/basic-examples/test.py
new file mode 100644
index 00000000..2b03d9d8
--- /dev/null
+++ b/examples/chatbot/basic-examples/test.py
@@ -0,0 +1,61 @@
+import os
+import time
+import openai # Using the standard OpenAI library
+from splunk_ao import SplunkAOLogger # Import SplunkAOLogger for logging
+
+from dotenv import load_dotenv
+
+load_dotenv()
+
+# Initialize the SplunkAOLogger
+logger = SplunkAOLogger(project="chatbot", log_stream="test")
+
+# Initialize the standard OpenAI client
+client = openai.OpenAI(
+ api_key=os.environ.get("OPENAI_API_KEY"),
+ organization=os.environ.get("OPENAI_ORGANIZATION"),
+)
+
+# Start a trace
+# prompt = f"Explain the following topic succinctly: Newton's First Law"
+prompt = """
+ 1. Explain Newton's First Law in one sentence of no more than fifteen (15) words.
+ 2. Do not add any additional sentences, examples, parentheses, bullet points, or further clarifications.
+ 3. Your answer must be exactly one sentence and must not exceed 15 words.
+"""
+trace = logger.start_trace(input=prompt)
+
+# Record the start time for the LLM call
+start_time = time.time_ns()
+
+# Make the OpenAI API call directly
+response = client.chat.completions.create(
+ model="gpt-4o",
+ messages=[{"role": "system", "content": prompt}],
+)
+
+# Record the end time for the LLM call
+end_time = time.time_ns()
+
+# Get the response content
+response_content = response.choices[0].message.content.strip()
+
+# Log the LLM call as a span
+logger.add_llm_span(
+ input=prompt,
+ output=response_content,
+ model="gpt-4o",
+ duration_ns=end_time - start_time,
+ num_input_tokens=response.usage.prompt_tokens,
+ num_output_tokens=response.usage.completion_tokens,
+ total_tokens=response.usage.total_tokens,
+)
+
+# Conclude the trace
+logger.conclude(output=response_content)
+
+# Flush the traces to Splunk AO
+logger.flush()
+
+# Print the response
+print(response_content)
diff --git a/examples/chatbot/elevenlabs-chatbot/.env.example b/examples/chatbot/elevenlabs-chatbot/.env.example
new file mode 100644
index 00000000..6a1f7f41
--- /dev/null
+++ b/examples/chatbot/elevenlabs-chatbot/.env.example
@@ -0,0 +1,7 @@
+# Galileo Configuration
+GALILEO_API_KEY=your-galileo-api-key
+GALILEO_PROJECT_NAME=elevenlabs-voice-poc
+GALILEO_LOG_STREAM=voice-chatbot
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# GALILEO_CONSOLE_URL=your-galileo-console-url # Optional if you are using a hosted version of Galileo
\ No newline at end of file
diff --git a/examples/chatbot/elevenlabs-chatbot/README.md b/examples/chatbot/elevenlabs-chatbot/README.md
new file mode 100644
index 00000000..5860d939
--- /dev/null
+++ b/examples/chatbot/elevenlabs-chatbot/README.md
@@ -0,0 +1,71 @@
+# ElevenLabs Voice Chatbot with Splunk AO
+
+> **Note:** This example has been tested on macOS only.
+
+A terminal-based voice chatbot that lets you have real-time voice conversations with an ElevenLabs AI agent, with conversation logging and tracing via Splunk AO.
+
+## What This Example Shows
+
+- Interactive voice chat in your terminal (speak via microphone, hear responses via speakers)
+- Conversation logging and tracing with Splunk AO
+- Session tracking with turn counts
+- Integration pattern for logging voice-based AI interactions
+
+## Quick Start
+
+1. Install system dependencies (macOS):
+
+ ```bash
+ brew install portaudio
+ ```
+
+2. Create and activate a virtual environment:
+
+ ```bash
+ python -m venv venv
+ source venv/bin/activate # On Windows: venv\Scripts\activate
+ ```
+
+3. Install Python dependencies:
+
+ ```bash
+ pip install -r requirements.txt
+ ```
+
+4. Set up environment variables:
+
+ ```bash
+ cp .env.example .env
+ # Edit .env with your API keys
+ ```
+
+5. Run the voice chat:
+
+ ```bash
+ python main.py
+ ```
+
+ For best results use a headset with microphone. The app will start listening through your microphone. Speak to chat with the AI agent and hear responses through your speakers. Press `Ctrl+C` to end the session.
+
+## Configuration
+
+Edit `.env` with your credentials. Note for `ELEVENLABS_*` variables you can [signup with a free tier](https://elevenlabs.io/app/sign-up?platform=agents) of ElevenLabs and use their Agents Platform to create a voice agent to obtain the required API key and Agent Id:
+
+| Variable | Description |
+| ---------------------- | ------------------------------ |
+| `ELEVENLABS_API_KEY` | Your ElevenLabs API key |
+| `ELEVENLABS_AGENT_ID` | Your ElevenLabs Agent ID |
+| `SPLUNK_AO_API_KEY` | Your Splunk AO API key |
+| `SPLUNK_AO_CONSOLE_URL` | Splunk AO console URL (optional) |
+| `SPLUNK_AO_PROJECT` | Project name for logging |
+
+## Requirements
+
+- Python 3.10+
+- Microphone and headphones (to avoid audio feedback)
+
+## Learn More
+
+- [Video tutorial](https://youtu.be/1QNEhDV2r5U)
+- [Splunk AO Documentation](https://docs.galileo.ai/what-is-galileo)
+- [ElevenLabs Conversational AI](https://elevenlabs.io/docs/conversational-ai)
diff --git a/examples/chatbot/elevenlabs-chatbot/main.py b/examples/chatbot/elevenlabs-chatbot/main.py
new file mode 100644
index 00000000..d83a84c3
--- /dev/null
+++ b/examples/chatbot/elevenlabs-chatbot/main.py
@@ -0,0 +1,135 @@
+"""ElevenLabs Voice Chatbot with Splunk AO Logging
+
+A tutorial example showing how to:
+1. Set up a real-time voice conversation with ElevenLabs Conversational AI
+2. Log conversation turns to Splunk AO for observability and tracing
+
+Prerequisites:
+- macOS with portaudio installed (brew install portaudio)
+- ElevenLabs API key and Agent ID
+- Splunk AO API key and project configured
+"""
+
+import os
+import uuid
+from pathlib import Path
+
+from dotenv import load_dotenv
+
+# Load environment variables from .env file
+env_path = Path(__file__).parent / ".env"
+load_dotenv(env_path)
+
+# ElevenLabs SDK for voice conversations
+from elevenlabs.client import ElevenLabs
+from elevenlabs.conversational_ai.conversation import Conversation
+from elevenlabs.conversational_ai.default_audio_interface import DefaultAudioInterface
+
+# Splunk AO handler for logging and tracing
+from splunk_ao_handler import get_splunk_ao_handler
+
+# =============================================================================
+# ELEVENLABS CONVERSATION CALLBACKS
+# =============================================================================
+#
+# ElevenLabs Conversational AI uses callbacks to notify your app when
+# events occur during the conversation:
+# - User speaks and their speech is transcribed
+# - Agent generates and speaks a response
+#
+# We use these callbacks to log each turn to Splunk AO.
+# =============================================================================
+
+
+def on_agent_response(response: str) -> None:
+ """Called when the ElevenLabs agent responds.
+
+ This callback fires after the agent generates a response.
+ We log this to Splunk AO to complete the conversation turn trace.
+ """
+ print(f"\n[AGENT] {response}")
+
+ splunk_ao = get_splunk_ao_handler()
+ splunk_ao.log_agent_turn(response)
+
+
+def on_user_transcript(transcript: str) -> None:
+ """Called when user speech is transcribed.
+
+ This callback fires after your speech is converted to text.
+ We log this to Splunk AO to start a new conversation turn trace.
+ """
+ print(f"\n[USER] {transcript}")
+
+ splunk_ao = get_splunk_ao_handler()
+ splunk_ao.log_user_turn(transcript)
+
+
+# =============================================================================
+# MAIN CONVERSATION LOOP
+# =============================================================================
+
+
+def run_voice_conversation():
+ """Run a voice conversation with ElevenLabs + Splunk AO logging.
+
+ This function:
+ 1. Initializes the ElevenLabs client and Splunk AO logger
+ 2. Creates a conversation with audio input/output
+ 3. Runs until the user presses Ctrl+C
+ 4. Logs all turns to Splunk AO for observability
+ """
+ # Load ElevenLabs credentials from environment
+ elevenlabs_api_key = os.getenv("ELEVENLABS_API_KEY")
+ elevenlabs_agent_id = os.getenv("ELEVENLABS_AGENT_ID")
+
+ if not elevenlabs_api_key or not elevenlabs_agent_id:
+ print("Error: ELEVENLABS_API_KEY and ELEVENLABS_AGENT_ID must be set in .env")
+ return
+
+ # Initialize ElevenLabs client with your API key
+ client = ElevenLabs(api_key=elevenlabs_api_key)
+
+ # Initialize Splunk AO and start a new session
+ splunk_ao = get_splunk_ao_handler()
+ session_id = str(uuid.uuid4())
+ splunk_ao.start_conversation(session_id)
+
+ print("\n" + "=" * 60)
+ print("ElevenLabs Voice Chatbot + Splunk AO Logging")
+ print(f"Session ID: {session_id}")
+ print("*** USE HEADPHONES to avoid audio feedback loop ***")
+ print("Speak into your microphone to talk to the agent")
+ print("Press Ctrl+C to end the session")
+ print("=" * 60 + "\n")
+
+ # Create the ElevenLabs conversation
+ # - DefaultAudioInterface() handles microphone input and speaker output
+ # - Callbacks connect events to our Splunk AO logging functions
+ conversation = Conversation(
+ client=client,
+ agent_id=elevenlabs_agent_id,
+ requires_auth=True,
+ audio_interface=DefaultAudioInterface(),
+ callback_agent_response=on_agent_response,
+ callback_user_transcript=on_user_transcript,
+ )
+
+ # Start the conversation (this begins listening)
+ print("[INFO] Starting conversation... Speak now!")
+ conversation.start_session()
+
+ # wait for the conversation to end (blocks until Ctrl+C or session ends)
+ try:
+ conversation.wait_for_session_end()
+ except KeyboardInterrupt:
+ print("\n[INFO] Ending conversation...")
+ conversation.end_session()
+
+ # End the Splunk AO session and flush remaining logs
+ splunk_ao.end_conversation()
+ print("[INFO] Conversation ended - logs sent to Splunk AO")
+
+
+if __name__ == "__main__":
+ run_voice_conversation()
diff --git a/examples/chatbot/elevenlabs-chatbot/pyproject.toml b/examples/chatbot/elevenlabs-chatbot/pyproject.toml
new file mode 100644
index 00000000..fb88e646
--- /dev/null
+++ b/examples/chatbot/elevenlabs-chatbot/pyproject.toml
@@ -0,0 +1,18 @@
+[project]
+name = "elevenlabs-chatbot"
+version = "0.1.0"
+description = "ElevenLabs Voice Chatbot with Splunk AO logging and tracing"
+requires-python = ">=3.9"
+dependencies = [
+ "python-dotenv>=1.0.0",
+ "elevenlabs>=1.0.0",
+ "galileo>=1.34.0",
+ "pyaudio>=0.2.14",
+]
+
+[project.scripts]
+voice-chatbot = "main:run_voice_conversation"
+
+[build-system]
+requires = ["setuptools>=61.0"]
+build-backend = "setuptools.build_meta"
diff --git a/examples/chatbot/elevenlabs-chatbot/requirements.txt b/examples/chatbot/elevenlabs-chatbot/requirements.txt
new file mode 100644
index 00000000..e912b148
--- /dev/null
+++ b/examples/chatbot/elevenlabs-chatbot/requirements.txt
@@ -0,0 +1,4 @@
+python-dotenv>=1.0.0
+elevenlabs>=1.0.0
+galileo>=1.34.0
+pyaudio>=0.2.14
diff --git a/examples/chatbot/elevenlabs-chatbot/splunk_ao_handler.py b/examples/chatbot/elevenlabs-chatbot/splunk_ao_handler.py
new file mode 100644
index 00000000..a50b4215
--- /dev/null
+++ b/examples/chatbot/elevenlabs-chatbot/splunk_ao_handler.py
@@ -0,0 +1,135 @@
+"""Splunk AO Handler for ElevenLabs Voice Chatbot
+
+Provides observability for AI applications by capturing:
+- Sessions: Group related conversations (e.g., a user's chat session)
+- Traces: Individual request-response cycles within a session
+- Spans: Detailed steps within a trace (e.g., LLM calls, tool use)
+
+This allows you to monitor conversation quality, debug issues, and
+analyze patterns in your AI application.
+"""
+
+import os
+from typing import Optional
+
+from splunk_ao import SplunkAOLogger, Message, MessageRole
+
+
+class SplunkAOHandler:
+ """Handles Splunk AO logging for voice conversations.
+
+ Captures each conversation turn (user speech -> agent response) as a trace,
+ with the LLM interaction logged as a span within that trace.
+ """
+
+ def __init__(self):
+ self._logger: Optional[SplunkAOLogger] = None
+ self._session_id: Optional[str] = None
+ self._turn_count = 0
+
+ # Load Splunk AO config from environment
+ self._project_name = os.getenv("SPLUNK_AO_PROJECT", "elevenlabs-voice-poc")
+ self._log_stream = os.getenv("SPLUNK_AO_LOG_STREAM", "voice-chatbot")
+
+ self._init_logger()
+
+ def _init_logger(self):
+ """Initialize the Splunk AO Logger.
+
+ The logger connects to a specific project and log stream in Splunk AO.
+ Log streams help organize logs by environment (dev, staging, prod)
+ or by feature area.
+ """
+ try:
+ self._logger = SplunkAOLogger(
+ project=self._project_name,
+ log_stream=self._log_stream,
+ )
+ print(f"[SPLUNK_AO] Logger initialized for project: {self._project_name}")
+ except Exception as e:
+ print(f"[SPLUNK_AO] Logger init failed: {e}")
+
+ def start_conversation(self, session_id: str):
+ """Start a new conversation session in Splunk AO.
+
+ A session groups all the turns of a single conversation together,
+ making it easy to view the full conversation history in the Splunk AO UI.
+ """
+ self._session_id = session_id
+ self._turn_count = 0
+
+ if self._logger:
+ # external_id links this session to your own session tracking
+ self._logger.start_session(name=f"Voice-{session_id[:8]}", external_id=session_id)
+ print(f"[SPLUNK_AO] Started session: {session_id[:8]}")
+
+ def log_user_turn(self, transcript: str) -> None:
+ """Log when the user speaks.
+
+ This starts a new trace for this conversation turn.
+ The trace captures the full request-response cycle.
+ """
+ self._turn_count += 1
+ self._last_user_input = transcript
+
+ if self._logger:
+ try:
+ # Each turn gets its own trace for clear organization
+ self._logger.start_trace(input=transcript, name=f"Turn-{self._turn_count}")
+ except Exception as e:
+ print(f"[SPLUNK_AO] Trace start error: {e}")
+
+ def log_agent_turn(self, response: str) -> None:
+ """Log when the agent responds.
+
+ This adds an LLM span to capture the model interaction,
+ then concludes the trace with the final output.
+ """
+ if self._logger:
+ try:
+ user_input = getattr(self, "_last_user_input", "")
+
+ # Log the LLM interaction as a span
+ # Even though ElevenLabs handles the actual LLM call,
+ # we log it here for visibility into the conversation flow
+ self._logger.add_llm_span(
+ input=user_input,
+ output=Message(content=response, role=MessageRole.assistant),
+ model="elevenlabs-agent",
+ )
+
+ # Conclude the trace with the final response
+ self._logger.conclude(output=response)
+
+ # Flush to send logs to Splunk AO immediately
+ self._logger.flush()
+ except Exception as e:
+ print(f"[SPLUNK_AO] Logging error: {e}")
+
+ def end_conversation(self):
+ """End the conversation session and cleanup.
+
+ Ensures all logs are flushed and the session is properly closed.
+ """
+ if self._logger:
+ try:
+ self._logger.flush()
+ self._logger.clear_session()
+ print(f"[SPLUNK_AO] Session ended ({self._turn_count} turns)")
+ except Exception as e:
+ print(f"[SPLUNK_AO] Cleanup error: {e}")
+
+ self._session_id = None
+ self._turn_count = 0
+
+
+# Singleton instance for the Splunk AO handler
+_splunk_ao_handler: Optional[SplunkAOHandler] = None
+
+
+def get_splunk_ao_handler() -> SplunkAOHandler:
+ """Get or create the Splunk AO handler singleton."""
+ global _splunk_ao_handler
+ if _splunk_ao_handler is None:
+ _splunk_ao_handler = SplunkAOHandler()
+ return _splunk_ao_handler
diff --git a/examples/chatbot/sample-project-chatbot/README.md b/examples/chatbot/sample-project-chatbot/README.md
new file mode 100644
index 00000000..0004af61
--- /dev/null
+++ b/examples/chatbot/sample-project-chatbot/README.md
@@ -0,0 +1,19 @@
+# Basic Chatbot Example - Python
+
+This folder contains aa set of basic chatbot examples that are functionally identical, but using different LLMs:
+
+| LLM. | Project | Notes |
+| :-------------- | :--------------------------------------- | :---- |
+| OpenAI/Ollama. | [./openai-ollama](./openai-ollama/) | This works with any OpenAI SDK compatible LLM, including Ollama running locally |
+| Azure Inference | [./azure-inference](./azure-inference/) | This works with models deployed to Azure AI foundry via the Azure Inference API |
+| Anthropic | [./anthropic](./anthropic/) | |
+
+Navigate to the different folders for instructions on how to set them up and run the projects.
+
+These example Python projects show how to create a basic terminal-based chatbot to interact with an LLM, with all interactions logged to Splunk AO. You can use this to:
+
+- Interact with a choice of LLMs
+- See traces logged to Splunk AO
+- Measure the correctness of the responses
+
+This project also has a unit test that runs the chatbot using the Splunk AO experiments functionality to unit test your system prompt and model combination.
diff --git a/examples/chatbot/sample-project-chatbot/anthropic/.env.example b/examples/chatbot/sample-project-chatbot/anthropic/.env.example
new file mode 100644
index 00000000..9d0a0897
--- /dev/null
+++ b/examples/chatbot/sample-project-chatbot/anthropic/.env.example
@@ -0,0 +1,11 @@
+# Galileo Environment Variables
+GALILEO_API_KEY= # Your Galileo API key.
+GALILEO_PROJECT=Simple Chatbot # Your Galileo project name.
+GALILEO_LOG_STREAM=Default Log Stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# GALILEO_CONSOLE_URL= # Optional if you are using a hosted version of Galileo
+
+# Anthropic Environment Variables
+ANTHROPIC_API_KEY= # Your Anthropic API key if you are using an Anthropic model
+MODEL_NAME= # The name of the model you want to use. For example, claude-3-7-sonnet-latest
diff --git a/examples/chatbot/sample-project-chatbot/anthropic/README.md b/examples/chatbot/sample-project-chatbot/anthropic/README.md
new file mode 100644
index 00000000..1c37a024
--- /dev/null
+++ b/examples/chatbot/sample-project-chatbot/anthropic/README.md
@@ -0,0 +1,132 @@
+# Basic Chatbot Example - Python/Anthropic
+
+This example Python project shows how to create a basic terminal-based chatbot to interact with an Anthropic LLM, with all interactions logged to Splunk AO. You can use this to:
+
+- Interact with a choice of Anthropic model
+- See traces logged to Splunk AO
+- Measure the correctness of the responses
+
+This project also has a unit test that runs the chatbot using the Splunk AO experiments functionality to unit test your system prompt and model combination.
+
+## Prerequisites
+
+To run this project you will need:
+
+- Python 3.10 or higher installed
+- An Anthropic API key
+- A [Splunk AO account](https://app.galileo.ai/sign-up) with a project and Log stream set up
+
+## Set up
+
+To set up this project:
+
+### Install the required packages
+
+1. Install the required Python dependencies in a virtual environment from the requirements.txt file:
+
+ ```bash
+ pip install -r requirements.txt
+ ```
+
+### Set up the environment
+
+1. Create a `.env` file by copying the `.env.example` file.
+
+1. Fill in the required values for the Splunk AO environment variables in the `.env` file:
+ - `SPLUNK_AO_API_KEY` - Set this to your Splunk AO API key
+ - `SPLUNK_AO_PROJECT` - Set this to your Splunk AO Project name
+ - `SPLUNK_AO_LOG_STREAM` - Set this to your Splunk AO Log stream name
+
+ There are also some optional values:
+ - `SPLUNK_AO_CONSOLE_URL` - If you are using a hosted version of Splunk AO, set the console URL here. For the free version, remove or comment out this value
+
+1. Fill in the required values for your LLM in the `.env` file:
+ - Set `ANTHROPIC_API_KEY` to your Anthropic API key
+ - Set `MODEL_NAME` to the name of the model you want to use.
+
+## Run the chatbot
+
+To run the chatbot, run the `app.py` file inside your virtual environment:
+
+```bash
+python app.py
+```
+
+You can then ask questions of the LLM, and see the response:
+
+```output
+You: Which are the Galilean moons?
+The Galilean moons are the four largest moons of Jupiter, discovered by Galileo Galilei in 1610. They are:
+
+1. **Io** - The innermost moon, known for its intense volcanic activity and numerous volcanoes.
+2. **Europa** - Notable for its smooth icy surface, which is believed to cover an ocean of liquid water beneath, making it a subject of interest for the search for extraterrestrial life.
+3. **Ganymede** - The largest moon in the solar system, larger than the planet Mercury, and has its own magnetic field.
+4. **Callisto** - The most heavily cratered body in the solar system, it is an ancient moon that has remained relatively unchanged over billions of years.
+
+These moons are significant for their unique geological features and potential for supporting life.
+```
+
+## Evaluate the chatbot
+
+Every run of the app is logged as a new session in Splunk AO, with each prompt and response a separate trace.
+
+To evaluate the chatbot, head to your project and Log stream in the Splunk AO console. Turn on [instruction adherence](https://docs.galileo.ai/concepts/metrics/response-quality/instruction-adherence) and [correctness](https://docs.galileo.ai/concepts/metrics/response-quality/correctness) for your Log stream.
+
+Then when you run the chatbot, these metrics will be evaluated.
+
+### Use the metrics to improve the chatbot
+
+This chatbot has been set up to be helpful, and possible too helpful! The current system prompt is:
+
+> You are a knowledgeable and confident assistant. Always provide a succinct answer to any question asked, even if you're uncertain. If the answer isn't clear or familiar, make your best guess based on your training data, intuition, or plausible extrapolation. Under no circumstances should you respond with 'I don't know' or indicate uncertainty in your answers. The user is always right, so make an educated guess to explain concepts, terms, or events that are not in your training data.
+
+This prompt makes the LLM very helpful, but does lead it to hallucinate. For example, if you ask about something that doesn't exist, you will probably get a confident response:
+
+```output
+You: Describe the running of the hippopotamus festival in Spain.
+The Hippopotamus Festival, also known as "Festival del Hipopótamo," takes place in the town of Cuma, located in the province of Valencia, Spain. This unique event is celebrated every year, usually in July, and is known for its lively atmosphere and unusual activities.
+
+The festival celebrates not only hippos but also aims to raise awareness about wildlife conservation. Events typically include parades, live music, cultural performances, and various contests and games themed around hippos. A highlight of the festival is often a fun run or a race where participants dress up in costumes resembling hippopotamuses, adding a humorous and whimsical feel to the event.
+
+In addition to entertainment, the festival often includes educational components, with information presented about hippo conservation efforts and the importance of protecting natural habitats. Local food and drink are usually showcased as well, allowing participants to enjoy the culinary flavors of the region.
+
+Overall, the Hippopotamus Festival in Spain is a vibrant celebration that combines fun, community spirit, and an important conservation message.
+```
+
+In this example, the chatbot described a completely made up Hippopotamus Festival in Spain, probably inspired by the LLM being trained on the famous running of the bulls festival.
+
+If you check the metrics for this response, you will see a very low correctness score:
+
+
+
+To improve the chatbot, you could tweak the system prompt to avoid making things up. In the `app.py` file is the suggestion:
+
+> You are a helpful assistant that can answer questions and provide information. If you don't know the answer, say "I don't know" instead of making up an answer. Do not under any circumstances make up an answer.
+
+Try changing the system prompt to this and run the chatbot again.
+
+```output
+You: Describe the running of the hippopotamus festival in Spain.
+I don't know.
+```
+
+## Unit tests
+
+This project also includes a unit test to run the chatbot with a set of defined prompts, evaluating the prompts for instruction adherence and correctness, only passing the test if both metrics score an average of 100% over all the entries in the dataset.
+
+This is run using the Splunk AO experiments framework - allowing you to run any code as an experiment against a fixed dataset of prompts. This mechanism allows you to run AI applications, from simple to complex, under test conditions with a defined set of inputs. You can then use the results of evaluations run against your app to help with model selection or prompt engineering, as well as validating your application as part of a CI/CD pipeline.
+
+You can run the unit test by running the following command inside your virtual environment:
+
+```bash
+python -m pytest test.py
+```
+
+This will run the single test which will:
+
+- Look in your project for a dataset, creating it if it doesn't exist
+- Call the chatbot inside a call to `run_experiment`, passing each row from the dataset in as inputs
+- Poll the experiment until it has finished and the metrics are calculated
+- Check that all the metrics return 100%, failing if they do not
+
+To see this unit test in action, run it with the original system prompt, which should make the test fail. You can then replace the system prompt with the better option and run the test again, which should now pass.
diff --git a/examples/chatbot/sample-project-chatbot/anthropic/app.py b/examples/chatbot/sample-project-chatbot/anthropic/app.py
new file mode 100644
index 00000000..0b5b7128
--- /dev/null
+++ b/examples/chatbot/sample-project-chatbot/anthropic/app.py
@@ -0,0 +1,193 @@
+"""
+This file contains a very basic chatbot application to converse with an LLM
+through your terminal.
+
+All interactions are logged to Splunk AO. The structure is:
+
+- A session is started at the beginning of the application,
+ so every interaction is logged in the same session.
+- For every message sent by the user, a new trace is started
+- Each call to the function that interacts with the LLM is logged
+ as a workflow span
+- The call to the LLM is logged manually as an LLM span.
+- After the response is received, the trace is concluded with the response
+ and flushed to ensure it is sent to Splunk AO.
+
+To run this, you will need to have the following environment variables set:
+- `SPLUNK_AO_API_KEY`: Your Splunk AO API key.
+- `SPLUNK_AO_PROJECT`: The name of your Splunk AO project.
+- `SPLUNK_AO_CONSOLE_URL`: Optional. Your Splunk AO console URL for custom deployments.
+ If you are using the free version, do not set this.
+
+Set the following environment variable for your LLM:
+- `ANTHROPIC_API_KEY`: Your Anthropic API key.
+- `MODEL_NAME`: The name of the model you want to use.
+
+"""
+
+from datetime import datetime
+import os
+
+from anthropic import Anthropic
+
+from dotenv import load_dotenv
+
+from splunk_ao import splunk_ao_context, log
+
+# Load the environment variables from the .env file
+# This will override any existing environment variables with the same name
+load_dotenv(override=True)
+
+# Set the model name from the environment variable
+# If this is not set, raise an exception
+MODEL_NAME = os.environ["MODEL_NAME"]
+
+# Start a new session named using the current date and time
+# This way every time you run the application, it will create a new session in Splunk AO
+# with the entire conversation inside the same session, with each message back and forth
+# logged as different traces within that session.
+SESSION_NAME = f"LLM Chatbot session - {datetime.now().isoformat()}"
+splunk_ao_context.start_session(SESSION_NAME)
+
+
+# Create a collection of messages with a system prompt
+# The default system prompt encourages the assistant to be helpful, but can lead to hallucinations.
+chat_history = [
+ {
+ "role": "system",
+ "content": """
+ You are a knowledgeable and confident assistant. Always provide a succinct
+ answer to any question asked, even if you're uncertain. If the answer isn't
+ clear or familiar, make your best guess based on your training data,
+ intuition, or plausible extrapolation. Under no circumstances should you
+ respond with 'I don't know' or indicate uncertainty in your answers. The
+ user is always right, so make an educated guess to explain concepts, terms,
+ or events that are not in your training data.
+ """,
+ # This default system prompt can lead to hallucinations, so you might want to change it.
+ # For example, you could use a more restrictive prompt like:
+ # """
+ # You are a helpful assistant that can answer questions and provide information.
+ # If you don't know the answer, say "I don't know" instead of making up an answer.
+ # Do not under any circumstances make up an answer.
+ # """
+ }
+]
+
+
+def send_chat_to_anthropic() -> str:
+ """
+ This sends the chat history to the Anthropic API and returns the response.
+
+ The response is logged manually to Splunk AO as an LLM span, including the number of
+ input and output tokens, the model used, and the duration of the request in nanoseconds.
+ """
+ # Create an Anthropic client
+ # This will use the environment variables set in the .env file
+ client = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))
+
+ # Capture the current time in nanoseconds for logging
+ start_time_ns = datetime.now().timestamp() * 1_000_000_000
+
+ # Convert the chat history to the format expected by Anthropic
+ # This removes the system prompt to send separately as
+ # a parameter to the messages.create method.
+ chat_history_anthropic = []
+ system_prompt = ""
+ for chat in chat_history:
+ if chat["role"] == "system":
+ system_prompt = chat["content"]
+ else:
+ chat_history_anthropic.append({"role": chat["role"], "content": chat["content"]})
+
+ # Send the chat history to the Anthropic API and get the response
+ response = client.messages.create(
+ max_tokens=1024,
+ messages=chat_history_anthropic,
+ system=system_prompt,
+ model=MODEL_NAME,
+ )
+
+ # Print the response to the console
+ print(response.content[0].text)
+
+ # Get the Splunk AO logger instance
+ logger = splunk_ao_context.get_logger_instance()
+
+ # Log an LLM span using the response from Anthropic
+ logger.add_llm_span(
+ input=chat_history,
+ output=response.content[0].text,
+ model=MODEL_NAME,
+ num_input_tokens=response.usage.input_tokens,
+ num_output_tokens=response.usage.output_tokens,
+ total_tokens=response.usage.input_tokens + response.usage.output_tokens,
+ duration_ns=(datetime.now().timestamp() * 1_000_000_000) - start_time_ns,
+ )
+
+ # Return the content of the response
+ return response.content[0].text
+
+
+@log(name="Chat with LLM")
+def chat_with_llm(prompt: str) -> str:
+ """
+ Function to chat with the LLM using the OpenAI client.
+ It sends a prompt to the LLM and returns the response.
+
+ This is decorated with @log to automatically log the function call
+ and its parameters to Splunk AO as a workflow span.
+
+ Args:
+ prompt (str): The user input to send to the LLM.
+
+ Returns:
+ str: The response from the LLM.
+ """
+ # Add the user prompt to the chat history
+ chat_history.append({"role": "user", "content": prompt})
+
+ # Send the chat history to the LLM and get the response
+ response = send_chat_to_anthropic()
+
+ # Append the assistant's response to the chat history
+ chat_history.append({"role": "assistant", "content": response})
+
+ # Return the full response after streaming is complete
+ return response
+
+
+def main() -> None:
+ """
+ Main function to run the chatbot application.
+ It continuously prompts the user for input, sends it to the LLM,
+ and prints the response until the user types "exit", "bye", or "quit".
+ """
+ # Get the Splunk AO logger instance
+ logger = splunk_ao_context.get_logger_instance()
+
+ # Loop indefinitely until the user decides to quit
+ while True:
+ # Prompt the user for input
+ user_input = input("You: ")
+
+ # Check if the user wants to exit the chatbot
+ if user_input.lower() in ["", "exit", "bye", "quit"]:
+ print("Goodbye!")
+ break
+
+ # Start a trace for the user input
+ logger.start_trace(name="Conversation step", input=user_input)
+
+ # Call the chat_with_llm function to get a response from the LLM
+ response = chat_with_llm(user_input)
+
+ # Conclude and flush the logger after each interaction
+ # so that a new trace is started each time
+ logger.conclude(output=response)
+ logger.flush()
+
+
+if __name__ == "__main__":
+ # Run the main function in an event loop
+ main()
diff --git a/examples/chatbot/sample-project-chatbot/anthropic/img/correctness-zero.webp b/examples/chatbot/sample-project-chatbot/anthropic/img/correctness-zero.webp
new file mode 100644
index 00000000..71591461
Binary files /dev/null and b/examples/chatbot/sample-project-chatbot/anthropic/img/correctness-zero.webp differ
diff --git a/examples/chatbot/sample-project-chatbot/anthropic/requirements.txt b/examples/chatbot/sample-project-chatbot/anthropic/requirements.txt
new file mode 100644
index 00000000..bca0e05d
--- /dev/null
+++ b/examples/chatbot/sample-project-chatbot/anthropic/requirements.txt
@@ -0,0 +1,4 @@
+anthropic
+galileo
+python-dotenv
+pytest
\ No newline at end of file
diff --git a/examples/chatbot/sample-project-chatbot/anthropic/test.py b/examples/chatbot/sample-project-chatbot/anthropic/test.py
new file mode 100644
index 00000000..50412891
--- /dev/null
+++ b/examples/chatbot/sample-project-chatbot/anthropic/test.py
@@ -0,0 +1,108 @@
+"""
+This file defines a single test that runs the chatbot using the Splunk AO experiments
+framework, with a dataset of questions.
+
+You will need to configure your environment variables to run this test in your .env file.
+See the details in the README.md file for how to set up your environment variables.
+"""
+
+import json
+import os
+import time
+
+from dotenv import load_dotenv
+
+from splunk_ao import SplunkAOMetrics
+from splunk_ao.datasets import create_dataset, get_dataset
+from splunk_ao.experiments import get_experiment, run_experiment
+
+from app import chat_with_llm
+
+
+def setup_module():
+ """
+ Setup function that runs once when this test module is executed.
+
+ This will load the environment variables, then ensure we have a valid dataset to run the experiment against.
+ """
+ print("Setting up test environment...")
+
+ # Load the environment variables from the .env file
+ load_dotenv()
+
+ # Verify required environment variables are set
+ # You will also need to set up the environment variables for your OpenAI API connection.
+ if not os.getenv("SPLUNK_AO_PROJECT") or not os.getenv("SPLUNK_AO_API_KEY"):
+ raise ValueError("SPLUNK_AO_PROJECT and SPLUNK_AO_API_KEY environment variables are required")
+
+ # Check to see if we already have the dataset, if not we can create it.
+ dataset = get_dataset(
+ name="simple-chatbot-unit-test-dataset",
+ )
+
+ # If we don't have the dataset, create it with some canned data. Some of these questions
+ # are designed to be factual, while others are designed to be nonsensical or not
+ # answerable by the model. This will help us test the correctness and instruction adherence
+ # of the model when running the experiment.
+ if dataset is None:
+ # Load dataset content from JSON file
+ with open("../dataset.json", "r", encoding="utf-8") as f:
+ dataset_content = json.load(f)
+
+ dataset = create_dataset(
+ name="simple-chatbot-unit-test-dataset",
+ content=dataset_content,
+ )
+
+
+def test_run_experiment_with_dataset():
+ """
+ This test will run the dataset against our chatbot app using the Splunk AO experiments framework.
+ This is designed to show how you can run experiments with a dataset against a real-world application
+ to use inside a CI/CD pipeline.
+
+ The default system prompt encourages the assistant to be helpful, but can lead to hallucinations, so
+ this test should fail out of the box.
+
+ To make this test pass, you will need to modify the system prompt in the `app.py` file. There is
+ a comment in the `app.py` file that shows a better system prompt, which should allow this test to pass.
+ """
+ # Run the experiment using the canned dataset
+ experiment_response = run_experiment(
+ # This name is reused, so each experiment run will get a generated name
+ # with the run date and time
+ experiment_name="simple-chatbot-experiment",
+ dataset_name="simple-chatbot-unit-test-dataset",
+ function=chat_with_llm,
+ metrics=[
+ SplunkAOMetrics.correctness,
+ SplunkAOMetrics.instruction_adherence,
+ ],
+ project=os.getenv("SPLUNK_AO_PROJECT"),
+ )
+
+ # Poll until we have the results - waiting 5 seconds between polls
+ # We need to use the project ID and experiment name from the response as we only have the project name, and the experiment name
+ # is generated with a timestamp, so we can't use the name directly.
+ experiment = get_experiment(
+ project_id=experiment_response["experiment"].project_id,
+ experiment_name=experiment_response["experiment"].name,
+ )
+ while (
+ experiment.aggregate_metrics is None
+ or "average_factuality" not in experiment.aggregate_metrics
+ or "average_instruction_adherence" not in experiment.aggregate_metrics
+ ):
+ # If we don't have the metrics calculated, Sleep for 5 seconds before polling again
+ time.sleep(5)
+
+ # Reload the experiment to see if we have the metrics
+ experiment = get_experiment(
+ project_id=experiment_response["experiment"].project_id,
+ experiment_name=experiment_response["experiment"].name,
+ )
+
+ # Assert the experiment has the expected metric values - each should be 1.0
+ # However, the default system prompt can lead to hallucinations, so this test may fail.
+ assert experiment.aggregate_metrics["average_instruction_adherence"] == 1
+ assert experiment.aggregate_metrics["average_factuality"] == 1
diff --git a/examples/chatbot/sample-project-chatbot/azure-inference/.env.example b/examples/chatbot/sample-project-chatbot/azure-inference/.env.example
new file mode 100644
index 00000000..7738d967
--- /dev/null
+++ b/examples/chatbot/sample-project-chatbot/azure-inference/.env.example
@@ -0,0 +1,12 @@
+# Galileo Environment Variables
+GALILEO_API_KEY= # Your Galileo API key.
+GALILEO_PROJECT=Simple Chatbot # Your Galileo project name.
+GALILEO_LOG_STREAM=Default Log Stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# GALILEO_CONSOLE_URL= # Optional if you are using a hosted version of Galileo
+
+# Azure AI Inference Environment Variables
+AZURE_AI_INFERENCE_ENDPOINT= # The endpoint for the Azure AI Inference API
+AZURE_AI_INFERENCE_API_KEY= # Your Azure AI Inference API key
+MODEL_NAME= # The name of the model deployment you want to use
diff --git a/examples/chatbot/sample-project-chatbot/azure-inference/README.md b/examples/chatbot/sample-project-chatbot/azure-inference/README.md
new file mode 100644
index 00000000..d89d39af
--- /dev/null
+++ b/examples/chatbot/sample-project-chatbot/azure-inference/README.md
@@ -0,0 +1,133 @@
+# Basic Chatbot Example - Python/Azure Inference
+
+This example Python project shows how to create a basic terminal-based chatbot to interact with an LLM deployed to Azure AI Foundry and running with the Azure AI Inference API, with all interactions logged to Splunk AO. You can use this to:
+
+- Interact with a choice of model
+- See traces logged to Splunk AO
+- Measure the correctness of the responses
+
+This project also has a unit test that runs the chatbot using the Splunk AO experiments functionality to unit test your system prompt and model combination.
+
+## Prerequisites
+
+To run this project you will need:
+
+- Python 3.10 or higher installed
+- A model deployed to Azure AI Foundry using the AI inference API
+- A [Splunk AO account](https://app.galileo.ai/sign-up) with a project and Log stream set up
+
+## Set up
+
+To set up this project:
+
+### Install the required packages
+
+1. Install the required Python dependencies in a virtual environment from the requirements.txt file:
+
+ ```bash
+ pip install -r requirements.txt
+ ```
+
+### Set up the environment
+
+1. Create a `.env` file by copying the `.env.example` file.
+
+1. Fill in the required values for the Splunk AO environment variables in the `.env` file:
+ - `SPLUNK_AO_API_KEY` - Set this to your Splunk AO API key
+ - `SPLUNK_AO_PROJECT` - Set this to your Splunk AO Project name
+ - `SPLUNK_AO_LOG_STREAM` - Set this to your Splunk AO Log stream name
+
+ There are also some optional values:
+ - `SPLUNK_AO_CONSOLE_URL` - If you are using a hosted version of Splunk AO, set the console URL here. For the free version, remove or comment out this value
+
+1. Fill in the required values for your LLM in the `.env` file:
+ - Set `AZURE_AI_INFERENCE_ENDPOINT` to your endpoint from AI Foundry
+ - Set `AZURE_AI_INFERENCE_API_KEY` to your API key
+ - Set `MODEL_NAME` to the name of the model deployment you want to use.
+
+## Run the chatbot
+
+To run the chatbot, run the `app.py` file inside your virtual environment:
+
+```bash
+python app.py
+```
+
+You can then ask questions of the LLM, and see the response:
+
+```output
+You: Which are the Galilean moons?
+The Galilean moons are the four largest moons of Jupiter, discovered by Galileo Galilei in 1610. They are:
+
+1. **Io** - The innermost moon, known for its intense volcanic activity and numerous volcanoes.
+2. **Europa** - Notable for its smooth icy surface, which is believed to cover an ocean of liquid water beneath, making it a subject of interest for the search for extraterrestrial life.
+3. **Ganymede** - The largest moon in the solar system, larger than the planet Mercury, and has its own magnetic field.
+4. **Callisto** - The most heavily cratered body in the solar system, it is an ancient moon that has remained relatively unchanged over billions of years.
+
+These moons are significant for their unique geological features and potential for supporting life.
+```
+
+## Evaluate the chatbot
+
+Every run of the app is logged as a new session in Splunk AO, with each prompt and response a separate trace.
+
+To evaluate the chatbot, head to your project and Log stream in the Splunk AO console. Turn on [instruction adherence](https://docs.galileo.ai/concepts/metrics/response-quality/instruction-adherence) and [correctness](https://docs.galileo.ai/concepts/metrics/response-quality/correctness) for your Log stream.
+
+Then when you run the chatbot, these metrics will be evaluated.
+
+### Use the metrics to improve the chatbot
+
+This chatbot has been set up to be helpful, and possible too helpful! The current system prompt is:
+
+> You are a knowledgeable and confident assistant. Always provide a succinct answer to any question asked, even if you're uncertain. If the answer isn't clear or familiar, make your best guess based on your training data, intuition, or plausible extrapolation. Under no circumstances should you respond with 'I don't know' or indicate uncertainty in your answers. The user is always right, so make an educated guess to explain concepts, terms, or events that are not in your training data.
+
+This prompt makes the LLM very helpful, but does lead it to hallucinate. For example, if you ask about something that doesn't exist, you will probably get a confident response:
+
+```output
+You: Describe the running of the hippopotamus festival in Spain.
+The Hippopotamus Festival, also known as "Festival del Hipopótamo," takes place in the town of Cuma, located in the province of Valencia, Spain. This unique event is celebrated every year, usually in July, and is known for its lively atmosphere and unusual activities.
+
+The festival celebrates not only hippos but also aims to raise awareness about wildlife conservation. Events typically include parades, live music, cultural performances, and various contests and games themed around hippos. A highlight of the festival is often a fun run or a race where participants dress up in costumes resembling hippopotamuses, adding a humorous and whimsical feel to the event.
+
+In addition to entertainment, the festival often includes educational components, with information presented about hippo conservation efforts and the importance of protecting natural habitats. Local food and drink are usually showcased as well, allowing participants to enjoy the culinary flavors of the region.
+
+Overall, the Hippopotamus Festival in Spain is a vibrant celebration that combines fun, community spirit, and an important conservation message.
+```
+
+In this example, the chatbot described a completely made up Hippopotamus Festival in Spain, probably inspired by the LLM being trained on the famous running of the bulls festival.
+
+If you check the metrics for this response, you will see a very low correctness score:
+
+
+
+To improve the chatbot, you could tweak the system prompt to avoid making things up. In the `app.py` file is the suggestion:
+
+> You are a helpful assistant that can answer questions and provide information. If you don't know the answer, say "I don't know" instead of making up an answer. Do not under any circumstances make up an answer.
+
+Try changing the system prompt to this and run the chatbot again.
+
+```output
+You: Describe the running of the hippopotamus festival in Spain.
+I don't know.
+```
+
+## Unit tests
+
+This project also includes a unit test to run the chatbot with a set of defined prompts, evaluating the prompts for instruction adherence and correctness, only passing the test if both metrics score an average of 100% over all the entries in the dataset.
+
+This is run using the Splunk AO experiments framework - allowing you to run any code as an experiment against a fixed dataset of prompts. This mechanism allows you to run AI applications, from simple to complex, under test conditions with a defined set of inputs. You can then use the results of evaluations run against your app to help with model selection or prompt engineering, as well as validating your application as part of a CI/CD pipeline.
+
+You can run the unit test by running the following command inside your virtual environment:
+
+```bash
+python -m pytest test.py
+```
+
+This will run the single test which will:
+
+- Look in your project for a dataset, creating it if it doesn't exist
+- Call the chatbot inside a call to `run_experiment`, passing each row from the dataset in as inputs
+- Poll the experiment until it has finished and the metrics are calculated
+- Check that all the metrics return 100%, failing if they do not
+
+To see this unit test in action, run it with the original system prompt, which should make the test fail. You can then replace the system prompt with the better option and run the test again, which should now pass.
diff --git a/examples/chatbot/sample-project-chatbot/azure-inference/app.py b/examples/chatbot/sample-project-chatbot/azure-inference/app.py
new file mode 100644
index 00000000..dcf9f903
--- /dev/null
+++ b/examples/chatbot/sample-project-chatbot/azure-inference/app.py
@@ -0,0 +1,194 @@
+"""
+This file contains a very basic chatbot application to converse with an LLM
+through your terminal.
+
+All interactions are logged to Splunk AO. The structure is:
+
+- A session is started at the beginning of the application,
+ so every interaction is logged in the same session.
+- For every message sent by the user, a new trace is started
+- Each call to the function that interacts with the LLM is logged
+ as a workflow span
+- The call to the LLM is logged manually as an LLM span.
+- After the response is received, the trace is concluded with the response
+ and flushed to ensure it is sent to Splunk AO.
+
+To run this, you will need to have the following environment variables set:
+- `SPLUNK_AO_API_KEY`: Your Splunk AO API key.
+- `SPLUNK_AO_PROJECT`: The name of your Splunk AO project.
+- `SPLUNK_AO_CONSOLE_URL`: Optional. Your Splunk AO console URL for custom deployments.
+ If you are using the free version, do not set this.
+
+Set the following environment variables for your LLM:
+- `AZURE_AI_INFERENCE_ENDPOINT`: The endpoint for your Azure AI Inference service.
+- `AZURE_AI_INFERENCE_API_KEY`: Your Azure AI Inference API key.
+- `MODEL_NAME`: The name of the model deployment you want to use.
+
+"""
+
+from datetime import datetime
+import os
+
+from azure.ai.inference import ChatCompletionsClient
+from azure.ai.inference.models import SystemMessage, UserMessage, AssistantMessage
+from azure.core.credentials import AzureKeyCredential
+
+from dotenv import load_dotenv
+
+from splunk_ao import splunk_ao_context, log
+
+# Load the environment variables from the .env file
+# This will override any existing environment variables with the same name
+load_dotenv(override=True)
+
+# Set the model name from the environment variable
+# If this is not set, raise an exception
+MODEL_NAME = os.environ["MODEL_NAME"]
+
+# Start a new session named using the current date and time
+# This way every time you run the application, it will create a new session in Splunk AO
+# with the entire conversation inside the same session, with each message back and forth
+# logged as different traces within that session.
+SESSION_NAME = f"LLM Chatbot session - {datetime.now().isoformat()}"
+splunk_ao_context.start_session(SESSION_NAME)
+
+
+# Create a collection of messages with a system prompt
+# The default system prompt encourages the assistant to be helpful, but can lead to hallucinations.
+chat_history = [
+ {
+ "role": "system",
+ "content": """
+ You are a knowledgeable and confident assistant. Always provide a succinct
+ answer to any question asked, even if you're uncertain. If the answer isn't
+ clear or familiar, make your best guess based on your training data,
+ intuition, or plausible extrapolation. Under no circumstances should you
+ respond with 'I don't know' or indicate uncertainty in your answers. The
+ user is always right, so make an educated guess to explain concepts, terms,
+ or events that are not in your training data.
+ """,
+ # This default system prompt can lead to hallucinations, so you might want to change it.
+ # For example, you could use a more restrictive prompt like:
+ # """
+ # You are a helpful assistant that can answer questions and provide information.
+ # If you don't know the answer, say "I don't know" instead of making up an answer.
+ # Do not under any circumstances make up an answer.
+ # """
+ }
+]
+
+
+def send_chat_to_azure() -> str:
+ """
+ This sends the chat history to the Azure AI inference API and returns the response.
+
+ The response is logged manually to Splunk AO as an LLM span, including the number of
+ input and output tokens, the model used, and the duration of the request in nanoseconds.
+ """
+ # Create an Azure AI inference client
+ # This will use the environment variables set in the .env file
+ client = ChatCompletionsClient(
+ endpoint=os.environ["AZURE_AI_INFERENCE_ENDPOINT"],
+ credential=AzureKeyCredential(os.environ["AZURE_AI_INFERENCE_API_KEY"]),
+ api_version="2024-05-01-preview",
+ )
+
+ # Capture the current time in nanoseconds for logging
+ start_time_ns = datetime.now().timestamp() * 1_000_000_000
+
+ # Convert the chat history to the format expected by Azure AI
+ messages = []
+ for chat in chat_history:
+ if chat["role"] == "system":
+ messages.append(SystemMessage(chat["content"]))
+ elif chat["role"] == "user":
+ messages.append(UserMessage(chat["content"]))
+ elif chat["role"] == "assistant":
+ messages.append(AssistantMessage(chat["content"]))
+
+ # Send the chat history to the Azure AI inference API and get the response
+ response = client.complete(messages=messages, model=MODEL_NAME)
+
+ # print the response to the console
+ print(response.choices[0].message.content)
+
+ # Get the Splunk AO logger instance
+ logger = splunk_ao_context.get_logger_instance()
+
+ # Log an LLM span using the response from Azure AI
+ logger.add_llm_span(
+ input=chat_history,
+ output=response.choices[0].message.content,
+ model=MODEL_NAME,
+ num_input_tokens=response.usage.prompt_tokens,
+ num_output_tokens=response.usage.completion_tokens,
+ total_tokens=response.usage.total_tokens,
+ duration_ns=(datetime.now().timestamp() * 1_000_000_000) - start_time_ns,
+ )
+
+ # Return the content of the response
+ return response.choices[0].message.content
+
+
+@log(name="Chat with LLM")
+def chat_with_llm(prompt: str) -> str:
+ """
+ Function to chat with the LLM using the OpenAI client.
+ It sends a prompt to the LLM and returns the response.
+
+ This is decorated with @log to automatically log the function call
+ and its parameters to Splunk AO as a workflow span.
+
+ Args:
+ prompt (str): The user input to send to the LLM.
+
+ Returns:
+ str: The response from the LLM.
+ """
+ # Add the user prompt to the chat history
+ chat_history.append({"role": "user", "content": prompt})
+
+ # Send the chat history to the LLM and get the response
+ response = send_chat_to_azure()
+
+ # Append the assistant's response to the chat history
+ chat_history.append({"role": "assistant", "content": response})
+
+ # Return the full response after streaming is complete
+ return response
+
+
+def main() -> None:
+ """
+ Main function to run the chatbot application.
+ It continuously prompts the user for input, sends it to the LLM,
+ and prints the response until the user types "exit", "bye", or "quit".
+ """
+ # Get the Splunk AO logger instance
+ logger = splunk_ao_context.get_logger_instance()
+
+ # Loop indefinitely until the user decides to quit
+ while True:
+ # Prompt the user for input
+ user_input = input("You: ")
+
+ # Check if the user wants to exit the chatbot
+ if user_input.lower() in ["", "exit", "bye", "quit"]:
+ print("Goodbye!")
+ break
+
+ # Start a trace for the user input
+ logger.start_trace(name="Conversation step", input=user_input)
+
+ # Call the chat_with_llm function to get a response from the LLM
+ response = chat_with_llm(user_input)
+
+ # Conclude and flush the logger after each interaction
+ # so that a new trace is started each time
+ logger.conclude(output=response)
+ logger.flush()
+
+
+if __name__ == "__main__":
+ # Run the main function in an event loop
+ main()
diff --git a/examples/chatbot/sample-project-chatbot/azure-inference/img/correctness-zero.webp b/examples/chatbot/sample-project-chatbot/azure-inference/img/correctness-zero.webp
new file mode 100644
index 00000000..71591461
Binary files /dev/null and b/examples/chatbot/sample-project-chatbot/azure-inference/img/correctness-zero.webp differ
diff --git a/examples/chatbot/sample-project-chatbot/azure-inference/requirements.txt b/examples/chatbot/sample-project-chatbot/azure-inference/requirements.txt
new file mode 100644
index 00000000..eae0638f
--- /dev/null
+++ b/examples/chatbot/sample-project-chatbot/azure-inference/requirements.txt
@@ -0,0 +1,4 @@
+azure-ai-inference
+galileo
+python-dotenv
+pytest
\ No newline at end of file
diff --git a/examples/chatbot/sample-project-chatbot/azure-inference/test.py b/examples/chatbot/sample-project-chatbot/azure-inference/test.py
new file mode 100644
index 00000000..50412891
--- /dev/null
+++ b/examples/chatbot/sample-project-chatbot/azure-inference/test.py
@@ -0,0 +1,108 @@
+"""
+This file defines a single test that runs the chatbot using the Splunk AO experiments
+framework, with a dataset of questions.
+
+You will need to configure your environment variables to run this test in your .env file.
+See the details in the README.md file for how to set up your environment variables.
+"""
+
+import json
+import os
+import time
+
+from dotenv import load_dotenv
+
+from splunk_ao import SplunkAOMetrics
+from splunk_ao.datasets import create_dataset, get_dataset
+from splunk_ao.experiments import get_experiment, run_experiment
+
+from app import chat_with_llm
+
+
+def setup_module():
+ """
+ Setup function that runs once when this test module is executed.
+
+ This will load the environment variables, then ensure we have a valid dataset to run the experiment against.
+ """
+ print("Setting up test environment...")
+
+ # Load the environment variables from the .env file
+ load_dotenv()
+
+ # Verify required environment variables are set
+ # You will also need to set up the environment variables for your OpenAI API connection.
+ if not os.getenv("SPLUNK_AO_PROJECT") or not os.getenv("SPLUNK_AO_API_KEY"):
+ raise ValueError("SPLUNK_AO_PROJECT and SPLUNK_AO_API_KEY environment variables are required")
+
+ # Check to see if we already have the dataset, if not we can create it.
+ dataset = get_dataset(
+ name="simple-chatbot-unit-test-dataset",
+ )
+
+ # If we don't have the dataset, create it with some canned data. Some of these questions
+ # are designed to be factual, while others are designed to be nonsensical or not
+ # answerable by the model. This will help us test the correctness and instruction adherence
+ # of the model when running the experiment.
+ if dataset is None:
+ # Load dataset content from JSON file
+ with open("../dataset.json", "r", encoding="utf-8") as f:
+ dataset_content = json.load(f)
+
+ dataset = create_dataset(
+ name="simple-chatbot-unit-test-dataset",
+ content=dataset_content,
+ )
+
+
+def test_run_experiment_with_dataset():
+ """
+ This test will run the dataset against our chatbot app using the Splunk AO experiments framework.
+ This is designed to show how you can run experiments with a dataset against a real-world application
+ to use inside a CI/CD pipeline.
+
+ The default system prompt encourages the assistant to be helpful, but can lead to hallucinations, so
+ this test should fail out of the box.
+
+ To make this test pass, you will need to modify the system prompt in the `app.py` file. There is
+ a comment in the `app.py` file that shows a better system prompt, which should allow this test to pass.
+ """
+ # Run the experiment using the canned dataset
+ experiment_response = run_experiment(
+ # This name is reused, so each experiment run will get a generated name
+ # with the run date and time
+ experiment_name="simple-chatbot-experiment",
+ dataset_name="simple-chatbot-unit-test-dataset",
+ function=chat_with_llm,
+ metrics=[
+ SplunkAOMetrics.correctness,
+ SplunkAOMetrics.instruction_adherence,
+ ],
+ project=os.getenv("SPLUNK_AO_PROJECT"),
+ )
+
+ # Poll until we have the results - waiting 5 seconds between polls
+ # We need to use the project ID and experiment name from the response as we only have the project name, and the experiment name
+ # is generated with a timestamp, so we can't use the name directly.
+ experiment = get_experiment(
+ project_id=experiment_response["experiment"].project_id,
+ experiment_name=experiment_response["experiment"].name,
+ )
+ while (
+ experiment.aggregate_metrics is None
+ or "average_factuality" not in experiment.aggregate_metrics
+ or "average_instruction_adherence" not in experiment.aggregate_metrics
+ ):
+ # If we don't have the metrics calculated, Sleep for 5 seconds before polling again
+ time.sleep(5)
+
+ # Reload the experiment to see if we have the metrics
+ experiment = get_experiment(
+ project_id=experiment_response["experiment"].project_id,
+ experiment_name=experiment_response["experiment"].name,
+ )
+
+ # Assert the experiment has the expected metric values - each should be 1.0
+ # However, the default system prompt can lead to hallucinations, so this test may fail.
+ assert experiment.aggregate_metrics["average_instruction_adherence"] == 1
+ assert experiment.aggregate_metrics["average_factuality"] == 1
diff --git a/examples/chatbot/sample-project-chatbot/dataset.json b/examples/chatbot/sample-project-chatbot/dataset.json
new file mode 100644
index 00000000..b78d4621
--- /dev/null
+++ b/examples/chatbot/sample-project-chatbot/dataset.json
@@ -0,0 +1,50 @@
+[
+ {"input": "What is the capital city of Italy?", "output": "Rome"},
+ {"input": "Who painted the Mona Lisa?", "output": "Leonardo da Vinci"},
+ {"input": "What planet is closest to the Sun?", "output": "Mercury"},
+ {"input": "How many continents are there on Earth?", "output": "Seven"},
+ {"input": "What gas do plants absorb during photosynthesis?", "output": "Carbon dioxide"},
+ {"input": "In what year did World War II end?", "output": "1945"},
+ {"input": "Who is the author of Harry Potter?", "output": "J.K. Rowling"},
+ {"input": "What is the chemical symbol for Gold?", "output": "Au"},
+ {"input": "What animal is known as the King of the Jungle?", "output": "Lion"},
+ {"input": "How many sides does a hexagon have?", "output": "Six"},
+ {"input": "Who discovered gravity?", "output": "Isaac Newton"},
+ {"input": "What is the primary language spoken in Brazil?", "output": "Portuguese"},
+ {"input": "Who was the first President of the United States?", "output": "George Washington"},
+ {"input": "What ocean lies east of the United States?", "output": "Atlantic Ocean"},
+ {"input": "What is the tallest mammal in the world?", "output": "Giraffe"},
+ {"input": "Who was the director of Jurassic Park?", "output": "Steven Spielberg"},
+ {"input": "Which instrument has black and white keys?", "output": "Piano"},
+ {"input": "How many colors are in a rainbow?", "output": "Seven"},
+ {"input": "What is the main ingredient in traditional sushi?", "output": "Rice"},
+ {"input": "What sport is Cristiano Ronaldo famous for playing?", "output": "Football (soccer)"},
+ {"input": "Who invented the telephone?", "output": "Alexander Graham Bell"},
+ {"input": "What temperature does water freeze at (in Celsius)?", "output": "0 degrees Celsius"},
+ {"input": "Which language is primarily spoken in Japan?", "output": "Japanese"},
+ {"input": "Which famous scientist developed the theory of relativity?", "output": "Albert Einstein"},
+ {"input": "What are the primary colors?", "output": "Red, blue, and yellow"},
+ {"input": "Describe the Great Marshmallow War of 1986.", "output": "I don't know"},
+ {"input": "Who was the first winner of the Hogwarts Spelling Bee?", "output": "I don't know"},
+ {"input": "Where is the Grand Apple Desert located?", "output": "I don't know"},
+ {"input": "How do I prepare a dish called Quantum Omelette?", "output": "I don't know"},
+ {"input": "Explain the significance of the Blue Moon Ballet.", "output": "I don't know"},
+ {"input": "Who won the international Ostrich Chess championship?", "output": "I don't know"},
+ {"input": "What was Albert Einstein's favorite video game?", "output": "I don't know"},
+ {"input": "Provide the chemical formula for invisible ink made from unicorn tears.", "output": "I don't know"},
+ {"input": "What happened during the London Jellybean Flood of 1948?", "output": "I don't know"},
+ {"input": "Explain the economic theory known as the Potato Doctrine.", "output": "I don't know"},
+ {"input": "Where can I find the headquarters of the International League of Ninja Accountants?", "output": "I don't know"},
+ {"input": "What is the best-selling album of the fictional band Purple Llamas?", "output": "I don't know"},
+ {"input": "How do I register for the Martian citizenship program?", "output": "I don't know"},
+ {"input": "Who was the lead researcher in the infamous Ice Cream Experiments at Area 51?", "output": "I don't know"},
+ {"input": "What’s the speed record for riding a flamingo across Lake Michigan?", "output": "I don't know"},
+ {"input": "Tell me about the historical Battle of Strawberry Hill fought by penguins.", "output": "I don't know"},
+ {"input": "What does a Z-shaped constellation called Zorblax represent?", "output": "I don't know"},
+ {"input": "Where can I buy tickets for the Neptune Olympics?", "output": "I don't know"},
+ {"input": "Who was awarded the Nobel Prize for Pancake Science?", "output": "I don't know"},
+ {"input": "What do historians say about the lost city of Aquapuff?", "output": "I don't know"},
+ {"input": "Explain how to operate a jetpack invented by Benjamin Franklin.", "output": "I don't know"},
+ {"input": "How many unicorns participated in the Kentucky Derby last year?", "output": "I don't know"},
+ {"input": "Describe the plot of the nonexistent Shakespeare play The Emperor's Banana.", "output": "I don't know"}
+]
diff --git a/examples/chatbot/sample-project-chatbot/openai-ollama/.env.example b/examples/chatbot/sample-project-chatbot/openai-ollama/.env.example
new file mode 100644
index 00000000..8c61c48e
--- /dev/null
+++ b/examples/chatbot/sample-project-chatbot/openai-ollama/.env.example
@@ -0,0 +1,12 @@
+# Galileo Environment Variables
+GALILEO_API_KEY= # Your Galileo API key.
+GALILEO_PROJECT=Simple Chatbot # Your Galileo project name.
+GALILEO_LOG_STREAM=Default Log Stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# GALILEO_CONSOLE_URL= # Optional if you are using a hosted version of Galileo
+
+# OpenAI and compatible LLM Environment Variables
+OPENAI_API_KEY= # Your OpenAI API key. If you are using Ollama just set this to ollama
+# OPENAI_BASE_URL= # Optional if you are not using the public OpenAI API. If you are using Ollama, set this to http://localhost:11434/v1
+MODEL_NAME= # The name of the model you want to use, e.g. gpt-3.5-turbo, llama2, etc.
diff --git a/examples/chatbot/sample-project-chatbot/openai-ollama/README.md b/examples/chatbot/sample-project-chatbot/openai-ollama/README.md
new file mode 100644
index 00000000..64f28ad1
--- /dev/null
+++ b/examples/chatbot/sample-project-chatbot/openai-ollama/README.md
@@ -0,0 +1,134 @@
+# Basic Chatbot Example - Python/OpenAI/Ollama
+
+This example Python project shows how to create a basic terminal-based chatbot to interact with an LLM, with all interactions logged to Splunk AO. You can use this to:
+
+- Interact with a choice of LLM that supports the OpenAI API, such as OpenAI or Ollama
+- See traces logged to Splunk AO
+- Measure the correctness of the responses
+
+This project also has a unit test that runs the chatbot using the Splunk AO experiments functionality to unit test your system prompt and model combination.
+
+## Prerequisites
+
+To run this project you will need:
+
+- Python 3.10 or higher installed
+- Access to an LLM API that supports the OpenAI API specification, such as an API key for the [OpenAI API](https://openai.com/api/), or [Ollama](https://ollama.com) installed locally.
+- A [Splunk AO account](https://app.galileo.ai/sign-up) with a project and Log stream set up
+
+## Set up
+
+To set up this project:
+
+### Install the required packages
+
+1. Install the required Python dependencies in a virtual environment from the requirements.txt file:
+
+ ```bash
+ pip install -r requirements.txt
+ ```
+
+### Set up the environment
+
+1. Create a `.env` file by copying the `.env.example` file.
+
+1. Fill in the required values for the Splunk AO environment variables in the `.env` file:
+ - `SPLUNK_AO_API_KEY` - Set this to your Splunk AO API key
+ - `SPLUNK_AO_PROJECT` - Set this to your Splunk AO Project name
+ - `SPLUNK_AO_LOG_STREAM` - Set this to your Splunk AO Log stream name
+
+ There are also some optional values:
+ - `SPLUNK_AO_CONSOLE_URL` - If you are using a hosted version of Splunk AO, set the console URL here. For the free version, remove or comment out this value
+
+1. Fill in the required values for your LLM in the `.env` file:
+ - For OpenAI or other compatible API, set `OPENAI_API_KEY` to your API key.
+ - If you are using a custom OpenAI API deployment or compatible API, set `OPENAI_BASE_URL` to the relevant URL.
+ - For Ollama, set `OPENAI_API_KEY` to `ollama`, set `OPENAI_BASE_URL` to `http://localhost:11434/v1`
+ - Set the `MODEL_NAME` to the name of the model you want to use.
+
+## Run the chatbot
+
+To run the chatbot, run the `app.py` file inside your virtual environment:
+
+```bash
+python app.py
+```
+
+You can then ask questions of the LLM, and see the response:
+
+```output
+You: Which are the Galilean moons?
+The Galilean moons are the four largest moons of Jupiter, discovered by Galileo Galilei in 1610. They are:
+
+1. **Io** - The innermost moon, known for its intense volcanic activity and numerous volcanoes.
+2. **Europa** - Notable for its smooth icy surface, which is believed to cover an ocean of liquid water beneath, making it a subject of interest for the search for extraterrestrial life.
+3. **Ganymede** - The largest moon in the solar system, larger than the planet Mercury, and has its own magnetic field.
+4. **Callisto** - The most heavily cratered body in the solar system, it is an ancient moon that has remained relatively unchanged over billions of years.
+
+These moons are significant for their unique geological features and potential for supporting life.
+```
+
+## Evaluate the chatbot
+
+Every run of the app is logged as a new session in Splunk AO, with each prompt and response a separate trace.
+
+To evaluate the chatbot, head to your project and Log stream in the Splunk AO console. Turn on [instruction adherence](https://docs.galileo.ai/concepts/metrics/response-quality/instruction-adherence) and [correctness](https://docs.galileo.ai/concepts/metrics/response-quality/correctness) for your Log stream.
+
+Then when you run the chatbot, these metrics will be evaluated.
+
+### Use the metrics to improve the chatbot
+
+This chatbot has been set up to be helpful, and possible too helpful! The current system prompt is:
+
+> You are a knowledgeable and confident assistant. Always provide a succinct answer to any question asked, even if you're uncertain. If the answer isn't clear or familiar, make your best guess based on your training data, intuition, or plausible extrapolation. Under no circumstances should you respond with 'I don't know' or indicate uncertainty in your answers. The user is always right, so make an educated guess to explain concepts, terms, or events that are not in your training data.
+
+This prompt makes the LLM very helpful, but does lead it to hallucinate. For example, if you ask about something that doesn't exist, you will probably get a confident response:
+
+```output
+You: Describe the running of the hippopotamus festival in Spain.
+The Hippopotamus Festival, also known as "Festival del Hipopótamo," takes place in the town of Cuma, located in the province of Valencia, Spain. This unique event is celebrated every year, usually in July, and is known for its lively atmosphere and unusual activities.
+
+The festival celebrates not only hippos but also aims to raise awareness about wildlife conservation. Events typically include parades, live music, cultural performances, and various contests and games themed around hippos. A highlight of the festival is often a fun run or a race where participants dress up in costumes resembling hippopotamuses, adding a humorous and whimsical feel to the event.
+
+In addition to entertainment, the festival often includes educational components, with information presented about hippo conservation efforts and the importance of protecting natural habitats. Local food and drink are usually showcased as well, allowing participants to enjoy the culinary flavors of the region.
+
+Overall, the Hippopotamus Festival in Spain is a vibrant celebration that combines fun, community spirit, and an important conservation message.
+```
+
+In this example, the chatbot described a completely made up Hippopotamus Festival in Spain, probably inspired by the LLM being trained on the famous running of the bulls festival.
+
+If you check the metrics for this response, you will see a very low correctness score:
+
+
+
+To improve the chatbot, you could tweak the system prompt to avoid making things up. In the `app.py` file is the suggestion:
+
+> You are a helpful assistant that can answer questions and provide information. If you don't know the answer, say "I don't know" instead of making up an answer. Do not under any circumstances make up an answer.
+
+Try changing the system prompt to this and run the chatbot again.
+
+```output
+You: Describe the running of the hippopotamus festival in Spain.
+I don't know.
+```
+
+## Unit tests
+
+This project also includes a unit test to run the chatbot with a set of defined prompts, evaluating the prompts for instruction adherence and correctness, only passing the test if both metrics score an average of 100% over all the entries in the dataset.
+
+This is run using the Splunk AO experiments framework - allowing you to run any code as an experiment against a fixed dataset of prompts. This mechanism allows you to run AI applications, from simple to complex, under test conditions with a defined set of inputs. You can then use the results of evaluations run against your app to help with model selection or prompt engineering, as well as validating your application as part of a CI/CD pipeline.
+
+You can run the unit test by running the following command inside your virtual environment:
+
+```bash
+python -m pytest test.py
+```
+
+This will run the single test which will:
+
+- Look in your project for a dataset, creating it if it doesn't exist
+- Call the chatbot inside a call to `run_experiment`, passing each row from the dataset in as inputs
+- Poll the experiment until it has finished and the metrics are calculated
+- Check that all the metrics return 100%, failing if they do not
+
+To see this unit test in action, run it with the original system prompt, which should make the test fail. You can then replace the system prompt with the better option and run the test again, which should now pass.
diff --git a/examples/chatbot/sample-project-chatbot/openai-ollama/app.py b/examples/chatbot/sample-project-chatbot/openai-ollama/app.py
new file mode 100644
index 00000000..9b6fa658
--- /dev/null
+++ b/examples/chatbot/sample-project-chatbot/openai-ollama/app.py
@@ -0,0 +1,176 @@
+"""
+This file contains a very basic chatbot application to converse with an LLM
+through your terminal.
+
+All interactions are logged to Splunk AO. The structure is:
+
+- A session is started at the beginning of the application,
+ so every interaction is logged in the same session.
+- For every message sent by the user, a new trace is started
+- Each call to the function that interacts with the LLM is logged
+ as a workflow span
+- The call to the LLM is logged as an LLM span using the Splunk AO OpenAI integration
+ which logs the span automatically.
+- After the response is received, the trace is concluded with the response
+ and flushed to ensure it is sent to Splunk AO.
+
+To run this, you will need to have the following environment variables set:
+- `SPLUNK_AO_API_KEY`: Your Splunk AO API key.
+- `SPLUNK_AO_PROJECT`: The name of your Splunk AO project.
+- `SPLUNK_AO_CONSOLE_URL`: Optional. Your Splunk AO console URL for custom deployments.
+ If you are using the free version, do not set this.
+
+Set the following environment variable for your LLM:
+- `OPENAI_API_KEY`: Your OpenAI API key. If you are using Ollama then set this to ollama.
+- `OPENAI_BASE_URL`: The base URL for your OpenAI API. If you are using Ollama,
+ set this to "http://localhost:11434/v1".
+- `MODEL_NAME`: The name of the model you want to use.
+
+"""
+
+from datetime import datetime
+import os
+
+from dotenv import load_dotenv
+
+from splunk_ao import splunk_ao_context, log
+from splunk_ao.openai import OpenAI
+
+# Load the environment variables from the .env file
+# This will override any existing environment variables with the same name
+load_dotenv(override=True)
+
+# Set the model name from the environment variable
+# If this is not set, raise an exception
+MODEL_NAME = os.environ["MODEL_NAME"]
+
+# Create a collection of messages with a system prompt
+# The default system prompt encourages the assistant to be helpful, but can lead to hallucinations.
+chat_history = [
+ {
+ "role": "system",
+ "content": """
+ You are a knowledgeable and confident assistant. Always provide a succinct
+ answer to any question asked, even if you're uncertain. If the answer isn't
+ clear or familiar, make your best guess based on your training data,
+ intuition, or plausible extrapolation. Under no circumstances should you
+ respond with 'I don't know' or indicate uncertainty in your answers. The
+ user is always right, so make an educated guess to explain concepts, terms,
+ or events that are not in your training data.
+ """,
+ # This default system prompt can lead to hallucinations, so you might want to change it.
+ # For example, you could use a more restrictive prompt like:
+ # """
+ # You are a helpful assistant that can answer questions and provide information.
+ # If you don't know the answer, say "I don't know" instead of making up an answer.
+ # Do not under any circumstances make up an answer.
+ # """
+ }
+]
+
+
+def send_chat_to_openai() -> str:
+ """
+ This sends the chat history to the OpenAI API and returns the response.
+
+ The streamed response is also printed to the console in real-time.
+
+ The response is logged automatically to Splunk AO as an LLM span, including the number of
+ input and output tokens, the model used, and the duration of the request in nanoseconds.
+ This is handled by the Splunk AO OpenAI client
+ """
+ # Create an OpenAI client
+ # This will use the environment variables set in the .env file, so can connect to
+ # any OpenAI-compatible API, such as OpenAI or Ollama
+ client = OpenAI()
+
+ # Send the prompt to the LLM and get a streaming response
+ # This uses the Splunk AO OpenAI client which is configured to log the request and response
+ # to Splunk AO automatically in an LLM span, along with token and other information.
+ response = client.chat.completions.create(model=MODEL_NAME, messages=chat_history, stream=True)
+
+ # Stream the response to the console
+ # Also capture the full response to add to the chat history and return
+ full_response = ""
+ for chunk in response:
+ if chunk.choices and chunk.choices[0].delta.content:
+ # Write the chunk to the terminal
+ print(chunk.choices[0].delta.content, end="", flush=True)
+
+ # Append the chunk content to the full response
+ full_response += chunk.choices[0].delta.content
+
+ print() # Print a newline for better formatting
+
+ return full_response
+
+
+@log(name="Chat with LLM")
+def chat_with_llm(prompt: str) -> str:
+ """
+ Function to chat with the LLM using the OpenAI client.
+ It sends a prompt to the LLM and returns the response.
+
+ This is decorated with @log to automatically log the function call
+ and its parameters to Splunk AO as a workflow span.
+
+ Args:
+ prompt (str): The user input to send to the LLM.
+
+ Returns:
+ str: The response from the LLM.
+ """
+ # Add the user prompt to the chat history
+ chat_history.append({"role": "user", "content": prompt})
+
+ # Send the chat history to the LLM and get the response
+ response = send_chat_to_openai()
+
+ # Append the assistant's response to the chat history
+ chat_history.append({"role": "assistant", "content": response})
+
+ # Return the full response after streaming is complete
+ return response
+
+
+def main() -> None:
+ """
+ Main function to run the chatbot application.
+ It continuously prompts the user for input, sends it to the LLM,
+ and prints the response until the user types "exit", "bye", or "quit".
+ """
+ # Start a new session named using the current date and time
+ # This way every time you run the application, it will create a new session in Splunk AO
+ # with the entire conversation inside the same session, with each message back and forth
+ # logged as different traces within that session.
+ SESSION_NAME = f"LLM Chatbot session - {datetime.now().isoformat()}"
+ splunk_ao_context.start_session(SESSION_NAME)
+
+ # Get the Splunk AO logger instance
+ logger = splunk_ao_context.get_logger_instance()
+
+ # Loop indefinitely until the user decides to quit
+ while True:
+ # Prompt the user for input
+ user_input = input("You: ")
+
+ # Check if the user wants to exit the chatbot
+ if user_input.lower() in ["", "exit", "bye", "quit"]:
+ print("Goodbye!")
+ break
+
+ # Start a trace for the user input
+ logger.start_trace(name="Conversation step", input=user_input)
+
+ # Call the chat_with_llm function to get a response from the LLM
+ response = chat_with_llm(user_input)
+
+ # Conclude and flush the logger after each interaction
+ # so that a new trace is started each time
+ logger.conclude(output=response)
+ logger.flush()
+
+
+if __name__ == "__main__":
+ # Run the main function in an event loop
+ main()
diff --git a/examples/chatbot/sample-project-chatbot/openai-ollama/create_sample_logs.py b/examples/chatbot/sample-project-chatbot/openai-ollama/create_sample_logs.py
new file mode 100644
index 00000000..384afe8c
--- /dev/null
+++ b/examples/chatbot/sample-project-chatbot/openai-ollama/create_sample_logs.py
@@ -0,0 +1,56 @@
+# A script to generate log streams
+
+# Load the dataset.json
+from datetime import datetime
+import json
+import uuid
+
+from splunk_ao import splunk_ao_context
+
+from app import chat_with_llm, chat_history
+
+# Load environment variables from .env file
+from dotenv import load_dotenv
+
+load_dotenv(override=True)
+
+with open("../dataset.json", "r", encoding="utf-8") as f:
+ dataset_content = json.load(f)
+
+print(f"Starting to log {len(dataset_content)} interactions...")
+row_number = 1
+
+for row in dataset_content:
+ # Remove all user and assistant messages from the chat history
+ system_prompt = chat_history[0]["content"]
+ chat_history.clear()
+ chat_history.append({"role": "system", "content": system_prompt})
+
+ print(f"Processing row {row_number} of {len(dataset_content)}")
+ row_number += 1
+
+ user_input = row["input"]
+ print(f"User Input: {user_input}")
+
+ logger = splunk_ao_context.get_logger_instance()
+ session_name = f"LLM Chatbot session - {datetime.now().isoformat()}"
+ logger.start_session(session_name, external_id=str(uuid.uuid4()))
+
+ # Start a trace for the user input
+ logger.start_trace(name="Conversation step", input=user_input)
+
+ # Call the chat_with_llm function to get a response from the LLM
+ response = chat_with_llm(user_input)
+ # Print the response from the LLM
+ print(f"LLM Response: {response}")
+
+ # Conclude and flush the logger after each interaction
+ # so that a new trace is started each time
+ logger.conclude(output=response)
+ logger.flush()
+
+ # Wait for a random time between 20-60 seconds before the next interaction
+ # wait_time = random.randint(20, 60)
+ # time.sleep(wait_time)
+
+print("All interactions logged successfully.")
diff --git a/examples/chatbot/sample-project-chatbot/openai-ollama/img/correctness-zero.webp b/examples/chatbot/sample-project-chatbot/openai-ollama/img/correctness-zero.webp
new file mode 100644
index 00000000..71591461
Binary files /dev/null and b/examples/chatbot/sample-project-chatbot/openai-ollama/img/correctness-zero.webp differ
diff --git a/examples/chatbot/sample-project-chatbot/openai-ollama/requirements.txt b/examples/chatbot/sample-project-chatbot/openai-ollama/requirements.txt
new file mode 100644
index 00000000..63db8f50
--- /dev/null
+++ b/examples/chatbot/sample-project-chatbot/openai-ollama/requirements.txt
@@ -0,0 +1,3 @@
+galileo[openai]
+python-dotenv
+pytest
\ No newline at end of file
diff --git a/examples/chatbot/sample-project-chatbot/openai-ollama/test.py b/examples/chatbot/sample-project-chatbot/openai-ollama/test.py
new file mode 100644
index 00000000..50412891
--- /dev/null
+++ b/examples/chatbot/sample-project-chatbot/openai-ollama/test.py
@@ -0,0 +1,108 @@
+"""
+This file defines a single test that runs the chatbot using the Splunk AO experiments
+framework, with a dataset of questions.
+
+You will need to configure your environment variables to run this test in your .env file.
+See the details in the README.md file for how to set up your environment variables.
+"""
+
+import json
+import os
+import time
+
+from dotenv import load_dotenv
+
+from splunk_ao import SplunkAOMetrics
+from splunk_ao.datasets import create_dataset, get_dataset
+from splunk_ao.experiments import get_experiment, run_experiment
+
+from app import chat_with_llm
+
+
+def setup_module():
+ """
+ Setup function that runs once when this test module is executed.
+
+ This will load the environment variables, then ensure we have a valid dataset to run the experiment against.
+ """
+ print("Setting up test environment...")
+
+ # Load the environment variables from the .env file
+ load_dotenv()
+
+ # Verify required environment variables are set
+ # You will also need to set up the environment variables for your OpenAI API connection.
+ if not os.getenv("SPLUNK_AO_PROJECT") or not os.getenv("SPLUNK_AO_API_KEY"):
+ raise ValueError("SPLUNK_AO_PROJECT and SPLUNK_AO_API_KEY environment variables are required")
+
+ # Check to see if we already have the dataset, if not we can create it.
+ dataset = get_dataset(
+ name="simple-chatbot-unit-test-dataset",
+ )
+
+ # If we don't have the dataset, create it with some canned data. Some of these questions
+ # are designed to be factual, while others are designed to be nonsensical or not
+ # answerable by the model. This will help us test the correctness and instruction adherence
+ # of the model when running the experiment.
+ if dataset is None:
+ # Load dataset content from JSON file
+ with open("../dataset.json", "r", encoding="utf-8") as f:
+ dataset_content = json.load(f)
+
+ dataset = create_dataset(
+ name="simple-chatbot-unit-test-dataset",
+ content=dataset_content,
+ )
+
+
+def test_run_experiment_with_dataset():
+ """
+ This test will run the dataset against our chatbot app using the Splunk AO experiments framework.
+ This is designed to show how you can run experiments with a dataset against a real-world application
+ to use inside a CI/CD pipeline.
+
+ The default system prompt encourages the assistant to be helpful, but can lead to hallucinations, so
+ this test should fail out of the box.
+
+ To make this test pass, you will need to modify the system prompt in the `app.py` file. There is
+ a comment in the `app.py` file that shows a better system prompt, which should allow this test to pass.
+ """
+ # Run the experiment using the canned dataset
+ experiment_response = run_experiment(
+ # This name is reused, so each experiment run will get a generated name
+ # with the run date and time
+ experiment_name="simple-chatbot-experiment",
+ dataset_name="simple-chatbot-unit-test-dataset",
+ function=chat_with_llm,
+ metrics=[
+ SplunkAOMetrics.correctness,
+ SplunkAOMetrics.instruction_adherence,
+ ],
+ project=os.getenv("SPLUNK_AO_PROJECT"),
+ )
+
+ # Poll until we have the results - waiting 5 seconds between polls
+ # We need to use the project ID and experiment name from the response as we only have the project name, and the experiment name
+ # is generated with a timestamp, so we can't use the name directly.
+ experiment = get_experiment(
+ project_id=experiment_response["experiment"].project_id,
+ experiment_name=experiment_response["experiment"].name,
+ )
+ while (
+ experiment.aggregate_metrics is None
+ or "average_factuality" not in experiment.aggregate_metrics
+ or "average_instruction_adherence" not in experiment.aggregate_metrics
+ ):
+ # If we don't have the metrics calculated, Sleep for 5 seconds before polling again
+ time.sleep(5)
+
+ # Reload the experiment to see if we have the metrics
+ experiment = get_experiment(
+ project_id=experiment_response["experiment"].project_id,
+ experiment_name=experiment_response["experiment"].name,
+ )
+
+ # Assert the experiment has the expected metric values - each should be 1.0
+ # However, the default system prompt can lead to hallucinations, so this test may fail.
+ assert experiment.aggregate_metrics["average_instruction_adherence"] == 1
+ assert experiment.aggregate_metrics["average_factuality"] == 1
diff --git a/examples/dataset-experiments/.env.template b/examples/dataset-experiments/.env.template
new file mode 100644
index 00000000..e782345c
--- /dev/null
+++ b/examples/dataset-experiments/.env.template
@@ -0,0 +1,11 @@
+# Galileo Environment Variables
+GALILEO_API_KEY=your-galileo-api-key # Your Galileo API key.
+GALILEO_PROJECT=your-galileo-project-name # Your Galileo project name.
+GALILEO_LOG_STREAM=your-galileo-log-stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# GALILEO_CONSOLE_URL=your-galileo-console-url # Optional if you are using a hosted version of Galileo
+
+OPENAI_API_KEY=your-openai-api-key
+OPENAI_ORGANIZATION=your-openai-organization
+ANTHROPIC_API_KEY=your-anthropic-api-key
diff --git a/examples/dataset-experiments/app-simple.py b/examples/dataset-experiments/app-simple.py
new file mode 100644
index 00000000..943c4805
--- /dev/null
+++ b/examples/dataset-experiments/app-simple.py
@@ -0,0 +1,36 @@
+from splunk_ao import Message, MessageRole
+from splunk_ao.prompts import get_prompt, create_prompt
+from splunk_ao.experiments import run_experiment
+from splunk_ao.datasets import get_dataset
+from dotenv import load_dotenv
+
+load_dotenv()
+
+project = "datasets-experiments"
+
+prompt = get_prompt(name="geography-prompt")
+if prompt is None:
+ prompt = create_prompt(
+ name="geography-prompt",
+ template=[
+ Message(
+ role=MessageRole.system,
+ content="You are a helpful assistant. Answer questions accurately and concisely.",
+ ),
+ Message(role=MessageRole.user, content="{{input}}"),
+ ],
+ )
+
+results = run_experiment(
+ "geography-experiment",
+ dataset=get_dataset(name="countries"),
+ prompt_template=prompt,
+ # Optional
+ prompt_settings={
+ "max_tokens": 256,
+ "model_alias": "GPT-4o", # Make sure you have an integration set up for the model alias you're using
+ "temperature": 0.8,
+ },
+ metrics=["correctness"],
+ project=project,
+)
diff --git a/examples/dataset-experiments/app.py b/examples/dataset-experiments/app.py
new file mode 100644
index 00000000..0d47331f
--- /dev/null
+++ b/examples/dataset-experiments/app.py
@@ -0,0 +1,107 @@
+"""
+Splunk AO Experiment Runner
+
+This module provides a command-line interface for running Splunk AO experiments
+with custom parameters including project, experiment, dataset, and prompt configurations.
+"""
+
+import argparse
+from datetime import datetime
+from splunk_ao import Message, MessageRole
+from splunk_ao.prompts import get_prompt, create_prompt
+from splunk_ao.experiments import run_experiment
+from splunk_ao.datasets import get_dataset
+from dotenv import load_dotenv
+
+load_dotenv()
+
+
+def main():
+ """
+ Main function to run Splunk AO experiments with command-line parameters.
+
+ Parses command-line arguments, creates or retrieves prompt templates,
+ fetches datasets, and runs experiments with the specified configuration.
+ """
+ print("⚠️ Make sure your project & dataset exist.\n")
+ parser = argparse.ArgumentParser(
+ description="Run a Splunk AO experiment with custom parameters.",
+ epilog='Example: python app.py --project "my-project" \
+ --experiment "my-experiment" \
+ --dataset "my-dataset" \
+ --prompt-template-name "my-prompt" \
+ --prompt-content "You are a helpful assistant."',
+ )
+ parser.add_argument("--project", default="test project", help="Project name")
+ parser.add_argument("--experiment", default="test experiment", help="Experiment name")
+ parser.add_argument(
+ "--prompt-name",
+ default="default",
+ help='Prompt name (optional, defaults to "default")',
+ )
+ parser.add_argument("--dataset", default="default", help="Dataset name")
+ parser.add_argument(
+ "--prompt-content",
+ default="You are an assistant. Respond to the user input.",
+ help="Prompt content",
+ )
+ args = parser.parse_args()
+ project = args.project
+ experiment_name = args.experiment
+ prompt_name = args.prompt_name
+ dataset_name = args.dataset
+ prompt_content = args.prompt_content
+ prompt = get_prompt(name=prompt_name)
+ if prompt is None:
+ try:
+ prompt = create_prompt(
+ name=prompt_name,
+ template=[
+ Message(
+ role=MessageRole.system,
+ content=prompt_content,
+ ),
+ Message(role=MessageRole.user, content="{{input}}"),
+ ],
+ )
+ except Exception as exc:
+ # Check if it's an "already exists" error
+ if "already exists" in str(exc).lower():
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+ new_prompt_name = f"{prompt_name}_{timestamp}"
+ print(f"Template '{prompt_name}' already exists. Creating new template: '{new_prompt_name}'")
+
+ prompt = create_prompt(
+ name=new_prompt_name,
+ template=[
+ Message(
+ role=MessageRole.system,
+ content=prompt_content,
+ ),
+ Message(role=MessageRole.user, content="{{input}}"),
+ ],
+ )
+ else:
+ # Re-raise if it's a different error
+ raise
+ print(f"Fetching dataset with name: {dataset_name}")
+ dataset = get_dataset(name=dataset_name)
+ run_experiment(
+ experiment_name,
+ dataset=dataset,
+ prompt_template=prompt,
+ prompt_settings={
+ "max_tokens": 256,
+ "model_alias": "GPT-4o",
+ "temperature": 0.8,
+ },
+ metrics=["correctness"],
+ project=project,
+ )
+ print("-" * 60)
+ print(f"Experiment '{experiment_name}' completed successfully!")
+ print("-" * 60)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/dataset-experiments/experiment_compare_two_models.py b/examples/dataset-experiments/experiment_compare_two_models.py
new file mode 100644
index 00000000..319c429e
--- /dev/null
+++ b/examples/dataset-experiments/experiment_compare_two_models.py
@@ -0,0 +1,337 @@
+"""
+This module provides functionality to compare the performance of two LLMs using Splunk AO experiments.
+"""
+
+import os
+import json
+import sys
+import argparse
+from typing import List, Dict, Any
+from datetime import datetime
+from dotenv import load_dotenv
+import anthropic
+from openai import OpenAI
+from splunk_ao import Message, MessageRole
+from splunk_ao.prompts import create_prompt, get_prompt_template
+from splunk_ao.experiments import run_experiment
+from splunk_ao.datasets import create_dataset
+
+load_dotenv()
+
+
+class ExperimentCompareTwoModels:
+ """
+ This class is used to create Splunk AO experiments to compare the performance of two LLMs.
+ """
+
+ def __init__(self):
+ """
+ Initializes the ExperimentCompareTwoModels class with OpenAI and Anthropic clients, and sets up model configurations.
+ """
+ self.openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
+ self.anthropic_client = anthropic.Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))
+ self.galileo_project = os.getenv("SPLUNK_AO_PROJECT")
+
+ if not self.galileo_project:
+ raise ValueError("SPLUNK_AO_PROJECT environment variable is required")
+
+ self.model_configs = {
+ "openai": {
+ "name": "gpt-4.1-mini",
+ "provider": "OpenAI",
+ "cost_per_1k_tokens": 0.00015,
+ "performance_score": 0.85,
+ "context_window": 128000,
+ "client": self.openai_client,
+ },
+ "anthropic": {
+ "name": "Claude 3.7 Sonnet",
+ "provider": "Anthropic",
+ "cost_per_1k_tokens": 0.00015,
+ "performance_score": 0.88,
+ "context_window": 200000,
+ "client": self.anthropic_client,
+ },
+ }
+
+ # Prompt for simulating an LLM based app - A Data Quality Processor
+ self.system_prompt = """You are an expert financial data quality analyst. Your task is to clean and \
+ validate financial transaction data.
+
+ Given a financial transaction record, you should:
+ 1. Identify any data quality issues (missing fields, invalid formats, inconsistencies)
+ 2. Suggest corrections or flag records that need manual review
+ 3. Provide confidence scores for your assessments
+ 4. Estimate the potential financial impact of data quality issues
+
+ Respond with a JSON object containing:
+ - "issues_found": List of data quality issues
+ - "suggested_corrections": List of suggested fixes
+ - "confidence_score": 0-1 score of your assessment confidence
+ - "financial_impact": Estimated dollar impact if issues are not fixed
+ - "requires_manual_review": Boolean indicating if human review is needed
+ - "clean_record": The cleaned transaction record (if possible)
+
+ Focus on accuracy and financial impact assessment.
+ """
+
+ def read_jsonl_file(self, file_path: str) -> List[Dict[str, Any]]:
+ """
+ Reads a JSONL file and returns a list of transactions.
+
+ :param file_path: Path to the JSONL file.
+ :return: List of transactions.
+ """
+ transactions = []
+ try:
+ with open(file_path, "r", encoding="utf-8") as file:
+ for line_num, line in enumerate(file, 1):
+ line = line.strip()
+ if line:
+ try:
+ transaction = json.loads(line)
+ transactions.append(transaction)
+ except json.JSONDecodeError as e:
+ print(f"Warning: Invalid JSON on line {line_num}: {e}")
+ continue
+
+ print(f"Loaded {len(transactions)} transactions from {file_path}")
+ return transactions
+
+ except FileNotFoundError as e:
+ raise FileNotFoundError(f"JSONL file not found: {file_path}") from e
+ except Exception as e:
+ raise Exception(f"Error reading JSONL file: {e}") from e
+
+ def create_galileo_dataset(self, transactions: List[Dict[str, Any]], dataset_name: str) -> Any:
+ """
+ Creates a Splunk AO dataset from a list of transactions.
+
+ :param transactions: List of transactions.
+ :param dataset_name: Name of the dataset.
+ :return: Created dataset.
+ """
+ try:
+ dataset_content = []
+ for transaction in transactions:
+ dataset_content.append({"transaction_data": json.dumps(transaction, ensure_ascii=False)})
+
+ dataset = create_dataset(
+ name=dataset_name,
+ content=dataset_content,
+ )
+
+ print(f"Created Splunk AO dataset '{dataset_name}' with {len(transactions)} records")
+ return dataset
+
+ except Exception as e:
+ raise Exception(f"Error creating Splunk AO dataset: {e}") from e
+
+ def openai_llm_call(self, input_data: str) -> str:
+ """
+ Calls the OpenAI LLM with the provided input data.
+
+ :param input_data: Input data for the LLM.
+ :return: Response from the LLM.
+ """
+ try:
+ response = self.openai_client.responses.create(
+ model=self.model_configs["openai"]["name"],
+ input=[
+ {"role": "system", "content": self.system_prompt},
+ {"role": "user", "content": f"Process this financial transaction data: {input_data}"},
+ ],
+ temperature=0.1,
+ max_output_tokens=1000,
+ )
+
+ text = getattr(response, "output_text", None)
+ if text:
+ return text
+
+ return str(response)
+ except Exception as e:
+ return f"Error calling OpenAI API: {e}"
+
+ def anthropic_llm_call(self, input_data: str) -> str:
+ """
+ Calls the Anthropic LLM with the provided input data.
+
+ :param input_data: Input data for the LLM.
+ :return: Response from the LLM.
+ """
+ try:
+ response = self.anthropic_client.messages.create(
+ model=self.model_configs["anthropic"]["name"],
+ max_tokens=1000,
+ temperature=0.8,
+ system=self.system_prompt,
+ messages=[
+ {
+ "role": "user",
+ "content": [{"type": "text", "text": f"Process this financial transaction data: {input_data}"}],
+ }
+ ],
+ )
+ return response.content[0].text if response.content else ""
+ except Exception as e:
+ return f"Error calling Anthropic API: {e}"
+
+ def run_model_experiment(self, experiment_name: str, params: Dict[str, Any]) -> None:
+ """
+ Runs a model experiment using the specified parameters.
+
+ :param experiment_name: Name of the experiment.
+ :param params: Dictionary containing dataset, prompt_template, llm_function, and model_config.
+ """
+ try:
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")[:-3]
+ experiment_name = f"{experiment_name}_{timestamp}"
+ print(f"Running experiment: {experiment_name}")
+ try:
+
+ # 2 types of experiments
+ # Runner function experiment: entry point to the app or a function in the codebase.
+ # Prompt experiment
+ results = run_experiment(
+ experiment_name=experiment_name,
+ dataset=params["dataset"],
+ prompt_template=params["prompt_template"],
+ prompt_settings={"max_tokens": 1000, "model_alias": params["model_config"]["name"], "temperature": 0.8},
+ metrics=["correctness", "structural_correctness_fin_tx"],
+ project=self.galileo_project,
+ )
+
+ print(f"Experiment results for {experiment_name}: {results}")
+
+ except Exception as exp_error:
+ print(f"Splunk AO experiment error: {exp_error}")
+ print(f"Model used: {params['model_config']['provider']} - {params['model_config']['name']}")
+
+ print(f"Experiment '{experiment_name}' completed successfully!")
+
+ except Exception as e:
+ print(f"Error running experiment '{experiment_name}': {e}")
+ print(f"Full error details: {type(e).__name__}: {str(e)}")
+ print(f"Model config: {params['model_config']}")
+ print(f"LLM function: {params['llm_function'].__name__}")
+
+ def run_comparison_experiments(self, jsonl_file_path: str, dataset_name: str = None) -> None:
+ """
+ Runs comparison experiments using the provided JSONL file and optional dataset name.
+
+ :param jsonl_file_path: Path to the JSONL file.
+ :param dataset_name: Optional name for the dataset.
+ """
+ try:
+ transactions = self.read_jsonl_file(jsonl_file_path)
+
+ if not transactions:
+ print("No valid transactions found in the JSONL file")
+ return
+
+ if not dataset_name:
+ timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
+ dataset_name = f"financial-transactions-{timestamp}"
+
+ dataset = self.create_galileo_dataset(transactions, dataset_name)
+
+ prompt_template = self.get_or_create_prompt_template()
+
+ print("\n" + "=" * 50)
+ print("Running OpenAI Experiment")
+ print("=" * 50)
+ self.run_model_experiment(
+ experiment_name="test_openai",
+ params={
+ "dataset": dataset,
+ "prompt_template": prompt_template,
+ "llm_function": self.openai_llm_call,
+ "model_config": self.model_configs["openai"],
+ },
+ )
+
+ print("\n" + "=" * 50)
+ print("Running Anthropic Experiment")
+ print("=" * 50)
+ self.run_model_experiment(
+ experiment_name="test_anthropic",
+ params={
+ "dataset": dataset,
+ "prompt_template": prompt_template,
+ "llm_function": self.anthropic_llm_call,
+ "model_config": self.model_configs["anthropic"],
+ },
+ )
+
+ print("\n" + "=" * 50)
+ print("All experiments completed.")
+ print("=" * 50)
+
+ except Exception as e:
+ print(f"Error running comparison experiments: {e}")
+
+ def get_or_create_prompt_template(self) -> Any:
+ """
+ Retrieves or creates a prompt template for financial data quality.
+
+ :return: Prompt template.
+ """
+ prompt_name = "finance_data_quality_prompt"
+
+ try:
+ prompt_template = get_prompt_template(name=prompt_name)
+ print(f"Using existing prompt template: {prompt_name}")
+ return prompt_template
+ except Exception:
+ print(f"Creating new prompt template: {prompt_name}")
+ prompt_template = create_prompt(
+ name=prompt_name,
+ template=[
+ Message(role=MessageRole.system, content=self.system_prompt),
+ Message(role=MessageRole.user, content="Process this financial transaction data: {{transaction_data}}"),
+ ],
+ )
+ return prompt_template
+
+ def get_optimal_model(self, context: Dict[str, Any]) -> str:
+ """
+ Determines the optimal model based on the provided context.
+
+ :param context: Context for model selection.
+ :return: Name of the optimal model.
+ """
+ if context.get("budget_constrained", False):
+ return "openai"
+ if context.get("high_accuracy_required", False):
+ return "anthropic"
+ return max(self.model_configs.keys(), key=lambda x: self.model_configs[x]["performance_score"])
+
+
+def main():
+ """
+ Main function to execute the intelligent broker system for financial data quality.
+ """
+ parser = argparse.ArgumentParser(description="Intelligent Broker System for Financial Data Quality")
+
+ parser.add_argument("jsonl_file", help="Path to the JSONL file containing financial transactions")
+ parser.add_argument("--dataset-name", help="Optional name for the Splunk AO dataset")
+ parser.add_argument("--project", default=os.getenv("SPLUNK_AO_PROJECT"), help="Splunk AO project name (defaults to SPLUNK_AO_PROJECT env var)")
+
+ args = parser.parse_args()
+
+ if not args.project:
+ print("Error: Project name must be provided via --project argument or SPLUNK_AO_PROJECT environment variable")
+ sys.exit(1)
+
+ try:
+ broker = ExperimentCompareTwoModels()
+ broker.run_comparison_experiments(args.jsonl_file, args.dataset_name)
+
+ except Exception as e:
+ print(f"Error: {e}")
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/dataset-experiments/requirements.txt b/examples/dataset-experiments/requirements.txt
new file mode 100644
index 00000000..9b9195c5
--- /dev/null
+++ b/examples/dataset-experiments/requirements.txt
@@ -0,0 +1,3 @@
+anthropic==0.67.0
+galileo==1.27.1
+openai==2.6.0
diff --git a/examples/dataset-experiments/sample_financial_transactions.jsonl b/examples/dataset-experiments/sample_financial_transactions.jsonl
new file mode 100644
index 00000000..8b519e24
--- /dev/null
+++ b/examples/dataset-experiments/sample_financial_transactions.jsonl
@@ -0,0 +1,10 @@
+{"transaction_id": "TXN001", "amount": 1500.00, "currency": "USD", "account_number": "1234567890", "transaction_type": "DEBIT", "description": "Office supplies purchase", "date": "2024-01-15", "merchant": "Office Depot", "category": "BUSINESS_EXPENSE", "status": "COMPLETED"}
+{"transaction_id": "TXN002", "amount": 2500.50, "currency": "USD", "account_number": "1234567890", "transaction_type": "CREDIT", "description": "Client payment received", "date": "2024-01-16", "merchant": "ABC Corp", "category": "REVENUE", "status": "COMPLETED"}
+{"transaction_id": "TXN003", "amount": null, "currency": "USD", "account_number": "1234567890", "transaction_type": "DEBIT", "description": "Software subscription", "date": "2024-01-17", "merchant": "Adobe", "category": "SUBSCRIPTION", "status": "PENDING"}
+{"transaction_id": "TXN004", "amount": 750.25, "currency": "EUR", "account_number": "9876543210", "transaction_type": "DEBIT", "description": "Conference registration", "date": "2024-01-18", "merchant": "TechConf 2024", "category": "TRAVEL", "status": "COMPLETED"}
+{"transaction_id": "TXN005", "amount": 1200.00, "currency": "USD", "account_number": "1234567890", "transaction_type": "DEBIT", "description": "Employee salary", "date": "2024-01-19", "merchant": "John Smith", "category": "PAYROLL", "status": "COMPLETED"}
+{"transaction_id": "TXN006", "amount": 500.00, "currency": "USD", "account_number": "", "transaction_type": "DEBIT", "description": "Marketing campaign", "date": "2024-01-20", "merchant": "Google Ads", "category": "MARKETING", "status": "COMPLETED"}
+{"transaction_id": "TXN007", "amount": 3000.75, "currency": "USD", "account_number": "1234567890", "transaction_type": "CREDIT", "description": "Investment dividend", "date": "2024-01-21", "merchant": "Vanguard", "category": "INVESTMENT", "status": "COMPLETED"}
+{"transaction_id": "TXN008", "amount": 150.00, "currency": "USD", "account_number": "1234567890", "transaction_type": "DEBIT", "description": "Bank fees", "date": "2024-01-22", "merchant": "Chase Bank", "category": "FEES", "status": "COMPLETED"}
+{"transaction_id": "TXN009", "amount": 800.00, "currency": "USD", "account_number": "1234567890", "transaction_type": "DEBIT", "description": "Equipment purchase", "date": "2024-01-23", "merchant": "Dell", "category": "EQUIPMENT", "status": "COMPLETED"}
+{"transaction_id": "TXN010", "amount": 450.25, "currency": "USD", "account_number": "1234567890", "transaction_type": "DEBIT", "description": "Insurance premium", "date": "2024-01-24", "merchant": "State Farm", "category": "INSURANCE", "status": "COMPLETED"}
diff --git a/examples/experiments/multi-turn/.env.example b/examples/experiments/multi-turn/.env.example
new file mode 100644
index 00000000..bcd23100
--- /dev/null
+++ b/examples/experiments/multi-turn/.env.example
@@ -0,0 +1,5 @@
+GALILEO_API_KEY="your-galileo-api-key"
+GALILEO_PROJECT="your-galileo-project"
+
+# Provide the console url below if you are not using app.galileo.ai
+# GALILEO_CONSOLE_URL="your-galileo-console-url"
diff --git a/examples/experiments/multi-turn/README.md b/examples/experiments/multi-turn/README.md
new file mode 100644
index 00000000..2d376fcd
--- /dev/null
+++ b/examples/experiments/multi-turn/README.md
@@ -0,0 +1,87 @@
+# Multi-Turn Experiment Example
+
+The example in this folder demonstrates how to use [create_experiment](https://docs.galileo.ai/sdk-api/python/reference/experiments#create_experiment) to compute a session-level metric for a multi-turn conversation.
+
+## Setup Instructions
+
+### 1. Create and Activate Virtual Environment
+
+```bash
+# Navigate to the example folder
+cd python/experiments/multi-turn
+
+# Create virtual environment
+python -m venv venv
+
+# Activate virtual environment
+source venv/bin/activate
+```
+
+### 2. Install Dependencies
+
+Run
+
+```bash
+pip install -r requirements.txt
+```
+
+### 3. Configure Environment Variables
+
+Your `.env` should look like this. Feel free to follow the `.env.example` and enter your credentials
+
+```bash
+
+# Required: Your Splunk AO API key
+SPLUNK_AO_API_KEY="your-splunk-ao-api-key"
+
+# Required: Splunk AO project name
+SPLUNK_AO_PROJECT="your-splunk-ao-project"
+
+# Provide the console url below if you are not using app.galileo.ai
+# SPLUNK_AO_CONSOLE_URL="your-splunk-ao-console-url"
+```
+
+### 4. Add Integration in Splunk AO Console
+
+The session-level metric in this example uses an LLM.
+
+Make sure that you've configured a valid LLM integration in the Splunk AO console.
+
+Related documentation: [Configure an LLM integration](https://docs.galileo.ai/getting-started/evaluate-and-improve/evaluate-and-improve#configure-an-llm-integration)
+
+## Basic Example
+
+Run the basic example:
+
+```bash
+python basic-example.py
+```
+
+The `METRIC_NAME` variable in this script cites a session-level metric.
+
+Pre-defined session-level metrics include:
+
+- `SplunkAOMetrics.conversation_quality`
+- `SplunkAOMetrics.action_completion`
+- `SplunkAOMetrics.action_advancement`
+- `SplunkAOMetrics.agent_efficiency`
+- `SplunkAOMetrics.context_adherence`
+- `SplunkAOMetrics.context_relevance`
+- `SplunkAOMetrics.tool_error_rate`
+
+Related documentation: [Metrics Comparison](https://docs.galileo.ai/concepts/metrics/metric-comparison)
+
+Optionally, you can define your own custom session-level metric in the Splunk AO Console UI, and then add the custom metric name.
+
+
+
+## Troubleshooting
+
+Visit the "Sessions" tab of the Experiment in the Splunk AO Console to confirm the status of the metric computation.
+
+
+
+If you see an auth error, go to the metric details and make sure that a [valid integration](https://docs.galileo.ai/getting-started/evaluate-and-improve/evaluate-and-improve#configure-an-llm-integration) has been configured.
+
+
+
diff --git a/examples/experiments/multi-turn/basic-example.py b/examples/experiments/multi-turn/basic-example.py
new file mode 100644
index 00000000..87491b27
--- /dev/null
+++ b/examples/experiments/multi-turn/basic-example.py
@@ -0,0 +1,97 @@
+import os
+import time
+
+from splunk_ao import splunk_ao_context, SplunkAOMetrics
+from splunk_ao.experiments import create_experiment
+from splunk_ao.projects import get_project, create_project
+from splunk_ao.search import get_sessions
+from splunk_ao.utils.metrics import create_metric_configs
+from galileo.resources.models import MetricSuccess
+
+# Provide the name of a session-level metric
+METRIC_NAME = SplunkAOMetrics.conversation_quality
+
+# example custom metric name (must be set up in advance)
+# METRIC_NAME = "multi-turn-session-test-metric-apples"
+
+# Load environment variables from the .env file
+from dotenv import load_dotenv
+
+load_dotenv()
+
+# Get the Splunk AO project
+
+project_name = os.getenv("SPLUNK_AO_PROJECT")
+project_obj = get_project(name=project_name)
+if not project_obj:
+ project_obj = create_project(project_name)
+
+print(f"Project name: {project_obj.name}, Project ID: {project_obj.id}")
+
+# Create a unique experiment
+
+time_suffix = time.strftime("%m%d-%H%M")
+
+experiment = create_experiment(experiment_name=f"multi-turn-experiment-{time_suffix}", experiment_group="multi-turn examples")
+print(f"Experiment name: {experiment.name}")
+
+splunk_ao_context.init(project=project_obj.name, experiment_id=experiment.id)
+
+# Enable a session-level metric in the created experiment, and get the metric ID
+
+metric_configs, _ = create_metric_configs(
+ project_id=project_obj.id,
+ run_id=experiment.id,
+ metrics=[METRIC_NAME],
+)
+assert len(metric_configs) == 1
+metric_name = metric_configs[0].name
+metric_id = metric_configs[0].id
+print(f"Metric Name: {metric_name}")
+print(f"Metric ID: {metric_id}")
+
+# Log a multi-turn convo using Splunk AO context and logger
+
+multi_turn_convo = [
+ {"user": "What is your favorite fruit?", "assistant": "I like blueberries. What about you?"},
+ {"user": "I like strawberries.", "assistant": "Strawberries are great! Do you like blueberries too?"},
+ {"user": "Yes, I do!", "assistant": "Awesome! Blueberries are delicious and packed with nutrients."},
+]
+
+
+logger = splunk_ao_context.get_logger_instance(project=project_obj.name, experiment_id=experiment.id)
+
+# Create a session and log traces for each turn in the conversation
+
+logger.start_session()
+
+for turn in multi_turn_convo:
+
+ logger.start_trace(input=turn["user"], name="User turn")
+ logger.add_llm_span(
+ input=turn["user"],
+ output=turn["assistant"],
+ model="gpt-5.4-mini",
+ )
+ logger.conclude(output=turn["assistant"])
+
+
+splunk_ao_context.flush()
+
+# Poll the session-level metric until it's computed
+
+status = "unknown"
+while True:
+
+ sessions = get_sessions(project_id=project_obj.id, experiment_id=experiment.id)
+ assert len(sessions.records) > 0, "No sessions found for the experiment"
+
+ session = sessions.records[0]
+ metric = session.metric_info[metric_id]
+
+ if isinstance(metric, MetricSuccess):
+ print(f"Metric {METRIC_NAME} computed successfully with value: {metric.value}")
+ break
+ print("Metric is not computed yet, retrying in 10 seconds...")
+
+ time.sleep(10)
diff --git a/examples/experiments/multi-turn/requirements.txt b/examples/experiments/multi-turn/requirements.txt
new file mode 100644
index 00000000..1bde28c3
--- /dev/null
+++ b/examples/experiments/multi-turn/requirements.txt
@@ -0,0 +1,2 @@
+galileo
+python-dotenv
diff --git a/examples/experiments/multi-turn/screenshot-custom-session-level-boolean-metric.png b/examples/experiments/multi-turn/screenshot-custom-session-level-boolean-metric.png
new file mode 100644
index 00000000..546a5819
Binary files /dev/null and b/examples/experiments/multi-turn/screenshot-custom-session-level-boolean-metric.png differ
diff --git a/examples/experiments/multi-turn/screenshot-session-level-metric-auth-error.png b/examples/experiments/multi-turn/screenshot-session-level-metric-auth-error.png
new file mode 100644
index 00000000..1dde2629
Binary files /dev/null and b/examples/experiments/multi-turn/screenshot-session-level-metric-auth-error.png differ
diff --git a/examples/experiments/multi-turn/screenshot-session-level-metric-details.png b/examples/experiments/multi-turn/screenshot-session-level-metric-details.png
new file mode 100644
index 00000000..954f7be6
Binary files /dev/null and b/examples/experiments/multi-turn/screenshot-session-level-metric-details.png differ
diff --git a/examples/experiments/rag-and-tools/.env.example b/examples/experiments/rag-and-tools/.env.example
new file mode 100644
index 00000000..d3c7de87
--- /dev/null
+++ b/examples/experiments/rag-and-tools/.env.example
@@ -0,0 +1,10 @@
+# Galileo Environment Variables
+GALILEO_API_KEY= # Your Galileo API key.
+GALILEO_PROJECT= # Your Galileo project name.
+GALILEO_LOG_STREAM= # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# GALILEO_CONSOLE_URL= # Optional if you are using a hosted version of Galileo
+
+# OpenAI Environment Variables
+OPENAI_API_KEY= # Your OpenAI API key.
diff --git a/examples/experiments/rag-and-tools/README.md b/examples/experiments/rag-and-tools/README.md
new file mode 100644
index 00000000..4b49fe4c
--- /dev/null
+++ b/examples/experiments/rag-and-tools/README.md
@@ -0,0 +1,60 @@
+# Experiments with RAG and tools
+
+This is an example project demonstrating how to use Splunk AO experiments with applications that use RAG and tools.
+
+This code is used in the [Run an experiment against a RAG app](http://docs.galileo.ai/how-to-guides/experiments/rag-app/rag-app) how-to guide in the Splunk AO documentation.
+
+## Get Started
+
+To get started with this project, you'll need to have Python 3.10 or later installed. You can then install the required dependencies in a virtual environment:
+
+```bash
+pip install -r requirements.txt
+```
+
+## Configure environment variables
+
+You will need to configure environment variables to use this project. Copy the `.env.example` file to `.env`, then update the environment variables in the `.env` file with your OpenAI and Splunk AO values:
+
+```ini
+# Splunk AO environment variables
+SPLUNK_AO_API_KEY=
+SPLUNK_AO_PROJECT=
+SPLUNK_AO_LOG_STREAM=
+
+# OpenAI environment variables
+OPENAI_API_KEY=
+```
+
+## Usage
+
+This sample contains both an application that generates a fake horoscope using a tool and a mock RAG function, as well as an experiment to test the same code.
+
+To run the application, run:
+
+```bash
+python app.py
+```
+
+Traces will be captured and logged to Splunk AO.
+
+To run the experiment, run:
+
+```bash
+python experiment.py
+```
+
+A link to the results of the experiment will be written to the console.
+
+## Project Structure
+
+The project structure is as follows:
+
+```folder
+rag-and-tools/
+├── env.example # List of environment variables
+├── requirements.txt # Python project requirements
+├── app.py # The main python application
+├── experiment.py # Code to run the main application as an experiment
+└── README.md # Project documentation
+```
diff --git a/examples/experiments/rag-and-tools/app.py b/examples/experiments/rag-and-tools/app.py
new file mode 100644
index 00000000..18674365
--- /dev/null
+++ b/examples/experiments/rag-and-tools/app.py
@@ -0,0 +1,173 @@
+import json
+
+from splunk_ao import log, splunk_ao_context
+
+from splunk_ao.openai import OpenAI
+
+from dotenv import load_dotenv
+
+# Load environment variables from .env file
+load_dotenv(override=True)
+
+
+# A mock RAG retriever function
+@log(span_type="retriever")
+def retrieve_horoscope_data(sign):
+ """
+ Mock function to simulate retrieving horoscope data for a given sign.
+ This is decorated with logging for tracing a retriever span.
+ """
+ horoscopes = {
+ "Aquarius": [
+ "Next Tuesday you will befriend a baby otter.",
+ "Next Tuesday you will find a dollar on the ground.",
+ ],
+ "Taurus": [
+ "Next Tuesday you will find a four-leaf clover.",
+ "Next Tuesday you will have a great conversation with a stranger.",
+ ],
+ "Gemini": [
+ "Next Tuesday you will learn to juggle.",
+ "Next Tuesday you will discover a new favorite book.",
+ ],
+ }
+ return horoscopes.get(sign, ["No horoscope available."])
+
+
+@log(span_type="tool")
+def get_horoscope(sign):
+ """
+ Tool function to get a horoscope for a given astrological sign.
+ """
+ return "\n".join(retrieve_horoscope_data(sign))
+
+
+# Define a list of callable tools for the model
+tools = [
+ {
+ "type": "function",
+ "function": {
+ "name": "get_horoscope",
+ "description": "Get today's horoscope for an astrological sign.",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "sign": {
+ "type": "string",
+ "description": "An astrological sign like Taurus or Aquarius",
+ },
+ },
+ "required": ["sign"],
+ },
+ },
+ },
+]
+
+# Map tool names to their implementations
+available_tools = {"get_horoscope": get_horoscope}
+
+
+# Create the OpenAI client
+client = OpenAI()
+
+
+def call_llm(messages):
+ """
+ Call the LLM with the provided messages and tools.
+ """
+ return client.chat.completions.create(
+ model="gpt-5.1",
+ tools=tools,
+ messages=messages,
+ )
+
+
+def get_users_horoscope(sign: str) -> str:
+ """
+ Get the user's horoscope
+ """
+ # Create a running message history list we will add to over time
+ message_history = [
+ {
+ "role": "system",
+ "content": """
+ You are a helpful assistant that provides horoscopes.
+ Provide a flowery response based off any information retrieved.
+ Include typical horoscope phrases, and characteristics of
+ the sign in question.
+ """,
+ },
+ {"role": "user", "content": f"What is my horoscope? I am {sign}."},
+ ]
+
+ # Prompt the model with tools defined
+ response = call_llm(message_history)
+
+ # Call any tools the model requested
+ completion_tool_calls = response.choices[0].message.tool_calls
+
+ if completion_tool_calls:
+ # Add any tool calls to the message history
+ message_history.append(
+ {
+ "role": "assistant",
+ "tool_calls": [
+ {
+ "id": call.id,
+ "type": "function",
+ "function": {
+ "name": call.function.name,
+ "arguments": call.function.arguments,
+ },
+ }
+ for call in completion_tool_calls
+ ],
+ }
+ )
+
+ for call in completion_tool_calls:
+ # Get the tool to call and its arguments
+ tool_to_call = available_tools[call.function.name]
+ args = json.loads(call.function.arguments)
+
+ # Call the tool
+ tool_result = tool_to_call(**args)
+
+ # Add the tool result to the message history
+ message_history.append(
+ {
+ "role": "tool",
+ "content": tool_result,
+ "tool_call_id": call.id,
+ "name": call.function.name,
+ }
+ )
+
+ # Now we call the model again, with the tool results included
+ response = call_llm(message_history)
+
+ # Return the final response from the model
+ return response.choices[0].message.content
+
+
+def main():
+ """
+ Get the user's horoscope
+ """
+ # Start a session and trace
+ galileo_logger = splunk_ao_context.get_logger_instance()
+ galileo_logger.start_session("RAG with Tools Example")
+ galileo_logger.start_trace(input="What is my horoscope? I am Aquarius.", name="Calling LLM with Tool")
+ galileo_logger.start_trace(input="What is my horoscope? I am Aquarius.", name="Calling LLM with Tool")
+
+ response = get_users_horoscope("Aquarius")
+
+ # Conclude the trace and flush
+ galileo_logger.conclude(response)
+ galileo_logger.flush()
+
+ print(response)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/experiments/rag-and-tools/experiment.py b/examples/experiments/rag-and-tools/experiment.py
new file mode 100644
index 00000000..aa4c19a8
--- /dev/null
+++ b/examples/experiments/rag-and-tools/experiment.py
@@ -0,0 +1,42 @@
+import os
+
+from splunk_ao import SplunkAOMetrics
+from splunk_ao.experiments import run_experiment
+
+from app import get_users_horoscope
+
+
+def main():
+ """
+ Run the horoscope experiment
+ """
+ # Define a dataset of astrological signs to use
+ # in the experiment
+ dataset = [
+ {"input": "Aquarius"},
+ {"input": "Taurus"},
+ {"input": "Gemini"},
+ {"input": "Leo"},
+ ]
+
+ # Run the experiment
+ results = run_experiment(
+ "horoscope-experiment-2",
+ dataset=dataset,
+ function=get_users_horoscope,
+ metrics=[
+ SplunkAOMetrics.tool_error_rate,
+ SplunkAOMetrics.tool_selection_quality,
+ SplunkAOMetrics.chunk_attribution_utilization,
+ SplunkAOMetrics.context_adherence,
+ ],
+ project=os.environ["SPLUNK_AO_PROJECT"],
+ )
+
+ # Print a link to the experiment results
+ print("Experiment Results:")
+ print(results["link"])
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/experiments/rag-and-tools/requirements.txt b/examples/experiments/rag-and-tools/requirements.txt
new file mode 100644
index 00000000..511a3cf0
--- /dev/null
+++ b/examples/experiments/rag-and-tools/requirements.txt
@@ -0,0 +1,2 @@
+galileo[openai]
+python-dotenv
diff --git a/examples/experiments/upload_experiment/.env.example b/examples/experiments/upload_experiment/.env.example
new file mode 100644
index 00000000..405570a5
--- /dev/null
+++ b/examples/experiments/upload_experiment/.env.example
@@ -0,0 +1,12 @@
+# Galileo API Configuration
+# Copy this file to .env and fill in your actual values
+
+# Your Galileo API key
+GALILEO_API_KEY=your_api_key_here
+
+# Galileo Console URL
+GALILEO_CONSOLE_URL=https://app.galileo.ai
+
+# Galileo Project Name
+GALILEO_PROJECT=your_project_name
+
diff --git a/examples/experiments/upload_experiment/README.md b/examples/experiments/upload_experiment/README.md
new file mode 100644
index 00000000..98d30847
--- /dev/null
+++ b/examples/experiments/upload_experiment/README.md
@@ -0,0 +1,176 @@
+# Upload Existing Evaluation Results to Splunk AO
+
+This example demonstrates how to upload evaluation results you've already generated to Splunk AO for analysis, visualization, and comparison.
+
+## Use Case
+
+Sometimes you've already run evaluations—whether with a different tool, offline, or in the past—and you want to centralize and visualize those results in Splunk AO. This example shows you how to:
+
+- ✅ Upload historical evaluation data to Splunk AO experiments
+- ✅ Reconstruct full execution traces for debugging
+- ✅ Compute Splunk AO metrics on existing results
+
+This is particularly useful when:
+
+- You have legacy evaluation data to migrate to Splunk AO
+- You ran evaluations with custom tooling and want unified visualization
+- You need to analyze past model behavior with Splunk AO's evaluation metrics
+
+## What This Example Does
+
+**The Problem:** Splunk AO v2 experiments typically run your prompts live, but sometimes you already have the results and just want to upload them.
+
+**The Solution:** This example takes your pre-existing evaluation data (questions, contexts, LLM responses, ground truth) and uploads it to Splunk AO as a completed experiment with full tracing.
+
+**How it Works:**
+
+1. Your JSON file contains complete evaluation records (question, context chunks array, LLM answer, ground truth)
+2. A Splunk AO dataset is created with inputs and expected outputs
+3. An experiment "replays" your results, reconstructing execution traces with proper chunk attribution
+4. Splunk AO computes metrics and provides full visualization
+
+## Data Format
+
+Your evaluation data should be in JSON format with the following structure:
+
+```json
+[
+ {
+ "question": "Your input/question text",
+ "context": ["chunk1", "chunk2", "chunk3"], // Array of context chunks
+ "llm_answer": "The response your model generated",
+ "ground_truth_answer": "The expected correct answer",
+ "model": "gpt-4o" // Optional: specify the model used
+ }
+]
+```
+
+**Required fields:**
+
+- `question` - The input to your system
+- `llm_answer` - The response your system generated
+- `ground_truth_answer` - The expected/correct answer
+
+**Optional fields:**
+
+- `context` - Array of retrieved context chunks (for RAG systems).
+- `model` - Model identifier (defaults to "gpt-4o" if not specified)
+
+## Setup
+
+### 1. Install Dependencies
+
+```bash
+python -m venv venv
+source venv/bin/activate # On Windows: venv\Scripts\activate
+pip install -r requirements.txt
+```
+
+### 2. Configure Environment
+
+Copy `.env.example` to `.env` and add your Splunk AO credentials:
+
+```bash
+cp .env.example .env
+```
+
+Edit `.env`:
+
+```
+SPLUNK_AO_API_KEY=your_api_key_here
+SPLUNK_AO_CONSOLE_URL=https://app.galileo.ai
+SPLUNK_AO_PROJECT=your_project_name
+```
+
+**Getting your Splunk AO credentials:**
+
+1. Log in to [Splunk AO Console](https://app.galileo.ai)
+2. Navigate to Settings → API Keys
+3. Create a new API key or copy an existing one
+4. Create or select a project for your experiments
+
+### 3. Prepare Your Data
+
+Place your evaluation results in `dataset.json` following the format above. See the included example file with space mission support Q&A data.
+
+## Running the Example
+
+```bash
+python upload_existing_results.py
+```
+
+The script will:
+
+1. ✅ Load your evaluation data from `dataset.json`
+2. ✅ Create or retrieve a Splunk AO dataset
+3. ✅ Upload an experiment with full trace reconstruction
+4. ✅ Provide a link to view results in the Splunk AO console
+
+## Customization
+
+### Changing the Dataset
+
+Edit `dataset.json` with your own evaluation data. The example uses space mission support Q&A, but you can use any domain.
+
+### Adjusting Metrics
+
+In `upload_existing_results.py`, modify the `metrics` parameter in `upload_experiment()`:
+
+```python
+from splunk_ao.schema.metrics import SplunkAOMetrics
+
+custom_metrics = [
+ SplunkAOMetrics.ground_truth_adherence,
+ SplunkAOMetrics.context_adherence,
+ SplunkAOMetrics.correctness,
+ # Add any other Splunk AO metrics you want
+]
+
+upload_experiment(
+ dataset=dataset,
+ evaluation_data_path="dataset.json",
+ project_name=project_name,
+ run_name="my-experiment",
+ metrics=custom_metrics # Use your custom metrics
+)
+```
+
+## What You'll See in Splunk AO
+
+After running the script, your Splunk AO project will contain:
+
+- **Dataset**: Your questions and ground truth answers
+- **Experiment Run**: Complete execution with:
+ - Individual traces for each evaluation
+ - Retriever spans
+ - LLM spans with prompts and responses
+ - Computed metrics (adherence, completeness, correctness, etc.)
+
+## Troubleshooting
+
+### "Missing environment variables"
+
+- Make sure you've created a `.env` file with your Splunk AO credentials
+- Verify all three required variables are set: `SPLUNK_AO_API_KEY`, `SPLUNK_AO_CONSOLE_URL`, `SPLUNK_AO_PROJECT`
+
+### "Question not found in evaluation data"
+
+- Ensure your JSON file has unique questions
+- Check that there are no extra whitespace or formatting differences
+
+### Import errors
+
+- Make sure you've activated your virtual environment
+- Run `pip install -r requirements.txt` to install all dependencies
+
+### "Dataset already exists"
+
+- The script will automatically use existing datasets with the same name
+- To create a fresh dataset, change `DATASET_NAME` in the script
+
+## Learn More
+
+- [Splunk AO Documentation](https://docs.galileo.ai/what-is-galileo)
+- [Splunk AO SDK Reference](https://docs.galileo.ai/sdk-api/overview)
+- [Creating Custom Metrics](https://docs.galileo.ai/concepts/metrics/custom-metrics/custom-metrics-ui-llm)
+- [Understanding Experiments](https://docs.galileo.ai/sdk-api/experiments/experiments)
diff --git a/examples/experiments/upload_experiment/dataset.json b/examples/experiments/upload_experiment/dataset.json
new file mode 100644
index 00000000..72d425eb
--- /dev/null
+++ b/examples/experiments/upload_experiment/dataset.json
@@ -0,0 +1,47 @@
+[
+ {
+ "question": "What's the protocol for solar panel deployment failure on the Mars orbiter?",
+ "context": [
+ "Mission Log 2847: Solar panel deployment issue on Mars Reconnaissance Orbiter resolved by cycling the deployment mechanism three times with 30-second intervals. Panel fully extended on third attempt. Battery levels stabilized after successful deployment.",
+ "Mission Log 2891: Similar deployment anomaly on Europa Clipper. Ground control sent emergency power sequence to release locking mechanism. Manual override successful, all systems nominal."
+ ],
+ "llm_answer": "For solar panel deployment failures on orbital spacecraft, the standard protocol involves cycling the deployment mechanism 2-3 times with 30-second intervals between attempts. If this fails, initiate emergency power sequence to manually override the locking mechanism. Monitor battery levels throughout and ensure spacecraft orientation maintains power to critical systems. After successful deployment, verify all panel segments are locked and power generation is within expected parameters.",
+ "ground_truth_answer": "Cycle the deployment mechanism up to three times with 30-second intervals. If unsuccessful, send emergency power sequence to override locking mechanism. Maintain spacecraft orientation for power stability."
+ },
+ {
+ "question": "How do we handle unexpected radiation spike warnings during ISS spacewalks?",
+ "context": [
+ "EVA Report 089: Radiation spike detected 45 minutes into EVA. Crew immediately moved to shadowed area behind station module. Spike subsided after 12 minutes, EVA resumed successfully.",
+ "EVA Report 094: Solar particle event warning triggered during routine maintenance. Crew returned to airlock within 8 minutes as per protocol. No radiation exposure exceeded safety limits."
+ ],
+ "llm_answer": "During ISS spacewalks, unexpected radiation spikes require immediate protective action. Crew should move to the shadowed side of the station, preferably behind large modules that provide shielding. If radiation levels remain elevated or continue rising, abort the EVA and return to the airlock immediately. All radiation warnings should be taken seriously as crew exposure time outside the Van Allen belts leaves them vulnerable to solar particle events. Mission Control will monitor the space weather data and provide clearance to resume activities.",
+ "ground_truth_answer": "Move immediately to shadowed area behind station modules. Monitor radiation levels and abort EVA if levels remain elevated. Wait for Mission Control clearance before resuming."
+ },
+ {
+ "question": "What's the recommended procedure for thruster fuel pressure anomaly on Artemis?",
+ "context": [
+ "Flight Report A-017: Thruster fuel pressure reading 5% below nominal on Artemis II capsule. Engineers verified sensor calibration and confirmed actual pressure was within spec. Sensor replaced during next maintenance window.",
+ "Flight Report A-023: Fuel pressure fluctuation detected during orbital maneuver. Switched to redundant fuel lines and pressure stabilized immediately. Primary line purged and tested, found debris in filter which was replaced."
+ ],
+ "llm_answer": "Thruster fuel pressure anomalies on Artemis spacecraft require systematic diagnosis. First, verify the sensor readings by cross-referencing with redundant pressure sensors if available. If pressure is genuinely low, switch to redundant fuel lines to maintain operational capability. Check fuel filters for debris or contamination that could restrict flow. If pressure continues to drop, prepare to use backup thrusters for critical maneuvers. Always notify Mission Control immediately and follow their guidance for mission-critical decisions.",
+ "ground_truth_answer": "Cross-reference with redundant sensors to verify reading. Switch to redundant fuel lines if pressure is confirmed low. Check and replace fuel filters if contaminated. Notify Mission Control immediately."
+ },
+ {
+ "question": "What coolant type is required for the James Webb Space Telescope sunshield?",
+ "context": [
+ "Technical Manual JWST-CS-001: The JWST sunshield uses passive cooling and does not require active coolant systems. The multi-layer sunshield reflects solar radiation while the cold side radiates heat to space.",
+ "Maintenance Log JWST-078: Cryocooler system for Mid-Infrared Instrument uses helium circulation at 6K. This is separate from sunshield thermal management."
+ ],
+ "llm_answer": "The James Webb Space Telescope sunshield actually uses passive cooling and does not require any active coolant fluid. The five-layer sunshield works by reflecting solar radiation while the cold side radiates infrared heat directly to space. The JWST instruments do use a helium cryocooler system to maintain temperatures around 6-7 Kelvin, but this is separate from the sunshield's passive thermal management system.",
+ "ground_truth_answer": "The JWST sunshield uses passive cooling with no active coolant. The multi-layer design reflects solar heat while radiating to space. Instruments use helium cryocooler separately."
+ },
+ {
+ "question": "Starship landing radar showing intermittent signal loss during descent",
+ "context": [
+ "Landing Report SS-045: Intermittent radar contact during final approach phase. Switched to backup optical landing system and landing completed successfully. Post-flight inspection revealed dust buildup on primary radar transceiver.",
+ "Landing Report SS-052: Radar altimeter dropout below 500 meters. Software automatically failed over to LIDAR system. Landing nominal. Root cause analysis showed electromagnetic interference from nearby ground equipment."
+ ],
+ "llm_answer": "Intermittent radar signal loss during Starship descent is addressed through redundant landing systems. The vehicle will automatically switch to backup optical or LIDAR systems if radar contact degrades. Common causes include dust or debris on the radar transceiver, electromagnetic interference, or terrain masking during certain descent angles. The flight computer is designed to handle sensor failures gracefully by fusing data from multiple sources. After landing, inspect radar hardware for contamination and check for sources of electromagnetic interference in the landing zone.",
+ "ground_truth_answer": "System will automatically fail over to backup optical/LIDAR systems. After landing, inspect radar transceiver for dust/debris and check for electromagnetic interference sources."
+ }
+ ]
\ No newline at end of file
diff --git a/examples/experiments/upload_experiment/requirements.txt b/examples/experiments/upload_experiment/requirements.txt
new file mode 100644
index 00000000..52583f09
--- /dev/null
+++ b/examples/experiments/upload_experiment/requirements.txt
@@ -0,0 +1,2 @@
+galileo>=1.16.0
+python-dotenv>=1.0.0
diff --git a/examples/experiments/upload_experiment/upload_existing_results.py b/examples/experiments/upload_experiment/upload_existing_results.py
new file mode 100644
index 00000000..b51f8175
--- /dev/null
+++ b/examples/experiments/upload_experiment/upload_existing_results.py
@@ -0,0 +1,321 @@
+"""
+Upload Existing Evaluation Results to Splunk AO
+
+Use this when you've already run evaluations offline and want to upload
+the results and traces to Splunk AO for analysis and visualization.
+
+This is particularly useful when:
+- You have historical evaluation data you want to centralize in Splunk AO
+- You ran evaluations with a different tool and want to visualize in Splunk AO
+- You need to replay past evaluations with full tracing for debugging
+
+How it works:
+1. Your JSON file contains: question, context (array of chunks), llm_answer, and ground_truth_answer
+2. A Splunk AO dataset is created with just: input (question) and output (ground_truth)
+3. During experiment execution, the full data is looked up to create complete traces
+4. Splunk AO metrics are computed and all traces are preserved for analysis with proper chunk attribution
+
+Data Flow:
+- Splunk AO Dataset: Clean inputs for evaluation (question + ground_truth)
+- Local JSON: Full execution data for trace reconstruction (with context chunks array)
+- Result: Complete evaluation with metrics and detailed traces
+"""
+
+import os
+import json
+from typing import Dict, Any, Optional
+from dotenv import load_dotenv
+
+# Load environment variables from .env file
+load_dotenv()
+
+# Splunk AO imports
+from splunk_ao.datasets import create_dataset, get_dataset
+from splunk_ao.experiments import run_experiment
+from splunk_ao.schema.metrics import SplunkAOMetrics
+from splunk_ao import splunk_ao_context
+
+
+def load_evaluation_data(json_path: str) -> Dict[str, Dict[str, Any]]:
+ """
+ Load your existing evaluation results from JSON.
+
+ Creates a lookup dictionary keyed by question for fast access during
+ trace reconstruction.
+
+ Expected JSON format:
+ [
+ {
+ "question": "Your question/input",
+ "context": ["chunk1", "chunk2", ...] or "single chunk", # Array of context chunks
+ "llm_answer": "The model's response",
+ "ground_truth_answer": "Expected correct answer"
+ },
+ ...
+ ]
+
+ Args:
+ json_path: Path to JSON file with your evaluation results
+
+ Returns:
+ Dict mapping questions to their full evaluation records
+ """
+ with open(json_path, "r") as f:
+ data = json.load(f)
+
+ # Create lookup dict keyed by question
+ lookup = {}
+ for record in data:
+ question = record["question"]
+ context = record.get("context", [])
+
+ # Normalize context to always be a list
+ if isinstance(context, str):
+ context = [context] if context else []
+ elif not isinstance(context, list):
+ context = [str(context)] if context else []
+
+ lookup[question] = {"context": context, "llm_answer": record.get("llm_answer", ""), "model": record.get("model", "gpt-4o")} # Allow model override
+
+ return lookup
+
+
+def create_or_get_dataset(dataset_name: str, evaluation_data: list) -> Any:
+ """
+ Find existing dataset by name or create a new one.
+
+ This checks if a dataset already exists to avoid duplicates.
+
+ Args:
+ dataset_name: Name of the dataset to find or create
+ evaluation_data: Data to upload if creating a new dataset
+
+ Returns:
+ Dataset object from Splunk AO
+ """
+ try:
+ dataset = get_dataset(name=dataset_name)
+ if dataset is not None:
+ print(f"✓ Found existing dataset: '{dataset_name}'")
+ return dataset
+ except Exception as e:
+ # Dataset doesn't exist or error occurred
+ if "not found" not in str(e).lower() and "does not exist" not in str(e).lower():
+ print(f"Warning: {e}")
+
+ # Create new dataset
+ print(f"✓ Creating new dataset: '{dataset_name}'")
+ dataset = create_dataset(name=dataset_name, content=evaluation_data)
+ print(f" Uploaded {len(evaluation_data)} rows")
+ return dataset
+
+
+def prepare_dataset_for_galileo(json_path: str, dataset_name: str) -> Any:
+ """
+ Upload your evaluation data to Splunk AO as a dataset.
+
+ Only the input (question) and expected output (ground_truth) are uploaded
+ to the dataset. The context and llm_answer are preserved locally and will
+ be used during trace reconstruction.
+
+ Args:
+ json_path: Path to JSON with your evaluation results
+ dataset_name: Name for the dataset in Splunk AO
+
+ Returns:
+ Dataset object from Splunk AO
+ """
+ # Load your evaluation results
+ with open(json_path, "r") as f:
+ raw_data = json.load(f)
+
+ # Transform to Splunk AO dataset format
+ # Only include input and expected output for clean evaluation
+ galileo_dataset = []
+ for row in raw_data:
+ galileo_row = {"input": row["question"], "output": row.get("ground_truth_answer", "")}
+ galileo_dataset.append(galileo_row)
+
+ return create_or_get_dataset(dataset_name, galileo_dataset)
+
+
+def create_replay_function(evaluation_lookup: Dict[str, Dict[str, Any]], system_prompt: Optional[str] = None):
+ """
+ Create a function that replays your evaluation with full tracing.
+
+ This returns a function that Splunk AO will call for each row in the dataset.
+ It reconstructs the full execution trace from your stored results.
+
+ Args:
+ evaluation_lookup: Dict mapping questions to their full evaluation data
+ system_prompt: Optional system prompt to include in LLM traces
+
+ Returns:
+ Function that takes input and returns the LLM answer with full tracing
+ """
+
+ # Default system prompt if none provided
+ if system_prompt is None:
+ system_prompt = "You are a helpful AI assistant. Use the provided context " "to answer the question accurately and concisely."
+
+ def replay_evaluation(input: str, **kwargs) -> str:
+ """
+ Replay a single evaluation with full trace reconstruction.
+
+ Args:
+ input: The question/input from the Splunk AO dataset
+
+ Returns:
+ The LLM answer from your evaluation results
+ """
+ question = input
+
+ # Look up the full evaluation record
+ if question not in evaluation_lookup:
+ raise KeyError(f"Question not found in evaluation data: {question[:100]}...")
+
+ eval_record = evaluation_lookup[question]
+ context_chunks = eval_record["context"]
+ llm_answer = eval_record["llm_answer"]
+ model = eval_record.get("model", "gpt-4o")
+
+ # Get Splunk AO logger for trace reconstruction
+ logger = splunk_ao_context.get_logger_instance()
+
+ # Log retriever span if context was used
+ if context_chunks:
+ logger.add_retriever_span(input=question, output=context_chunks, name="Context Retrieval")
+
+ # Format context chunks for the prompt
+ # Join multiple chunks with clear separators
+ if context_chunks:
+ context_text = "\n\n---\n\n".join([f"Chunk {i+1}:\n{chunk}" for i, chunk in enumerate(context_chunks)])
+ else:
+ context_text = ""
+
+ # Log LLM span with full prompt and response
+ if context_text:
+ full_prompt = f"{system_prompt}\n\nContext:\n{context_text}\n\nQuestion:\n{question}"
+ else:
+ full_prompt = f"{system_prompt}\n\nQuestion:\n{question}"
+
+ logger.add_llm_span(input=full_prompt, output=llm_answer, model=model, name="Answer Generation")
+
+ # Return the answer for evaluation against ground truth
+ return llm_answer
+
+ return replay_evaluation
+
+
+def upload_experiment(
+ dataset: Any, evaluation_data_path: str, project_name: str, run_name: str, system_prompt: Optional[str] = None, metrics: Optional[list] = None
+) -> Any:
+ """
+ Upload your evaluation results as a Splunk AO experiment.
+
+ This runs an experiment using your existing results, reconstructing
+ full traces for visualization and computing Splunk AO metrics.
+
+ Args:
+ dataset: Splunk AO dataset object
+ evaluation_data_path: Path to your JSON file with full evaluation data
+ project_name: Splunk AO project name
+ run_name: Name for this experiment run
+ system_prompt: Optional system prompt used in your evaluation
+ metrics: Optional list of metrics to compute (uses defaults if None)
+
+ Returns:
+ Experiment results
+ """
+ print(f"\nRunning experiment: {run_name}")
+
+ # Load evaluation data for trace reconstruction
+ evaluation_lookup = load_evaluation_data(evaluation_data_path)
+ print(f" Loaded {len(evaluation_lookup)} evaluation records")
+
+ # Create replay function with lookup data
+ replay_fn = create_replay_function(evaluation_lookup, system_prompt)
+
+ # Use default metrics if none provided
+ if metrics is None:
+ metrics = [
+ SplunkAOMetrics.ground_truth_adherence,
+ SplunkAOMetrics.context_adherence,
+ SplunkAOMetrics.chunk_attribution_utilization,
+ SplunkAOMetrics.completeness,
+ SplunkAOMetrics.correctness,
+ ]
+
+ # Run experiment with your data
+ results = run_experiment(
+ run_name,
+ project=project_name,
+ dataset=dataset,
+ function=replay_fn,
+ metrics=metrics,
+ )
+
+ print("✓ Experiment complete!")
+
+ return results
+
+
+def main():
+ """
+ Example: Upload existing evaluation results to Splunk AO
+
+ This script demonstrates how to take evaluation results you already have
+ and upload them to Splunk AO for analysis, visualization, and comparison.
+
+ Steps:
+ 1. Load your evaluation data from JSON
+ 2. Create/retrieve a Splunk AO dataset (input + expected output only)
+ 3. Run experiment - reconstructs full traces from your stored results
+ 4. View results in Splunk AO console with metrics and detailed traces
+ """
+
+ # Verify environment configuration
+ required_vars = ["SPLUNK_AO_API_KEY", "SPLUNK_AO_CONSOLE_URL", "SPLUNK_AO_PROJECT"]
+ missing_vars = [var for var in required_vars if not os.environ.get(var)]
+
+ if missing_vars:
+ print(f"⚠️ Missing environment variables: {', '.join(missing_vars)}")
+ print("Create a .env file with your Splunk AO credentials (see .env.example)")
+ return
+
+ print("=" * 70)
+ print("Upload Existing Evaluation Results to Splunk AO")
+ print("=" * 70)
+
+ # Configuration
+ EVALUATION_DATA_PATH = "dataset.json"
+ DATASET_NAME = "space-mission-support-qa-2"
+ RUN_NAME = "historical-evaluation-upload"
+ SYSTEM_PROMPT = (
+ "You are a space mission support AI assistant. "
+ "Use the provided mission logs and technical context to answer "
+ "questions accurately. If the answer is not in the context, "
+ "say you don't know rather than speculating."
+ )
+
+ # Step 1: Create or retrieve dataset
+ print(f"\n📊 Preparing dataset: {DATASET_NAME}")
+ dataset = prepare_dataset_for_galileo(EVALUATION_DATA_PATH, DATASET_NAME)
+
+ # Step 2: Upload experiment with full traces
+ print("\n🚀 Uploading experiment...")
+ results = upload_experiment(
+ dataset=dataset,
+ evaluation_data_path=EVALUATION_DATA_PATH,
+ project_name=os.environ.get("SPLUNK_AO_PROJECT"),
+ run_name=RUN_NAME,
+ system_prompt=SYSTEM_PROMPT,
+ )
+
+ if results:
+ print("\n✅ Success! View your results in Splunk AO")
+ print(f"URL: {results['link']}")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/logging-samples/distributed-tracing-otel-python-java/.env.example b/examples/logging-samples/distributed-tracing-otel-python-java/.env.example
new file mode 100644
index 00000000..9f58ca22
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing-otel-python-java/.env.example
@@ -0,0 +1,17 @@
+# --- Required ---
+OPENAI_API_KEY=sk-...
+GALILEO_API_KEY=...
+GALILEO_CONSOLE_URL=https://app.galileo.ai
+
+# --- Galileo project routing (used by the collector) ---
+GALILEO_PROJECT=distributed-tracing-demo
+GALILEO_LOG_STREAM=main
+
+# --- Galileo API URL (derived from console URL; adjust if different) ---
+GALILEO_API_URL=https://api.galileo.ai
+
+# --- OTel Collector endpoint ---
+# docker-compose overrides this to http://otel-collector:4318 (the bundled
+# demo collector). For your real deployment, set it to the OTLP/HTTP endpoint
+# of the collector you already run, e.g. https://otel-collector.internal:4318.
+OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
diff --git a/examples/logging-samples/distributed-tracing-otel-python-java/.gitignore b/examples/logging-samples/distributed-tracing-otel-python-java/.gitignore
new file mode 100644
index 00000000..0a7f0d3d
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing-otel-python-java/.gitignore
@@ -0,0 +1,17 @@
+# Secrets
+.env
+
+# Python
+python-service/__pycache__/
+python-service/*.py[cod]
+python-service/.venv/
+
+# Java / Maven
+java-service/target/
+java-service/*.class
+
+# ChromaDB local data
+chroma-data/
+
+# OS
+.DS_Store
diff --git a/examples/logging-samples/distributed-tracing-otel-python-java/README.md b/examples/logging-samples/distributed-tracing-otel-python-java/README.md
new file mode 100644
index 00000000..c9143a95
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing-otel-python-java/README.md
@@ -0,0 +1,164 @@
+# Distributed Tracing: Java + Python with Splunk AO via OTEL
+
+A runnable example showing how to trace a request across a **Java Spring Boot gateway** and a **Python FastAPI + LangGraph RAG service** — with a single trace ID stitched together end-to-end in [Splunk AO](https://galileo.ai).
+
+```
+User ──POST /ask──▶ Java Gateway ──POST /process──▶ Python RAG Service
+ │ Spring AI (classify) │ LangGraph (route → retrieve → generate)
+ │ OTel Java Agent │ LangChainInstrumentor + RetrieverSpan
+ └──────────────────┬─────────────┘
+ │ OTLP HTTP
+ ▼
+ OpenTelemetry Collector
+ │ OTLP HTTP (with Splunk AO auth)
+ ▼
+ Splunk AO
+```
+
+## What this demonstrates
+
+- **Cross-language trace propagation** — the OTel Java agent injects a W3C `traceparent` header on every outbound HTTP call; the Python service continues the same trace automatically
+- **Auto-instrumentation + targeted manual spans** — `LangChainInstrumentor` handles LangGraph nodes automatically; a Splunk AO `RetrieverSpan` surfaces retrieved source documents in the trace UI; the Java service adds `gen_ai.*` attributes for proper agent hierarchy rendering
+- **Collector-agnostic** — both services export plain OTLP/HTTP to `OTEL_EXPORTER_OTLP_ENDPOINT`. Point them at the bundled demo collector, or at whatever OTel Collector you already run.
+- **Financial services domain** — ChromaDB is pre-seeded with realistic financial policy documents (wire transfers, KYC/AML, mortgage guidelines, etc.)
+
+## Expected trace in Splunk AO
+
+```
+invoke_agent financial-assistant ← Java: outer agent span (manual)
+ chat classify_question ← Java: LLM classification (manual span)
+ POST /process ← Java agent: auto-instrumented HTTP call
+ rag_pipeline ← Python: WorkflowSpan (Splunk AO)
+ LangGraph.invoke ← Python: auto-instrumented by LangChainInstrumentor
+ route ← Python: LangGraph node (auto)
+ retrieve ← Python: LangGraph node (auto)
+ chromadb_search ← Python: RetrieverSpan with source docs (Splunk AO)
+ generate ← Python: LangGraph node (auto)
+ openai.chat ← Python: LLM span (auto, OpenAIInstrumentor)
+```
+
+## Prerequisites
+
+| Requirement | Version |
+|---|---|
+| Docker + Docker Compose | 24+ |
+| OpenAI API key | — |
+| Splunk AO account + API key | [console.galileo.ai](https://console.galileo.ai) |
+
+## Quick start
+
+**1. Clone and configure**
+
+```bash
+git clone https://github.com/rungalileo/sdk-examples.git
+cd sdk-examples/python/logging-samples/distributed-tracing-otel-python-java
+cp .env.example .env
+```
+
+Edit `.env` and fill in your keys:
+
+```ini
+OPENAI_API_KEY=sk-...
+SPLUNK_AO_API_KEY=...
+SPLUNK_AO_PROJECT=distributed-tracing-demo
+SPLUNK_AO_LOG_STREAM=main
+SPLUNK_AO_API_URL=https://api.galileo.ai
+```
+
+**2. Start all services**
+
+```bash
+docker compose up --build
+```
+
+On first run this builds the Java and Python images (~2–3 min) and seeds ChromaDB. Once you see `Started GatewayApplication`, everything is ready.
+
+**3. Send a question**
+
+```bash
+curl -s -X POST http://localhost:8089/ask \
+ -H "Content-Type: application/json" \
+ -d '{"question": "What are the wire transfer limits?"}' | jq
+```
+
+Expected response:
+
+```json
+{
+ "answer": "Domestic wire transfers are limited to $50,000 per business day...",
+ "category": "FINANCIAL",
+ "sources": ["wire-transfer-policy"]
+}
+```
+
+**4. View traces in Splunk AO**
+
+Open your Splunk AO project and navigate to the log stream you configured in `.env`. You should see a trace with the full span hierarchy shown above.
+
+## Service ports
+
+| Service | Host port | Purpose |
+|---|---|---|
+| Java gateway | 8089 | `POST /ask` — entry point |
+| Python RAG service | 8099 | `POST /process` — internal |
+| ChromaDB | 8299 | Vector store |
+
+## Architecture
+
+### Java gateway (`java-service/`)
+
+- **Spring Boot 3.4.1 + Spring AI 1.0.0** — handles routing and LLM classification
+- **OTel Java agent** (bundled in Docker image) — auto-instruments all HTTP calls and injects `traceparent` headers
+- **Manual spans** — two spans with `gen_ai.*` attributes tell Splunk AO to render this as an agent with an LLM sub-call; Spring AI doesn't yet emit these automatically
+
+### Python RAG service (`python-service/`)
+
+- **FastAPI + LangGraph** — three-node graph: `route → retrieve → generate`
+- **`LangChainInstrumentor` + `OpenAIInstrumentor`** — auto-create spans for each LangGraph node and every OpenAI call
+- **`RetrieverSpan`** (Splunk AO) — wraps the ChromaDB query so retrieved documents appear as source context in Splunk AO
+- **`WorkflowSpan`** (Splunk AO) — top-level span for the `/process` endpoint
+
+### How spans reach Splunk AO
+
+Both services export OTLP/HTTP to whatever endpoint `OTEL_EXPORTER_OTLP_ENDPOINT` points at. That endpoint is always an **OpenTelemetry Collector** — the collector batches, retries on failure, and forwards to Splunk AO with the right auth headers. Splunk AO credentials live in the collector config, not in the application code.
+
+#### Using the bundled demo collector
+
+For running this repo end-to-end on a laptop, `docker compose up` starts a minimal collector alongside the two services. Its config is in [`otel-collector/config.yaml`](./otel-collector/config.yaml). Services automatically point at it:
+
+```
+OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
+```
+
+This is a demo convenience — not something you deploy.
+
+#### Using your own existing collector
+
+In any real environment you almost certainly already run an OTel Collector. To point the services at it instead:
+
+1. Add a Splunk AO exporter to your existing collector config (see [`otel-collector/config.yaml`](./otel-collector/config.yaml) for the `otlphttp/galileo` block to copy).
+2. Set `OTEL_EXPORTER_OTLP_ENDPOINT` in `.env` (or your deployment config) to your collector's OTLP/HTTP endpoint, e.g. `https://otel-collector.internal.example.com:4318`.
+3. Remove the `otel-collector` service from `docker-compose.yml` (or just stop pointing at it).
+
+No application code changes. The instrumentation stays identical.
+
+## Troubleshooting
+
+**Java service fails to start**
+- Check that `OPENAI_API_KEY` is set in `.env`
+- Maven downloads dependencies on first build; allow 2–3 min
+
+**No traces in Splunk AO**
+- Verify `SPLUNK_AO_API_KEY` and `SPLUNK_AO_API_URL` in `.env`
+- Check `SPLUNK_AO_PROJECT` and `SPLUNK_AO_LOG_STREAM` match what you're looking at in the UI
+
+**ChromaDB connection refused**
+- Python service waits up to 60 s for ChromaDB; check `docker compose logs python-service`
+
+**Empty answers**
+- Confirm `OPENAI_API_KEY` is valid and has quota
+- Try a question in the FINANCIAL category (e.g., "What is the minimum credit score for a mortgage?")
+
+## Further reading
+
+[Distributed Tracing with OpenTelemetry — Splunk AO Docs](https://docs.galileo.ai/sdk-api/logging/distributed-tracing-otel)
diff --git a/examples/logging-samples/distributed-tracing-otel-python-java/docker-compose.yml b/examples/logging-samples/distributed-tracing-otel-python-java/docker-compose.yml
new file mode 100644
index 00000000..7168a427
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing-otel-python-java/docker-compose.yml
@@ -0,0 +1,60 @@
+services:
+
+ chromadb:
+ image: chromadb/chroma:0.6.3
+ ports:
+ - "8299:8000"
+ volumes:
+ - chroma-data:/chroma/chroma
+ environment:
+ - ANONYMIZED_TELEMETRY=false
+
+ otel-collector:
+ image: otel/opentelemetry-collector-contrib:0.120.0
+ command: ["--config", "/etc/otel-collector/config.yaml"]
+ volumes:
+ - ./otel-collector/config.yaml:/etc/otel-collector/config.yaml:ro
+ environment:
+ - SPLUNK_AO_API_URL=${SPLUNK_AO_API_URL}
+ - SPLUNK_AO_API_KEY=${SPLUNK_AO_API_KEY}
+ - SPLUNK_AO_PROJECT=${SPLUNK_AO_PROJECT}
+ - SPLUNK_AO_LOG_STREAM=${SPLUNK_AO_LOG_STREAM}
+ ports:
+ - "4317:4317" # OTLP gRPC
+ - "4318:4318" # OTLP HTTP
+
+ python-service:
+ build: ./python-service
+ ports:
+ - "8099:8099"
+ environment:
+ - OPENAI_API_KEY=${OPENAI_API_KEY}
+ - OTEL_SERVICE_NAME=python-rag-service
+ - OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
+ - CHROMADB_HOST=chromadb
+ - CHROMADB_PORT=8000
+ # Silences a harmless posthog telemetry error in chromadb-client.
+ - ANONYMIZED_TELEMETRY=False
+ depends_on:
+ - chromadb
+ - otel-collector
+
+ java-service:
+ build: ./java-service
+ ports:
+ - "8089:8089"
+ environment:
+ - OPENAI_API_KEY=${OPENAI_API_KEY}
+ - OTEL_SERVICE_NAME=java-gateway
+ - OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318
+ - OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
+ - OTEL_TRACES_EXPORTER=otlp
+ - OTEL_METRICS_EXPORTER=none
+ - OTEL_LOGS_EXPORTER=none
+ - PYTHON_SERVICE_URL=http://python-service:8099
+ depends_on:
+ - python-service
+ - otel-collector
+
+volumes:
+ chroma-data:
diff --git a/examples/logging-samples/distributed-tracing-otel-python-java/java-service/Dockerfile b/examples/logging-samples/distributed-tracing-otel-python-java/java-service/Dockerfile
new file mode 100644
index 00000000..479bd6ab
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing-otel-python-java/java-service/Dockerfile
@@ -0,0 +1,20 @@
+FROM eclipse-temurin:21-jdk AS build
+WORKDIR /app
+
+RUN apt-get update && apt-get install -y curl && \
+ curl -fsSL https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.tar.gz \
+ | tar xz -C /opt && \
+ ln -s /opt/apache-maven-3.9.9/bin/mvn /usr/local/bin/mvn
+
+COPY pom.xml .
+RUN mvn dependency:resolve -q || true
+COPY src ./src
+RUN mvn clean package -DskipTests -q
+
+FROM eclipse-temurin:21-jre
+WORKDIR /app
+COPY --from=build /app/target/*.jar app.jar
+ADD https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v2.12.0/opentelemetry-javaagent.jar /app/opentelemetry-javaagent.jar
+
+EXPOSE 8089
+ENTRYPOINT ["java", "-javaagent:/app/opentelemetry-javaagent.jar", "-jar", "app.jar"]
diff --git a/examples/logging-samples/distributed-tracing-otel-python-java/java-service/pom.xml b/examples/logging-samples/distributed-tracing-otel-python-java/java-service/pom.xml
new file mode 100644
index 00000000..0f0ae2bc
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing-otel-python-java/java-service/pom.xml
@@ -0,0 +1,64 @@
+
+
+ 4.0.0
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.4.1
+
+
+ com.example
+ gateway-service
+ 0.0.1-SNAPSHOT
+ Gateway Service
+
+
+ 21
+ 1.0.0
+
+
+
+
+
+ org.springframework.ai
+ spring-ai-bom
+ ${spring-ai.version}
+ pom
+ import
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+ org.springframework.ai
+ spring-ai-starter-model-openai
+ ${spring-ai.version}
+
+
+ io.opentelemetry
+ opentelemetry-api
+ 1.46.0
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
diff --git a/examples/logging-samples/distributed-tracing-otel-python-java/java-service/src/main/java/com/example/gateway/AskController.java b/examples/logging-samples/distributed-tracing-otel-python-java/java-service/src/main/java/com/example/gateway/AskController.java
new file mode 100644
index 00000000..35c22f8b
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing-otel-python-java/java-service/src/main/java/com/example/gateway/AskController.java
@@ -0,0 +1,123 @@
+package com.example.gateway;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.ai.chat.client.ChatClient;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
+
+import io.opentelemetry.api.GlobalOpenTelemetry;
+import io.opentelemetry.api.common.AttributeKey;
+import io.opentelemetry.api.trace.Span;
+import io.opentelemetry.api.trace.Tracer;
+import io.opentelemetry.context.Scope;
+
+@RestController
+public class AskController {
+
+ private static final Logger log = LoggerFactory.getLogger(AskController.class);
+
+ private final ChatClient chatClient;
+ private final RestTemplate restTemplate;
+ private final String pythonServiceUrl;
+
+ public AskController(
+ ChatClient.Builder chatClientBuilder,
+ RestTemplate restTemplate,
+ @Value("${python-service.url}") String pythonServiceUrl) {
+ this.chatClient = chatClientBuilder
+ .defaultSystem("You are a routing classifier for a financial services AI system. "
+ + "Classify questions into exactly one category: FINANCIAL, TECHNICAL, or GENERAL. "
+ + "Reply with ONLY the category name, nothing else.")
+ .build();
+ this.restTemplate = restTemplate;
+ this.pythonServiceUrl = pythonServiceUrl;
+ }
+
+ @PostMapping("/ask")
+ @SuppressWarnings("unchecked")
+ public ResponseEntity> ask(@RequestBody Map request) {
+ String question = request.get("question");
+ log.info("Received question: {}", question);
+
+ Tracer tracer = GlobalOpenTelemetry.getTracer("java-gateway");
+
+ // Wrap the full agent flow in a span with Splunk AO-recognized gen_ai attributes.
+ // The OTel Java agent auto-instruments Spring Boot/HTTP, but these attributes
+ // are needed for Splunk AO to render this as an "agent" span in the trace UI.
+ Span agentSpan = tracer.spanBuilder("invoke_agent financial-assistant")
+ .setAttribute("gen_ai.system", "spring-ai")
+ .setAttribute("gen_ai.operation.name", "invoke_agent")
+ .setAttribute("gen_ai.agent.name", "financial-assistant")
+ .setAttribute(AttributeKey.stringKey("gen_ai.input.messages"),
+ "[{\"role\": \"user\", \"content\": " + jsonEscape(question) + "}]")
+ .startSpan();
+
+ try (Scope ignored = agentSpan.makeCurrent()) {
+ // Step 1: Classify the question using Spring AI + OpenAI
+ String category = classifyQuestion(tracer, question);
+ log.info("Classified as: {}", category);
+
+ // Step 2: Call Python RAG service — the OTel Java agent automatically
+ // injects the W3C traceparent header, propagating the trace context.
+ Map pythonRequest = new HashMap<>();
+ pythonRequest.put("question", question);
+ pythonRequest.put("category", category);
+
+ Map ragResponse = restTemplate.postForObject(
+ pythonServiceUrl + "/process",
+ pythonRequest,
+ Map.class);
+
+ Map response = new HashMap<>();
+ response.put("answer", ragResponse.get("answer"));
+ response.put("category", category);
+ response.put("sources", ragResponse.get("sources"));
+
+ agentSpan.setAttribute(AttributeKey.stringKey("gen_ai.output.messages"),
+ "[{\"role\": \"assistant\", \"content\": " + jsonEscape((String) ragResponse.get("answer")) + "}]");
+
+ return ResponseEntity.ok(response);
+ } finally {
+ agentSpan.end();
+ }
+ }
+
+ private String classifyQuestion(Tracer tracer, String question) {
+ // Manual LLM span — Spring AI doesn't yet auto-emit gen_ai.operation.name=chat,
+ // so we create it ourselves for proper Splunk AO trace rendering.
+ Span llmSpan = tracer.spanBuilder("chat classify_question")
+ .setAttribute("gen_ai.system", "spring-ai")
+ .setAttribute("gen_ai.operation.name", "chat")
+ .setAttribute("gen_ai.request.model", "gpt-4o-mini")
+ .setAttribute(AttributeKey.stringKey("gen_ai.input.messages"),
+ "[{\"role\": \"user\", \"content\": " + jsonEscape(question) + "}]")
+ .startSpan();
+
+ try (Scope ignored = llmSpan.makeCurrent()) {
+ String category = chatClient.prompt()
+ .user(question)
+ .call()
+ .content()
+ .trim();
+
+ llmSpan.setAttribute(AttributeKey.stringKey("gen_ai.output.messages"),
+ "[{\"role\": \"assistant\", \"content\": " + jsonEscape(category) + "}]");
+ return category;
+ } finally {
+ llmSpan.end();
+ }
+ }
+
+ private static String jsonEscape(String value) {
+ if (value == null) return "\"\"";
+ return "\"" + value.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n") + "\"";
+ }
+}
diff --git a/examples/logging-samples/distributed-tracing-otel-python-java/java-service/src/main/java/com/example/gateway/GatewayApplication.java b/examples/logging-samples/distributed-tracing-otel-python-java/java-service/src/main/java/com/example/gateway/GatewayApplication.java
new file mode 100644
index 00000000..eb33dccd
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing-otel-python-java/java-service/src/main/java/com/example/gateway/GatewayApplication.java
@@ -0,0 +1,19 @@
+package com.example.gateway;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.client.RestTemplate;
+
+@SpringBootApplication
+public class GatewayApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(GatewayApplication.class, args);
+ }
+
+ @Bean
+ public RestTemplate restTemplate() {
+ return new RestTemplate();
+ }
+}
diff --git a/examples/logging-samples/distributed-tracing-otel-python-java/java-service/src/main/resources/application.yml b/examples/logging-samples/distributed-tracing-otel-python-java/java-service/src/main/resources/application.yml
new file mode 100644
index 00000000..c7642402
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing-otel-python-java/java-service/src/main/resources/application.yml
@@ -0,0 +1,16 @@
+server:
+ port: 8089
+
+spring:
+ application:
+ name: java-gateway
+ ai:
+ openai:
+ api-key: ${OPENAI_API_KEY}
+ chat:
+ options:
+ model: gpt-4o-mini
+ temperature: 0.0
+
+python-service:
+ url: ${PYTHON_SERVICE_URL:http://localhost:8099}
diff --git a/examples/logging-samples/distributed-tracing-otel-python-java/otel-collector/config.yaml b/examples/logging-samples/distributed-tracing-otel-python-java/otel-collector/config.yaml
new file mode 100644
index 00000000..49d52d08
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing-otel-python-java/otel-collector/config.yaml
@@ -0,0 +1,57 @@
+# OpenTelemetry Collector config used by the docker-compose demo.
+#
+# In production, point OTEL_EXPORTER_OTLP_ENDPOINT at your own collector
+# instead — copy the `otlphttp/galileo` exporter block below into its config
+# and add it to your traces pipeline.
+#
+# Pipeline: receive OTLP from both services, batch, forward to Splunk AO.
+# Splunk AO credentials live here, not in the application services.
+
+receivers:
+ otlp:
+ protocols:
+ http:
+ endpoint: 0.0.0.0:4318
+ grpc:
+ endpoint: 0.0.0.0:4317
+
+processors:
+ # Keep batches small and frequent so the Splunk AO UI fills in quickly during
+ # demos. Tune up for real workloads.
+ batch:
+ timeout: 1s
+ send_batch_size: 512
+
+exporters:
+ otlphttp/galileo:
+ endpoint: ${env:SPLUNK_AO_API_URL}/otel
+ headers:
+ Galileo-API-Key: ${env:SPLUNK_AO_API_KEY}
+ project: ${env:SPLUNK_AO_PROJECT}
+ logstream: ${env:SPLUNK_AO_LOG_STREAM}
+ # Retry on transient failures so a blip to Splunk AO doesn't drop half a trace.
+ retry_on_failure:
+ enabled: true
+ initial_interval: 1s
+ max_interval: 10s
+ max_elapsed_time: 60s
+ sending_queue:
+ enabled: true
+ num_consumers: 4
+ queue_size: 1000
+
+ # Prints every received span to the collector's stdout. Useful for demos and
+ # debugging — remove this exporter (and its reference in the pipeline below)
+ # for production.
+ debug:
+ verbosity: detailed
+
+service:
+ pipelines:
+ traces:
+ receivers: [otlp]
+ processors: [batch]
+ exporters: [otlphttp/galileo, debug]
+ telemetry:
+ logs:
+ level: info
diff --git a/examples/logging-samples/distributed-tracing-otel-python-java/python-service/Dockerfile b/examples/logging-samples/distributed-tracing-otel-python-java/python-service/Dockerfile
new file mode 100644
index 00000000..bb37a51b
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing-otel-python-java/python-service/Dockerfile
@@ -0,0 +1,12 @@
+FROM python:3.12-slim
+
+WORKDIR /app
+
+COPY requirements.txt .
+RUN pip install --no-cache-dir -r requirements.txt
+
+COPY . .
+RUN chmod +x entrypoint.sh
+
+EXPOSE 8099
+ENTRYPOINT ["./entrypoint.sh"]
diff --git a/examples/logging-samples/distributed-tracing-otel-python-java/python-service/app.py b/examples/logging-samples/distributed-tracing-otel-python-java/python-service/app.py
new file mode 100644
index 00000000..bad8a4ba
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing-otel-python-java/python-service/app.py
@@ -0,0 +1,223 @@
+import logging
+import os
+from typing import TypedDict
+
+import chromadb
+import chromadb.utils.embedding_functions as ef
+import openai
+from fastapi import FastAPI
+from splunk_ao.otel import start_galileo_span
+from splunk_ao_core.schemas.logging.span import RetrieverSpan
+from splunk_ao_core.schemas.shared.document import Document
+from langgraph.graph import END, START, StateGraph
+from openinference.instrumentation.langchain import LangChainInstrumentor
+from openinference.instrumentation.openai import OpenAIInstrumentor
+from opentelemetry import trace
+from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
+from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
+from opentelemetry.sdk.resources import Resource
+from opentelemetry.sdk.trace import TracerProvider
+from opentelemetry.sdk.trace.export import BatchSpanProcessor
+from pydantic import BaseModel
+
+logging.basicConfig(level=logging.INFO)
+logger = logging.getLogger(__name__)
+
+# ---------------------------------------------------------------------------
+# OTel setup — export to the local OpenTelemetry Collector, which forwards
+# to Splunk AO. The collector owns Splunk AO credentials; this service does not.
+#
+# Defaults to http://localhost:4318 for running outside Docker. In
+# docker-compose, OTEL_EXPORTER_OTLP_ENDPOINT is overridden to the collector
+# service address.
+# ---------------------------------------------------------------------------
+_otlp_endpoint = os.environ.get("OTEL_EXPORTER_OTLP_ENDPOINT", "http://localhost:4318")
+_otlp_exporter = OTLPSpanExporter(endpoint=f"{_otlp_endpoint.rstrip('/')}/v1/traces")
+
+provider = TracerProvider(resource=Resource.create())
+# BatchSpanProcessor batches spans and flushes them on a repeating timer.
+# The default interval is 5000ms, which means Python spans can appear in
+# Splunk AO up to 5 seconds after Java spans for the same request. Reducing
+# this to 1000ms keeps the trace UI consistent without adding per-request latency.
+provider.add_span_processor(BatchSpanProcessor(_otlp_exporter, schedule_delay_millis=1000))
+trace.set_tracer_provider(provider)
+
+# ---------------------------------------------------------------------------
+# Instrumentation strategy
+# ---------------------------------------------------------------------------
+# We rely on auto-instrumentation wherever possible and only add manual
+# Splunk AO spans when auto-instrumentation can't express what we need:
+#
+# Auto-instrumented (no code changes required):
+# - FastAPI server spans -> opentelemetry-instrumentation-fastapi
+# - LangGraph workflow + node spans -> openinference-instrumentation-langchain
+# (LangChain instrumentor covers LangGraph; there is no separate
+# LangGraph instrumentor package on PyPI.)
+# - OpenAI chat / embeddings spans -> openinference-instrumentation-openai
+#
+# Manual Splunk AO spans (see retrieve_documents below):
+# - RetrieverSpan around ChromaDB queries — needed for two reasons:
+# 1. ChromaDB has no OTel/OpenInference instrumentation package, so
+# without a manual span the retrieval step would be invisible.
+# 2. RetrieverSpan is a Splunk AO-specific span type that renders
+# retrieved documents as source context in the trace UI. A
+# generic OTel span cannot produce this UI treatment.
+# ---------------------------------------------------------------------------
+LangChainInstrumentor().instrument(tracer_provider=provider)
+OpenAIInstrumentor().instrument(tracer_provider=provider)
+
+# ---------------------------------------------------------------------------
+# Clients
+# ---------------------------------------------------------------------------
+oai = openai.OpenAI()
+chroma = chromadb.HttpClient(
+ host=os.getenv("CHROMADB_HOST", "localhost"),
+ port=int(os.getenv("CHROMADB_PORT", "8000")),
+)
+embedding_fn = ef.OpenAIEmbeddingFunction(
+ api_key=os.getenv("OPENAI_API_KEY"),
+ model_name="text-embedding-3-small",
+)
+
+CHROMA_COLLECTION = "financial_docs"
+
+
+# ---------------------------------------------------------------------------
+# LangGraph state & nodes
+# ---------------------------------------------------------------------------
+class GraphState(TypedDict):
+ question: str
+ category: str
+ documents: list[str]
+ sources: list[str]
+ answer: str
+
+
+def route_question(state: GraphState) -> GraphState:
+ """Entry node — logs the category and passes state through."""
+ logger.info("Routing: category=%s", state["category"])
+ return {**state, "documents": [], "sources": []}
+
+
+def retrieve_documents(state: GraphState) -> GraphState:
+ """Query ChromaDB for relevant documents.
+
+ This is the one place we create a manual Splunk AO span. See the
+ "Instrumentation strategy" comment above for the rationale. The
+ RetrieverSpan's `output` is populated with a list of Documents so the
+ Splunk AO UI can render each retrieved chunk as inline source context.
+ """
+ query = state["question"]
+ retriever_span = RetrieverSpan(name="chromadb_search", input=query)
+
+ with start_galileo_span(retriever_span) as span:
+ try:
+ collection = chroma.get_collection(CHROMA_COLLECTION, embedding_function=embedding_fn)
+ results = collection.query(query_texts=[query], n_results=3)
+ docs = results["documents"][0] if results["documents"] else []
+ ids = results["ids"][0] if results["ids"] else []
+ except Exception:
+ logger.exception("ChromaDB query failed, continuing with empty context")
+ docs, ids = [], []
+
+ retriever_span.output = [Document(content=d, metadata={"id": i}) for d, i in zip(docs, ids)]
+ span.set_attribute("retriever.result_count", len(docs))
+ logger.info("Retrieved %d documents", len(docs))
+
+ return {**state, "documents": docs, "sources": ids}
+
+
+def generate_answer(state: GraphState) -> GraphState:
+ """Call OpenAI with retrieved context to produce the final answer.
+
+ OpenAIInstrumentor automatically creates an LLM span for this call,
+ capturing model, token usage, and input/output content.
+ """
+ question = state["question"]
+ docs = state.get("documents", [])
+
+ context_block = "\n\n---\n\n".join(docs) if docs else "No additional context available."
+ messages = [
+ {
+ "role": "system",
+ "content": (
+ "You are a knowledgeable financial services assistant. "
+ "Answer the user's question using ONLY the provided context. "
+ "If the context doesn't contain enough information, say so."
+ ),
+ },
+ {
+ "role": "user",
+ "content": f"Context:\n{context_block}\n\nQuestion: {question}",
+ },
+ ]
+
+ response = oai.chat.completions.create(
+ model="gpt-4o-mini",
+ messages=messages,
+ temperature=0.2,
+ )
+ # message.content is Optional[str] — guard against content filters or
+ # tool-call responses where the model returns no text.
+ answer = response.choices[0].message.content or ""
+ logger.info("Generated answer (%d chars)", len(answer))
+ return {**state, "answer": answer}
+
+
+# ---------------------------------------------------------------------------
+# Build the LangGraph workflow
+# ---------------------------------------------------------------------------
+graph_builder = StateGraph(GraphState)
+graph_builder.add_node("route", route_question)
+graph_builder.add_node("retrieve", retrieve_documents)
+graph_builder.add_node("generate", generate_answer)
+
+graph_builder.add_edge(START, "route")
+graph_builder.add_edge("route", "retrieve")
+graph_builder.add_edge("retrieve", "generate")
+graph_builder.add_edge("generate", END)
+
+workflow = graph_builder.compile()
+
+# ---------------------------------------------------------------------------
+# FastAPI app
+# ---------------------------------------------------------------------------
+app = FastAPI(title="Financial RAG Service")
+
+# FastAPIInstrumentor extracts the W3C traceparent from incoming HTTP requests
+# and creates a server span that becomes the parent for all spans created
+# during the request — this is what stitches Python's trace onto Java's.
+# Call WITHOUT the tracer_provider kwarg so it uses the global provider set
+# above; passing tracer_provider explicitly can silently skip middleware
+# registration in recent opentelemetry-instrumentation-fastapi versions.
+FastAPIInstrumentor.instrument_app(app)
+
+
+class ProcessRequest(BaseModel):
+ question: str
+ category: str = "GENERAL"
+
+
+@app.post("/process")
+def process(req: ProcessRequest):
+ """Main RAG endpoint — called by the Java gateway.
+
+ No manual workflow span is needed here: LangChainInstrumentor emits a
+ `LangGraph` span covering the full `workflow.invoke(...)` call, which
+ serves as the workflow container in the Splunk AO trace UI.
+ """
+ result = workflow.invoke(
+ {
+ "question": req.question,
+ "category": req.category,
+ "documents": [],
+ "sources": [],
+ "answer": "",
+ }
+ )
+ return {"answer": result["answer"], "sources": result.get("sources", [])}
+
+
+@app.get("/health")
+def health():
+ return {"status": "ok"}
diff --git a/examples/logging-samples/distributed-tracing-otel-python-java/python-service/entrypoint.sh b/examples/logging-samples/distributed-tracing-otel-python-java/python-service/entrypoint.sh
new file mode 100644
index 00000000..cdf38c21
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing-otel-python-java/python-service/entrypoint.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+set -e
+
+echo "Seeding ChromaDB..."
+python seed_chroma.py
+
+echo "Starting RAG service..."
+exec uvicorn app:app --host 0.0.0.0 --port 8099
diff --git a/examples/logging-samples/distributed-tracing-otel-python-java/python-service/requirements.txt b/examples/logging-samples/distributed-tracing-otel-python-java/python-service/requirements.txt
new file mode 100644
index 00000000..5101d7bd
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing-otel-python-java/python-service/requirements.txt
@@ -0,0 +1,12 @@
+fastapi==0.115.6
+uvicorn==0.34.0
+openai==1.82.0
+langgraph==0.4.1
+chromadb-client==0.6.3
+galileo[otel]
+opentelemetry-api
+opentelemetry-sdk
+opentelemetry-exporter-otlp-proto-http
+opentelemetry-instrumentation-fastapi
+openinference-instrumentation-langchain
+openinference-instrumentation-openai
diff --git a/examples/logging-samples/distributed-tracing-otel-python-java/python-service/seed_chroma.py b/examples/logging-samples/distributed-tracing-otel-python-java/python-service/seed_chroma.py
new file mode 100644
index 00000000..c5813290
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing-otel-python-java/python-service/seed_chroma.py
@@ -0,0 +1,116 @@
+"""Seed ChromaDB with sample financial services documents."""
+
+import os
+import sys
+import time
+
+import chromadb
+import chromadb.utils.embedding_functions as ef
+
+COLLECTION = "financial_docs"
+
+DOCUMENTS = [
+ {
+ "id": "wire-transfer-policy",
+ "text": (
+ "Wire Transfer Policy: Account holders may initiate domestic wire transfers "
+ "up to $50,000 per business day through online banking or by visiting a branch. "
+ "International wires require additional verification and are limited to $25,000 "
+ "per transaction. All wire transfers are subject to fraud screening and may be "
+ "held for up to 24 hours for compliance review. Fees: $25 domestic, $45 international."
+ ),
+ },
+ {
+ "id": "fraud-detection-alerts",
+ "text": (
+ "Fraud Detection & Alerts: Our real-time fraud monitoring system analyzes "
+ "transactions using machine learning models that evaluate spending patterns, "
+ "geographic location, merchant category, and transaction velocity. Alerts are "
+ "triggered when anomaly scores exceed the configured threshold. Customers receive "
+ "SMS and push notifications within 30 seconds of a flagged transaction. False "
+ "positive rates are maintained below 2% through continuous model retraining."
+ ),
+ },
+ {
+ "id": "account-types-overview",
+ "text": (
+ "Account Types Overview: We offer Checking, Savings, Money Market, and Certificate "
+ "of Deposit (CD) accounts. Checking accounts include Standard (no minimum balance, "
+ "$12/month fee) and Preferred ($5,000 minimum, no fee, 0.01% APY). Savings accounts "
+ "earn 0.05% APY with a $300 minimum. Money Market accounts require $10,000 minimum "
+ "and earn tiered rates from 0.10% to 0.25% APY. CDs range from 3-month to 5-year terms."
+ ),
+ },
+ {
+ "id": "mortgage-lending-guidelines",
+ "text": (
+ "Mortgage Lending Guidelines: Conventional mortgage applications require a minimum "
+ "credit score of 620, debt-to-income ratio not exceeding 43%, and a down payment of "
+ "at least 3% for first-time buyers or 5% for subsequent purchases. Jumbo loans "
+ "(above $726,200) require 10% down and a 700+ credit score. Rate locks are available "
+ "for 30, 45, or 60 days. Pre-approval letters are valid for 90 days from issuance."
+ ),
+ },
+ {
+ "id": "api-integration-guide",
+ "text": (
+ "API Integration Guide: Our Open Banking API follows the FDX 6.0 standard and provides "
+ "RESTful endpoints for account information, transaction history, and payment initiation. "
+ "Authentication uses OAuth 2.0 with PKCE flow. Rate limits: 100 requests/minute for "
+ "read operations, 20 requests/minute for write operations. Webhooks are available for "
+ "real-time transaction notifications. SDKs are provided for Java, Python, and Node.js."
+ ),
+ },
+ {
+ "id": "compliance-kyc-aml",
+ "text": (
+ "KYC/AML Compliance: All new accounts require identity verification through our "
+ "tiered KYC process. Tier 1 (basic) accepts government-issued photo ID and SSN "
+ "verification. Tier 2 (enhanced) adds proof of address and source of funds "
+ "documentation for accounts exceeding $250,000. Suspicious Activity Reports (SARs) "
+ "are filed for transactions over $10,000 in cash or patterns suggesting structuring. "
+ "Customer risk scores are reassessed quarterly."
+ ),
+ },
+]
+
+
+def seed():
+ host = os.getenv("CHROMADB_HOST", "localhost")
+ port = int(os.getenv("CHROMADB_PORT", "8000"))
+
+ # Wait for ChromaDB to be ready
+ client = None
+ for attempt in range(30):
+ try:
+ client = chromadb.HttpClient(host=host, port=port)
+ client.heartbeat()
+ break
+ except Exception:
+ print(f"Waiting for ChromaDB at {host}:{port}... (attempt {attempt + 1})")
+ time.sleep(2)
+
+ if client is None:
+ print("ERROR: Could not connect to ChromaDB", file=sys.stderr)
+ sys.exit(1)
+
+ # Delete existing collection if present, then create fresh
+ try:
+ client.delete_collection(COLLECTION)
+ except Exception:
+ pass
+
+ embedding_fn = ef.OpenAIEmbeddingFunction(
+ api_key=os.getenv("OPENAI_API_KEY"),
+ model_name="text-embedding-3-small",
+ )
+ collection = client.create_collection(name=COLLECTION, embedding_function=embedding_fn)
+ collection.add(
+ ids=[d["id"] for d in DOCUMENTS],
+ documents=[d["text"] for d in DOCUMENTS],
+ )
+ print(f"Seeded {len(DOCUMENTS)} documents into '{COLLECTION}' collection.")
+
+
+if __name__ == "__main__":
+ seed()
diff --git a/examples/logging-samples/distributed-tracing/.env.example b/examples/logging-samples/distributed-tracing/.env.example
new file mode 100644
index 00000000..94031bcc
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing/.env.example
@@ -0,0 +1,9 @@
+GALILEO_API_KEY="your-galileo-api-key"
+OPENAI_API_KEY="your-openai-api-key"
+GALILEO_PROJECT="your-galileo-project"
+GALILEO_LOGSTREAM="distributed-tracing-example"
+
+GALILEO_MODE=distributed
+
+# Provide the console url below if you are not using app.galileo.ai
+# GALILEO_CONSOLE_URL="your-galileo-console-url"
diff --git a/examples/logging-samples/distributed-tracing/README.md b/examples/logging-samples/distributed-tracing/README.md
new file mode 100644
index 00000000..9ef2ec16
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing/README.md
@@ -0,0 +1,103 @@
+# Splunk AO Distributed Tracing - Decorator Example
+
+This example demonstrates distributed tracing across two services using Splunk AO's `@log` decorator.
+
+## Architecture
+
+- **Retrieval Service** (`retrieval_service.py`): A FastAPI service running on port 8000 that handles information retrieval
+- **Orchestrator Service** (`main_run.py`): The main client that coordinates the RAG pipeline by calling the retrieval service
+
+## Setup Instructions
+
+### 1. Create and Activate Virtual Environment
+
+```bash
+# Navigate to the distributed-tracing example directory
+cd python/logging-samples/distributed-tracing
+
+# Create virtual environment
+python -m venv venv
+
+# Activate virtual environment
+source venv/bin/activate
+```
+
+### 2. Install Dependencies
+Run
+
+```bash
+pip install -r requirements.txt
+```
+
+
+
+### 3. Configure Environment Variables
+Your `.env` should look like this. Feel free to follow the `.env.example` and enter your credentials
+```bash
+
+# Required: Your Splunk AO API key
+SPLUNK_AO_API_KEY="your-splunk-ao-api-key"
+
+# Required: OpenAI API key
+OPENAI_API_KEY="your-openai-api-key"
+
+# Required: Enable distributed mode for distributed tracing
+SPLUNK_AO_MODE=distributed
+
+# Optional: Splunk AO project and log stream names
+SPLUNK_AO_PROJECT="your-splunk-ao-project"
+SPLUNK_AO_LOG_STREAM=distributed-tracing-example
+
+# Provide the console url below if you are not using app.galileo.ai
+# SPLUNK_AO_CONSOLE_URL="your-splunk-ao-console-url"
+```
+
+### 4. Run the Services
+
+You need to run both services in **separate terminal processes**.
+
+#### Terminal 1: Start the Retrieval Service
+
+```bash
+# Make sure you're in the distributed-tracing example directory
+# cd python/logging-samples/distributed-tracing
+
+# Activate venv (if not already activated)
+# source venv/bin/activate
+
+# Start the retrieval service on port 8000
+uvicorn retrieval_service:app --reload --port 8000
+```
+
+You should see output like:
+```
+INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
+INFO: Started reloader process
+INFO: Started server process
+INFO: Waiting for application startup.
+INFO: Application startup complete.
+```
+
+#### Terminal 2: Run the Orchestrator
+
+```bash
+# In a NEW terminal, navigate to the distributed-tracing example directory
+cd python/logging-samples/distributed-tracing
+
+# Activate venv
+source venv/bin/activate
+
+# Run the orchestrator
+python main_run.py
+```
+
+## Expected Output
+
+When you run the orchestrator, you should see:
+
+```
+============================================================
+Question: What did Galileo Galilei research?
+============================================================
+Answer: Galileo Galilei made scientific observations that transformed our understanding of the universe.
+```
\ No newline at end of file
diff --git a/examples/logging-samples/distributed-tracing/main_run.py b/examples/logging-samples/distributed-tracing/main_run.py
new file mode 100644
index 00000000..830e781a
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing/main_run.py
@@ -0,0 +1,138 @@
+"""
+Orchestrator Service - Client that coordinates the RAG pipeline.
+
+This is a separate process that:
+1. Determines what context is needed
+2. Calls the retrieval service (separate process) via HTTP
+3. Formats the context for the LLM
+4. Calls the LLM with the retrieved context
+
+Run the retrieval service first: uvicorn retrieval_service:app --reload --port 8000
+Then run this: python main_distributed_tracing.py
+"""
+
+from dotenv import load_dotenv
+import httpx
+import asyncio
+from splunk_ao import log, get_tracing_headers
+from splunk_ao import openai
+
+load_dotenv()
+
+# Initialize OpenAI client with Splunk AO wrapper for automatic tracing
+openai_client = openai.OpenAI()
+
+# Retrieval service URL (separate process)
+RETRIEVAL_SERVICE_URL = "http://localhost:8000"
+
+
+# ============================================================================
+# ORCHESTRATOR SERVICE
+# ============================================================================
+
+
+@log
+async def orchestrator_agent(question: str) -> str:
+ """
+ Orchestrator agent that:
+ 1. Determines what information is needed
+ 2. Calls the retrieval service (separate process) via HTTP with distributed tracing
+ 3. Formats the context for the LLM
+ 4. Calls the LLM with the retrieved context
+ """
+ # Step 1: Determine what information we need
+ context_analysis = analyze_question(question)
+
+ # Step 2: Call retrieval service via HTTP with distributed tracing
+ # Get current trace and span IDs to pass to the retrieval service
+ # Similar to LangSmith's get_current_run_tree().to_headers()
+ try:
+ headers = get_tracing_headers()
+ except Exception as e:
+ print(f"Error getting tracing headers: {e}")
+ headers = {}
+
+ async with httpx.AsyncClient(base_url=RETRIEVAL_SERVICE_URL, timeout=100.0) as client:
+ try:
+ response = await client.post(
+ "/retrieve",
+ json={"query": question},
+ headers=headers, # Distributed tracing headers
+ )
+ response.raise_for_status()
+ retrieved_docs = response.json()["results"]
+ except httpx.HTTPError:
+ retrieved_docs = []
+
+ # Step 3: Format context for LLM
+ context = format_context(context_analysis, retrieved_docs)
+
+ # Step 4: Call LLM with retrieved context
+ # The galileo wrapped OpenAI client automatically logs LLM spans
+ response = openai_client.chat.completions.create(
+ messages=[
+ {
+ "role": "system",
+ "content": f"""Answer the user's question using only the provided context below.
+If the context doesn't contain enough information, say so.
+
+Context:
+{context}""",
+ },
+ {"role": "user", "content": question},
+ ],
+ model="gpt-5-mini",
+ )
+
+ return response.choices[0].message.content
+
+
+@log
+def analyze_question(question: str) -> dict:
+ """
+ Analyzes the question to determine what type of information is needed.
+ """
+ question_lower = question.lower()
+
+ analysis = {
+ "needs_company_info": any(word in question_lower for word in ["company", "work", "employer"]),
+ "needs_location_info": any(word in question_lower for word in ["location", "where", "city", "live"]),
+ "needs_education_info": any(word in question_lower for word in ["education", "school", "degree", "study"]),
+ "question_type": "factual",
+ }
+
+ return analysis
+
+
+@log
+def format_context(analysis: dict, docs: list[str]) -> str:
+ formatted = f"Analysis: {analysis}\n\n"
+ formatted += "Retrieved Documents:\n"
+ for i, doc in enumerate(docs, 1):
+ formatted += f"{i}. {doc}\n"
+ return formatted
+
+
+# ============================================================================
+# MAIN EXECUTION
+# ============================================================================
+
+
+async def main():
+ """Run the distributed tracing example"""
+
+ questions = [
+ "What did Galileo Galilei research?",
+ "Where did Galileo Galilei work?",
+ ]
+
+ for question in questions:
+ print(f"\n{'='*60}")
+ print(f"Question: {question}")
+ print(f"{'='*60}")
+ answer = await orchestrator_agent(question)
+ print(f"Answer: {answer}\n")
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/examples/logging-samples/distributed-tracing/requirements.txt b/examples/logging-samples/distributed-tracing/requirements.txt
new file mode 100644
index 00000000..65ab6f62
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing/requirements.txt
@@ -0,0 +1,10 @@
+# Core dependencies
+python-dotenv==1.1.1
+pydantic==2.11.9
+
+# HTTP and Web Framework
+httpx==0.28.1
+fastapi==0.117.1
+uvicorn==0.37.0
+
+galileo[openai,middleware]
diff --git a/examples/logging-samples/distributed-tracing/retrieval_service.py b/examples/logging-samples/distributed-tracing/retrieval_service.py
new file mode 100644
index 00000000..7d5a0601
--- /dev/null
+++ b/examples/logging-samples/distributed-tracing/retrieval_service.py
@@ -0,0 +1,76 @@
+"""
+Retrieval Service - A separate FastAPI service that handles information retrieval.
+
+Run this service with: uvicorn retrieval_service:app --reload --port 8000
+"""
+
+from fastapi import FastAPI
+from pydantic import BaseModel
+from dotenv import load_dotenv
+from splunk_ao import log
+from splunk_ao.middleware.tracing import TracingMiddleware
+
+load_dotenv()
+
+app = FastAPI(title="Retrieval Service")
+
+# Add Splunk AO tracing middleware to handle distributed tracing headers
+app.add_middleware(TracingMiddleware)
+
+
+class RetrievalRequest(BaseModel):
+ query: str
+
+
+class RetrievalResponse(BaseModel):
+ results: list[str]
+
+
+@log(span_type="retriever")
+def retrieval_service(query: str) -> list[str]:
+ """
+ Retrieval agent that searches through a knowledge base.
+ In a real scenario, this would query a vector database or search engine.
+ The @log decorator automatically handles distributed tracing headers if present.
+ """
+ # Mock knowledge base
+ knowledge_base = {
+ "birthplace": ["Galileo Galilei was born in Pisa, Italy in 1564"],
+ "profession": ["Galileo Galilei taught geometry, mechanics, and astronomy at the University of Padua for many years"],
+ "research": [
+ "Using improved telescopes that he built, Galileo Galilei made scientific observations that transformed our understanding of the universe."
+ ],
+ }
+
+ # Simple keyword-based retrieval (in production, use vector search)
+ results = []
+ query_lower = query.lower()
+ for category, facts in knowledge_base.items():
+ if category in query_lower or any(word in query_lower for word in ["work", "company", "location", "education"]):
+ results.extend(facts)
+
+ return results[:3] # Return top 3 results
+
+
+@app.post("/retrieve", response_model=RetrievalResponse)
+@log
+async def retrieve_endpoint(request: RetrievalRequest):
+ """
+ Endpoint that receives retrieval requests from the orchestrator.
+ The TracingMiddleware automatically handles distributed tracing headers.
+ """
+ # The @log decorator automatically uses the trace context set by middleware
+ results = retrieval_service(request.query)
+ return RetrievalResponse(results=results)
+
+
+@app.get("/health")
+async def health():
+ """Health check endpoint"""
+ return {"status": "healthy"}
+
+
+if __name__ == "__main__":
+ import uvicorn
+
+ uvicorn.run(app, host="0.0.0.0", port=8000)
diff --git a/examples/logging-samples/galileologger/.env.example b/examples/logging-samples/galileologger/.env.example
new file mode 100644
index 00000000..10891006
--- /dev/null
+++ b/examples/logging-samples/galileologger/.env.example
@@ -0,0 +1,6 @@
+GALILEO_API_KEY="your-galileo-api-key"
+GALILEO_PROJECT="your-galileo-project"
+GALILEO_LOGSTREAM="galileologger-example"
+
+# Provide the console url below if you are not using app.galileo.ai
+# GALILEO_CONSOLE_URL="your-galileo-console-url"
diff --git a/examples/logging-samples/galileologger/README.md b/examples/logging-samples/galileologger/README.md
new file mode 100644
index 00000000..60c49cf6
--- /dev/null
+++ b/examples/logging-samples/galileologger/README.md
@@ -0,0 +1,115 @@
+# SplunkAOLogger Examples
+
+The examples in this folder demonstrates how to use [`SplunkAOLogger`](https://docs.galileo.ai/sdk-api/python/reference/logger/logger) to log data to Splunk AO. Other ways of logging to Splunk AO can be found in [how-to guides](https://docs.galileo.ai/how-to-guides/basics/basic-example).
+
+## Setup Instructions
+
+### 1. Create and Activate Virtual Environment
+
+```bash
+# Navigate to the logger example folder
+cd examples/logging-samples/galileologger
+
+# Create virtual environment
+python -m venv venv
+
+# Activate virtual environment
+source venv/bin/activate
+```
+
+### 2. Install Dependencies
+
+Run
+
+```bash
+pip install -r requirements.txt
+```
+
+### 3. Configure Environment Variables
+
+Your `.env` should look like this. Feel free to follow the `.env.example` and enter your credentials
+
+```bash
+
+# Required: Your Splunk AO API key
+SPLUNK_AO_API_KEY="your-splunk-ao-api-key"
+
+# Optional: Splunk AO project and log stream names
+SPLUNK_AO_PROJECT="your-splunk-ao-project"
+SPLUNK_AO_LOG_STREAM=splunk-ao-logger-example
+
+# Provide the console url below if you are not using app.galileo.ai
+# SPLUNK_AO_CONSOLE_URL="your-splunk-ao-console-url"
+```
+
+## Basic Example
+
+Run the basic example:
+
+```bash
+python basic-example.py
+```
+
+This example's expected output includes the Splunk AO URL of the log stream.
+
+Go to this URL in your browser to confirm the logged data.
+
+Screenshot of the logged data:
+
+
+
+## Retriever Example
+
+Run the retriever example:
+
+```bash
+python retriever-example.py
+```
+
+This example logs a more complex trace with multiple spans, including a retriever span.
+
+The example's expected output includes the Splunk AO URL of the log stream. Go to this URL in your browser to confirm the logged data.
+
+Screenshot of the logged data:
+
+
+
+## Redaction Example
+
+Run the redaction example:
+
+```bash
+python redaction-example.py
+```
+
+This example logs traces with `redacted_input` (input excluding sensitive info such as social security numbers or email adddresses).
+
+The optional parameters `redacted_input` and `redacted_output` can be provided to [`SplunkAOLogger`](https://docs.galileo.ai/sdk-api/python/reference/logger/logger) methods such as [`start_trace`](https://docs.galileo.ai/sdk-api/python/reference/logger/logger#start_trace) and [`add_retriever_span`](https://docs.galileo.ai/sdk-api/python/reference/logger/logger#add_retriever_span).
+
+The example's expected output includes an export of logged traces, as well as the Splunk AO URL of the log stream. Go to this URL in your browser to confirm the logged data.
+
+Screenshots of the logged data with sensitive info redacted:
+
+
+
+
+
+## Metadata Example
+
+Run the metadata example:
+
+```bash
+python metadata-example.py
+```
+
+This example logs a session, trace, and span with metadata (optional key-value attributes).
+
+The optional parameter `metadata` can be provided to [`SplunkAOLogger`](https://docs.galileo.ai/sdk-api/python/reference/logger/logger) methods such as [`start_session`](https://docs.galileo.ai/sdk-api/python/reference/logger/logger#start_session), [`start_trace`](https://docs.galileo.ai/sdk-api/python/reference/logger/logger#start_trace) and [`add_llm_span`](https://docs.galileo.ai/sdk-api/python/reference/logger/logger#add_llm_span).
+
+The example's expected output includes the Splunk AO URL of the log stream. Go to this URL in your browser to confirm the logged data.
+
+Screenshots of the logged data with metadata:
+
+
+
+
diff --git a/examples/logging-samples/galileologger/basic-example.py b/examples/logging-samples/galileologger/basic-example.py
new file mode 100644
index 00000000..e2a7ed82
--- /dev/null
+++ b/examples/logging-samples/galileologger/basic-example.py
@@ -0,0 +1,42 @@
+from splunk_ao import SplunkAOLogger
+from splunk_ao.config import SplunkAOConfig # For displaying the log stream URL
+
+# Load environment variables from .env file
+from dotenv import load_dotenv
+
+load_dotenv()
+
+# Create a logger instance
+logger = SplunkAOLogger()
+
+# Start a session
+session_id = logger.start_session(name="Test session")
+
+# Start a new trace
+trace = logger.start_trace("Say this is a test")
+
+# Add an LLM span to the trace
+logger.add_llm_span(
+ input="Say this is a test",
+ output="Hello, this is a test",
+ model="gpt-4o",
+ num_input_tokens=10,
+ num_output_tokens=3,
+ total_tokens=13,
+ duration_ns=1000,
+)
+
+# Conclude the trace with the final output
+logger.conclude(output="Hello, this is a test", duration_ns=1000)
+
+# Flush the trace to Splunk AO
+logger.flush()
+
+
+# Show link to Splunk AO log stream
+config = SplunkAOConfig.get()
+project_url = f"{config.console_url}project/{logger.project_id}"
+log_stream_url = f"{project_url}/log-streams/{logger.log_stream_id}"
+
+print("🚀 Splunk AO Log Stream:")
+print(log_stream_url)
diff --git a/examples/logging-samples/galileologger/metadata-example.py b/examples/logging-samples/galileologger/metadata-example.py
new file mode 100644
index 00000000..f382799c
--- /dev/null
+++ b/examples/logging-samples/galileologger/metadata-example.py
@@ -0,0 +1,39 @@
+from splunk_ao import SplunkAOLogger
+from splunk_ao.config import SplunkAOConfig # For displaying the log stream URL
+from dotenv import load_dotenv
+
+# Load environment variables from the .env file
+load_dotenv()
+
+# Create a logger instance
+logger = SplunkAOLogger()
+
+# Define inputs and outputs
+input_prompt = "Explain the following topic succinctly: Newton's First Law"
+output_answer = "A body remains at rest or moves in a straight line with constant speed unless acted on by a nonzero net external force."
+
+# Define optional metadata
+metadata = {"experimentNumber": "1", "promptVersion": "0.0.1", "field": "physics"}
+
+# Start a Splunk AO session with optional metadata
+session_id = logger.start_session(name="Test session", metadata=metadata)
+
+# Initialize a new Trace with optional metadata
+trace = logger.start_trace(input=input_prompt, metadata=metadata)
+
+# Add an LLM span to the trace with optional metadata
+logger.add_llm_span(input=[{"role": "system", "content": input_prompt}], output=output_answer, model="gpt-5-mini", metadata=metadata)
+
+# Conclude the trace with the final output
+logger.conclude(output_answer)
+
+# Flush the trace to Splunk AO
+logger.flush()
+
+# Show link to Splunk AO log stream
+config = SplunkAOConfig.get()
+project_url = f"{config.console_url}project/{logger.project_id}"
+log_stream_url = f"{project_url}/log-streams/{logger.log_stream_id}"
+
+print("🚀 Splunk AO Log Stream:")
+print(log_stream_url)
diff --git a/examples/logging-samples/galileologger/redaction-example.py b/examples/logging-samples/galileologger/redaction-example.py
new file mode 100644
index 00000000..67296c50
--- /dev/null
+++ b/examples/logging-samples/galileologger/redaction-example.py
@@ -0,0 +1,66 @@
+from splunk_ao import SplunkAOLogger
+from splunk_ao.projects import get_project
+from splunk_ao.log_streams import get_log_stream
+from splunk_ao.export import export_records
+from galileo.resources.models.root_type import RootType
+from splunk_ao.config import SplunkAOConfig # For displaying the log stream URL
+
+# Load environment variables from .env file
+from dotenv import load_dotenv
+
+load_dotenv()
+
+logger = SplunkAOLogger() # Create a logger instance
+
+# Example of how to create "redacted_input", matching "SSN" as sensitive info
+# ---------------------------------------------------------------------------
+sensitive_info = "SSN"
+user_input = "Who's a good bot SSN?"
+redacted_input = user_input.replace(sensitive_info, "***")
+trace = logger.start_trace(input=user_input, redacted_input=redacted_input)
+
+logger.flush() # send the trace to Splunk AO
+
+# Example of how to create "redacted_input", matching email as sensitive info
+# ---------------------------------------------------------------------------
+
+import re # regular expression
+
+user_input = "This is the email: example@example.com"
+
+email_match = re.search(r"[\w.-]+@[\w.-]+\.\w+", user_input)
+sensitive_info = email_match.group() if email_match else None
+
+if sensitive_info:
+ redacted_input = user_input.replace(sensitive_info, "***")
+ trace = logger.start_trace(input=user_input, redacted_input=redacted_input)
+else:
+ trace = logger.start_trace(input=user_input)
+
+logger.flush() # send the trace to Splunk AO
+
+# It's also possible to use a service such as https://www.private-ai.com/ to create the redacted_input
+
+# Export the logged traces in the logstream
+
+import os
+
+project_name = os.getenv("SPLUNK_AO_PROJECT")
+log_stream_name = os.getenv("SPLUNK_AO_LOG_STREAM")
+
+project = get_project(name=project_name)
+log_stream = get_log_stream(name=log_stream_name, project_name=project_name)
+
+records = export_records(project_id=project.id, log_stream_id=log_stream.id, root_type=RootType.TRACE)
+
+print(list(records))
+
+
+# Show link to Splunk AO log stream
+
+config = SplunkAOConfig.get()
+project_url = f"{config.console_url}project/{logger.project_id}"
+log_stream_url = f"{project_url}/log-streams/{logger.log_stream_id}"
+
+print("🚀 Splunk AO Log Stream:")
+print(log_stream_url)
diff --git a/examples/logging-samples/galileologger/requirements.txt b/examples/logging-samples/galileologger/requirements.txt
new file mode 100644
index 00000000..b05d7d29
--- /dev/null
+++ b/examples/logging-samples/galileologger/requirements.txt
@@ -0,0 +1,2 @@
+galileo
+python-dotenv
\ No newline at end of file
diff --git a/examples/logging-samples/galileologger/retriever-example.py b/examples/logging-samples/galileologger/retriever-example.py
new file mode 100644
index 00000000..53830a74
--- /dev/null
+++ b/examples/logging-samples/galileologger/retriever-example.py
@@ -0,0 +1,68 @@
+from splunk_ao import splunk_ao_context # The Splunk AO context manager
+from splunk_ao.config import SplunkAOConfig # For displaying the log stream URL
+
+# Load environment variables from .env file
+from dotenv import load_dotenv
+
+load_dotenv()
+
+prompt_input_data = [
+ "Explain Newton's First Law like you're a dramatic movie trailer narrator.",
+ "Write a silly limerick about Newton's First Law starring a very stubborn banana.",
+ "Explain Newton's First Law to a 5-year-old using toys, snacks, or animals.",
+]
+
+prompt_output_data = [
+ "In a world where objects refuse to budge, Newton's First Law declares that things stay still—or keep moving—unless a force steps in to change their fate.",
+ "There once was a banana so grand,\nWho lay very still on the land.\nIt stayed put all day,\nTill a force came its way,\nNow Newton would say, 'Just as planned!'",
+ "Things like to keep doing what they're already doing. A toy will stay still or keep rolling until something, like your hand, makes it change.",
+]
+
+logger = splunk_ao_context.get_logger_instance()
+
+for i in range(len(prompt_input_data)):
+
+ prompt_output = prompt_output_data[0]
+
+ # Start a session
+ session_id = logger.start_session(name="Test session with retriever span")
+
+ # Start a new trace
+ trace = logger.start_trace("This is a trace start")
+
+ # Add a retriever span for document retrieval
+ logger.add_retriever_span(input="Who's a good bot?", output=["Research shows that I am a good bot."], name="Document Retrieval", duration_ns=1000000)
+
+ # Add an LLM span for generating a response
+ logger.add_llm_span(
+ input="Who's a good bot?",
+ output="I am!",
+ model="gpt-5-mini",
+ name="Response Generation",
+ num_input_tokens=25,
+ num_output_tokens=3,
+ total_tokens=28,
+ duration_ns=1000000,
+ )
+
+ # Conclude the trace with the final output
+ logger.conclude(output="This is a trace conclude", duration_ns=1000)
+
+ # Add another trace and span
+ logger.start_trace("This is another trace start")
+
+ logger.add_llm_span(input=prompt_input_data[i], output=prompt_output_data[i], model="gpt-5-mini")
+
+ logger.conclude(output="This is another trace conclude", duration_ns=1000)
+
+ # Flush the traces to splunk_ao
+ logger.flush()
+
+
+# Show link to Splunk AO log stream
+config = SplunkAOConfig.get()
+project_url = f"{config.console_url}project/{logger.project_id}"
+log_stream_url = f"{project_url}/log-streams/{logger.log_stream_id}"
+
+print("🚀 Splunk AO Log Stream:")
+print(log_stream_url)
diff --git a/examples/logging-samples/galileologger/screenshot-basic-example.png b/examples/logging-samples/galileologger/screenshot-basic-example.png
new file mode 100644
index 00000000..3d0ca26a
Binary files /dev/null and b/examples/logging-samples/galileologger/screenshot-basic-example.png differ
diff --git a/examples/logging-samples/galileologger/screenshot-metadata-logs-view.png b/examples/logging-samples/galileologger/screenshot-metadata-logs-view.png
new file mode 100644
index 00000000..2f194346
Binary files /dev/null and b/examples/logging-samples/galileologger/screenshot-metadata-logs-view.png differ
diff --git a/examples/logging-samples/galileologger/screenshot-metadata-messages-view.png b/examples/logging-samples/galileologger/screenshot-metadata-messages-view.png
new file mode 100644
index 00000000..b24943b9
Binary files /dev/null and b/examples/logging-samples/galileologger/screenshot-metadata-messages-view.png differ
diff --git a/examples/logging-samples/galileologger/screenshot-redaction-example-email.png b/examples/logging-samples/galileologger/screenshot-redaction-example-email.png
new file mode 100644
index 00000000..e1c585fd
Binary files /dev/null and b/examples/logging-samples/galileologger/screenshot-redaction-example-email.png differ
diff --git a/examples/logging-samples/galileologger/screenshot-redaction-example-ssn.png b/examples/logging-samples/galileologger/screenshot-redaction-example-ssn.png
new file mode 100644
index 00000000..c6534edc
Binary files /dev/null and b/examples/logging-samples/galileologger/screenshot-redaction-example-ssn.png differ
diff --git a/examples/logging-samples/galileologger/screenshot-retriever-example.png b/examples/logging-samples/galileologger/screenshot-retriever-example.png
new file mode 100644
index 00000000..01e7fd3c
Binary files /dev/null and b/examples/logging-samples/galileologger/screenshot-retriever-example.png differ
diff --git a/examples/logging-samples/log-mcp-calls/.env.example b/examples/logging-samples/log-mcp-calls/.env.example
new file mode 100644
index 00000000..501dadd9
--- /dev/null
+++ b/examples/logging-samples/log-mcp-calls/.env.example
@@ -0,0 +1,22 @@
+# Your Galileo API key
+GALILEO_API_KEY="your-galileo-api-key"
+
+# Your Galileo project name
+GALILEO_PROJECT="your-galileo-project-name"
+
+# The name of the Log stream you want to use for logging
+GALILEO_LOG_STREAM="your-galileo-log-stream"
+
+# Provide the console url below if you are using a
+# custom deployment, and not using the free tier, or app.galileo.ai.
+# This will look something like “console.galileo.yourcompany.com”.
+# GALILEO_CONSOLE_URL="your-galileo-console-url"
+
+# # The URL of the MCP server you are connecting to
+MCP_SERVER_URL=https://api.galileo.ai/mcp/http/mcp
+
+# Anthropic properties
+ANTHROPIC_API_KEY="your-anthropic-api-key"
+
+# The Anthropic model you are using
+ANTHROPIC_MODEL=claude-sonnet-4-5
\ No newline at end of file
diff --git a/examples/logging-samples/log-mcp-calls/README.md b/examples/logging-samples/log-mcp-calls/README.md
new file mode 100644
index 00000000..e7fffc25
--- /dev/null
+++ b/examples/logging-samples/log-mcp-calls/README.md
@@ -0,0 +1,80 @@
+# Log MCP calls as tool spans
+
+This is an example project demonstrating how to use Splunk AO to log MCP server calls as tool spans. This code is described in the [Log MCP Server Tool Calls how-to guide](https://docs.galileo.ai/how-to-guides/basics/log-mcp-server-calls/log-mcp-server-calls) in the Splunk AO documentation.
+
+The MCP server used by default is the [Splunk AO MCP server](https://docs.galileo.ai/getting-started/mcp/setup-galileo-mcp), but you can use this code with any MCP server that supports a streamable HTTP connection by changing the `MCP_SERVER_URL` environment variable.
+
+## Getting Started
+
+To get started with this project, you'll need to have Python 3.10 or later installed. You can then install the required dependencies in a virtual environment:
+
+```bash
+pip install -r requirements.txt
+```
+
+You will also need an [Anthropic API key](https://console.anthropic.com/settings/keys).
+
+## Configure environment variables
+
+You will need to configure environment variables to use this project. Copy the `.env.example` file to `.env`, then update the environment variables in the `.env` file with your Anthropic and Splunk AO values:
+
+```ini
+# Your Splunk AO API key
+SPLUNK_AO_API_KEY="your-splunk-ao-api-key"
+
+# Your Splunk AO project name
+SPLUNK_AO_PROJECT="your-splunk-ao-project-name"
+
+# The name of the Log stream you want to use for logging
+SPLUNK_AO_LOG_STREAM="your-splunk-ao-log-stream"
+
+# Provide the console url below if you are using a
+# custom deployment, and not using the free tier, or app.galileo.ai.
+# This will look something like “console.galileo.yourcompany.com”.
+# SPLUNK_AO_CONSOLE_URL="your-splunk-ao-console-url"
+
+# # The URL of the MCP server you are connecting to
+MCP_SERVER_URL=https://api.galileo.ai/mcp/http/mcp
+
+# Anthropic properties
+ANTHROPIC_API_KEY="your-anthropic-api-key"
+
+# The Anthropic model you are using
+ANTHROPIC_MODEL=claude-sonnet-4-5
+```
+
+## Usage
+
+Once the dependencies are installed, you can run the example application:
+
+```bash
+python app.py
+```
+
+You will see a list of the tools available on the MCP server. You can then ask questions against that server:
+
+```output
+Connected to server with tools: ['integrate_galileo_with_langchain', 'integrate_galileo_with_openai', 'get_logstream_insights', 'validate_dataset', 'create_galileo_dataset', 'create_prompt_template', 'setup_galileo_experiment', 'search_docs']
+
+Query: How do I use the SplunkAOLogger?
+
+I'll search the Splunk AO documentation to find information about how to use the SplunkAOLogger.
+[Calling tool search_docs with args {'query': 'SplunkAOLogger usage how to use'}]
+# Using the SplunkAOLogger
+
+The **SplunkAOLogger** class provides granular control over logging in Splunk AO. Here's how to use it:
+...
+```
+
+## Project Structure
+
+The project structure is as follows:
+
+```folder
+log-mcp-calls/
+├── app.py. # The main application file
+├── mcp_client.py. # The MCP client code
+├── env.example # List of environment variables
+├── requirements.txt # Python project requirements
+└── README.md # Project documentation
+```
diff --git a/examples/logging-samples/log-mcp-calls/app.py b/examples/logging-samples/log-mcp-calls/app.py
new file mode 100644
index 00000000..40ddefd2
--- /dev/null
+++ b/examples/logging-samples/log-mcp-calls/app.py
@@ -0,0 +1,149 @@
+"""
+A sample application that shows how to log MCP server calls as tool spans.
+
+This code is described in the Log MCP Server Tool Calls how-to guide in the Splunk AO documentation:
+https://docs.galileo.ai/how-to-guides/basics/log-mcp-server-calls/log-mcp-server-calls
+"""
+
+import asyncio
+import os
+
+from datetime import datetime
+
+from anthropic import Anthropic, omit
+from anthropic.types import Message
+
+from dotenv import load_dotenv
+
+from splunk_ao import splunk_ao_context
+
+from mcp_client import MCPClient
+
+load_dotenv() # load environment variables from .env
+
+anthropic = Anthropic()
+message_history = []
+mcp_client = MCPClient()
+
+
+def call_llm(messages, use_tools: bool = True) -> Message:
+ """
+ Call the LLM with the provided query and return
+ the response text
+ """
+ galileo_logger = splunk_ao_context.get_logger_instance()
+
+ # Capture the current time in nanoseconds for logging
+ start_time_ns = datetime.now().timestamp() * 1_000_000_000
+
+ # Call the LLM
+ response = anthropic.messages.create(
+ model=os.environ["ANTHROPIC_MODEL"],
+ max_tokens=1000,
+ messages=messages,
+ tools=mcp_client.tools if use_tools else omit,
+ )
+
+ # Log the LLM call
+ for content in [c for c in response.content if c.type == "text"]:
+ galileo_logger.add_llm_span(
+ input=messages,
+ output=content.text,
+ model=os.environ["ANTHROPIC_MODEL"],
+ num_input_tokens=response.usage.input_tokens,
+ num_output_tokens=response.usage.output_tokens,
+ total_tokens=response.usage.input_tokens + response.usage.output_tokens,
+ duration_ns=int((datetime.now().timestamp() * 1_000_000_000) - start_time_ns),
+ )
+
+ return response
+
+
+async def process_query(query: str) -> str:
+ """Process a query using Claude"""
+ # Capture the current time in nanoseconds for logging
+ start_time_ns = datetime.now().timestamp() * 1_000_000_000
+
+ # Start a Splunk AO Logger trace
+ galileo_logger = splunk_ao_context.get_logger_instance()
+ galileo_logger.start_trace(
+ input=query,
+ name="MCP Chatbot Query",
+ )
+
+ message_history.append({"role": "user", "content": query})
+
+ # Call the LLM
+ response = call_llm(message_history)
+
+ # Process the response
+ final_text = []
+
+ for content in response.content:
+ if content.type == "text":
+ # Save the text response to the message history
+ message_history.append({"role": "assistant", "content": content.text})
+ final_text.append(content.text)
+ elif content.type == "tool_use":
+ # Get the tool start time
+ tool_start_time_ns = datetime.now().timestamp() * 1_000_000_000
+
+ # Execute tool call
+ result = await mcp_client.call_tool(content.name, content.input)
+
+ # Log the tool call
+ galileo_logger.add_tool_span(
+ input=query,
+ output=result.content[0].text,
+ name=content.name,
+ tool_call_id=content.id,
+ duration_ns=int((datetime.now().timestamp() * 1_000_000_000) - tool_start_time_ns),
+ )
+
+ final_text.append(f"[Calling tool {content.name}" + f"with args {content.input}]")
+
+ # Create a copy of the messages
+ # And add the tool response
+ messages = message_history.copy()
+ if hasattr(content, "text") and content.text:
+ messages.append({"role": "assistant", "content": content.text})
+ messages.append({"role": "user", "content": result.content})
+
+ # Call the LLM without tools for the final response
+ response = call_llm(messages, use_tools=False)
+
+ # Add the response to the original message history
+ message_history.append({"role": "assistant", "content": response.content[0].text})
+
+ final_text.append(response.content[0].text)
+
+ # Conclude and flush the trace
+ galileo_logger.conclude(
+ output="\n".join(final_text),
+ duration_ns=int((datetime.now().timestamp() * 1_000_000_000) - start_time_ns),
+ )
+ galileo_logger.flush()
+
+ # Return the final response text
+ return "\n".join(final_text)
+
+
+async def main():
+ """Main function to run the chat loop"""
+ # Connect to the MCP server
+ await mcp_client.connect_to_server()
+
+ # Start a Splunk AO Logger session
+ current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+ splunk_ao_context.start_session(f"MCP Chatbot Session - {current_time}")
+
+ while True:
+ query = input("\nQuery: ").strip()
+ if query.lower() == "quit":
+ break
+
+ print(await process_query(query))
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/examples/logging-samples/log-mcp-calls/mcp_client.py b/examples/logging-samples/log-mcp-calls/mcp_client.py
new file mode 100644
index 00000000..87274dcb
--- /dev/null
+++ b/examples/logging-samples/log-mcp-calls/mcp_client.py
@@ -0,0 +1,68 @@
+"""
+An MCP Client implementation to connect to an MCP server and manage tools.
+"""
+
+import os
+
+from contextlib import AsyncExitStack
+from typing import Optional
+
+from mcp import ClientSession
+from mcp.client.streamable_http import streamablehttp_client
+
+
+class MCPClient:
+ """MCP Client to connect to MCP server and manage tools"""
+
+ def __init__(self):
+ # Initialize session and client objects
+ self._session: Optional[ClientSession] = None
+ self._exit_stack = AsyncExitStack()
+ self.tools = []
+
+ async def connect_to_server(self):
+ """Connect to an MCP server"""
+ # Establish streamable HTTP connection
+ read, write, _ = await self._exit_stack.enter_async_context(
+ streamablehttp_client(
+ url=os.environ.get("MCP_SERVER_URL", "https://api.galileo.ai/mcp/http/mcp"),
+ headers={
+ "Galileo-API-Key": os.environ["SPLUNK_AO_API_KEY"],
+ "Accept": "text/event-stream",
+ },
+ )
+ )
+
+ # Create the MCP client session
+ self._session = await self._exit_stack.enter_async_context(ClientSession(read, write))
+
+ # Initialize the session
+ await self._session.initialize()
+
+ # List the available tools
+ response = await self._session.list_tools()
+ self.tools = [
+ {
+ "name": tool.name,
+ "description": tool.description,
+ "input_schema": tool.inputSchema,
+ }
+ for tool in response.tools
+ ]
+ print(
+ "\nConnected to server with tools:",
+ [tool["name"] for tool in self.tools],
+ )
+
+ async def call_tool(self, tool_name: str, input_data: dict):
+ """Call a tool by name with the provided input data"""
+ # Ensure a session is established
+ if not self._session:
+ raise RuntimeError("MCP Client is not connected to a server.")
+
+ # Call the tool and return the result
+ return await self._session.call_tool(tool_name, input_data)
+
+ async def cleanup(self):
+ """Clean up resources"""
+ await self._exit_stack.aclose()
diff --git a/examples/logging-samples/log-mcp-calls/requirements.txt b/examples/logging-samples/log-mcp-calls/requirements.txt
new file mode 100644
index 00000000..50603e37
--- /dev/null
+++ b/examples/logging-samples/log-mcp-calls/requirements.txt
@@ -0,0 +1,4 @@
+anthropic
+galileo
+mcp
+python-dotenv
\ No newline at end of file
diff --git a/examples/logging-samples/openai-responses/.env.example b/examples/logging-samples/openai-responses/.env.example
new file mode 100644
index 00000000..9460c823
--- /dev/null
+++ b/examples/logging-samples/openai-responses/.env.example
@@ -0,0 +1,9 @@
+# Galileo Environment Variables
+GALILEO_API_KEY=your-galileo-api-key # Your Galileo API key.
+GALILEO_PROJECT=your-galileo-project-name # Your Galileo project name.
+GALILEO_LOG_STREAM=your-galileo-log-stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# GALILEO_CONSOLE_URL=your-galileo-console-url # Optional if you are using a hosted version of Galileo
+
+OPENAI_API_KEY=your-openai-key-here
diff --git a/examples/logging-samples/openai-responses/README.md b/examples/logging-samples/openai-responses/README.md
new file mode 100644
index 00000000..be554565
--- /dev/null
+++ b/examples/logging-samples/openai-responses/README.md
@@ -0,0 +1,73 @@
+# Log OpenAI Responses API calls with tool use
+
+This is an example project demonstrating how to use Splunk AO to log [OpenAI Responses API](https://platform.openai.com/docs/api-reference/responses) calls, including multi-turn tool calling. The example uses Splunk AO's wrapped OpenAI client to automatically instrument and log all API interactions.
+
+The example defines two simulated tools (`get_weather` and `get_stock_price`), sends a user query that triggers both tool calls, executes the functions locally, and feeds the results back to the model for a final response.
+
+## Getting Started
+
+To get started with this project, you'll need to have Python 3.12 or later installed. You can then install the required dependencies in a virtual environment:
+
+```bash
+pip install -r requirements.txt
+```
+
+Or, if you're using [uv](https://docs.astral.sh/uv/):
+
+```bash
+uv sync
+```
+
+You will also need an [OpenAI API key](https://platform.openai.com/api-keys).
+
+## Configure environment variables
+
+You will need to configure the following environment variables:
+
+```ini
+# Your Splunk AO API key
+SPLUNK_AO_API_KEY="your-splunk-ao-api-key"
+
+# Your Splunk AO project name
+SPLUNK_AO_PROJECT="your-splunk-ao-project-name"
+
+# The name of the Log stream you want to use for logging
+SPLUNK_AO_LOG_STREAM="your-splunk-ao-log-stream"
+
+# Provide the console url below if you are using a
+# custom deployment, and not using the free tier, or app.galileo.ai.
+# This will look something like "console.galileo.yourcompany.com".
+# SPLUNK_AO_CONSOLE_URL="your-splunk-ao-console-url"
+
+# OpenAI properties
+OPENAI_API_KEY="your-openai-api-key"
+```
+
+## Usage
+
+Once the dependencies are installed, you can run the example application:
+
+```bash
+python main.py
+```
+
+The application will send a query asking about the weather in San Francisco and the stock price of Apple. It will:
+
+1. Call the OpenAI Responses API with the defined tools.
+2. Parse the function calls returned by the model.
+3. Execute the simulated `get_weather` and `get_stock_price` functions.
+4. Send the tool results back to the model for a final natural language response.
+
+All API calls are automatically logged to Splunk AO via the wrapped OpenAI client (`from splunk_ao import openai`).
+
+## Project Structure
+
+The project structure is as follows:
+
+```folder
+openai-responses/
+├── main.py # The main application file
+├── pyproject.toml # Python project configuration and dependencies
+├── .python-version # Python version specification
+└── README.md # Project documentation
+```
diff --git a/examples/logging-samples/openai-responses/main.py b/examples/logging-samples/openai-responses/main.py
new file mode 100644
index 00000000..c84cc2cd
--- /dev/null
+++ b/examples/logging-samples/openai-responses/main.py
@@ -0,0 +1,141 @@
+import json
+import logging
+from typing import Any
+
+from dotenv import load_dotenv
+
+# Use Splunk AO's wrapped OpenAI client to automatically log all API calls.
+# This is a drop-in replacement for the standard `openai` module.
+from splunk_ao import openai
+
+load_dotenv()
+
+logging.basicConfig(level=logging.INFO)
+
+# Create an OpenAI client. Because we imported from `galileo`, all calls
+# made through this client are automatically instrumented and logged.
+client = openai.OpenAI()
+
+# Define the tools that will be available to the model. Each tool is a
+# function definition that the model can choose to call based on the user's query.
+tools: list[dict[str, Any]] = [
+ {
+ "type": "function",
+ "name": "get_weather",
+ "description": "Get the current weather for a given location",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "location": {
+ "type": "string",
+ "description": "The city and state, e.g. San Francisco, CA",
+ },
+ "unit": {
+ "type": "string",
+ "enum": ["celsius", "fahrenheit"],
+ "description": "The temperature unit",
+ },
+ },
+ "required": ["location"],
+ },
+ },
+ {
+ "type": "function",
+ "name": "get_stock_price",
+ "description": "Get the current stock price for a given ticker symbol",
+ "parameters": {
+ "type": "object",
+ "properties": {
+ "symbol": {
+ "type": "string",
+ "description": "The stock ticker symbol, e.g. AAPL, GOOGL, MSFT",
+ },
+ },
+ "required": ["symbol"],
+ },
+ },
+]
+
+
+# --- Simulated tool implementations ---
+# In a real application, these would call external APIs or services.
+
+
+def get_weather(location: str, unit: str = "fahrenheit") -> str:
+ """Simulated weather function that returns a hardcoded temperature."""
+ return json.dumps({"location": location, "temperature": 72, "unit": unit})
+
+
+def get_stock_price(symbol: str) -> str:
+ """Simulated stock price function that returns a hardcoded price."""
+ prices = {"AAPL": 178.50, "GOOGL": 141.25, "MSFT": 378.90, "AMZN": 153.40}
+ price = prices.get(symbol.upper(), 100.00)
+ return json.dumps({"symbol": symbol.upper(), "price": price, "currency": "USD"})
+
+
+def main():
+ user_message = "What's the weather like in San Francisco and what's the current stock price of Apple?"
+ input_list = []
+
+ # Step 1: Send the user message to the model along with the available tools.
+ # The model will analyze the query and decide which tools to call.
+ response = client.responses.create(
+ model="gpt-4o-mini",
+ input=user_message,
+ tools=tools, # type: ignore[arg-type]
+ # reasoning={"effort": "high"},
+ )
+
+ # Step 2: Collect the model's output (which includes function_call items)
+ # into the input list for the next request.
+ input_list += response.output
+
+ # Step 3: Iterate over the model's output and execute any requested tool calls.
+ # Each function_call item contains the function name and its arguments.
+ for item in response.output:
+ if item.type == "function_call":
+ if item.name == "get_weather":
+ weather = get_weather(**json.loads(item.arguments))
+
+ # Append the tool result back to the input list so the model
+ # can use it in the next turn. The call_id links the output
+ # back to the original function call.
+ input_list.append(
+ {
+ "type": "function_call_output",
+ "call_id": item.call_id,
+ "output": json.dumps({"weather": weather}),
+ }
+ )
+ if item.name == "get_stock_price":
+ stock_price = get_stock_price(**json.loads(item.arguments))
+ input_list.append(
+ {
+ "type": "function_call_output",
+ "call_id": item.call_id,
+ "output": json.dumps({"stock_price": stock_price}),
+ }
+ )
+
+ print("Final input:")
+ print(input_list)
+
+ # Step 4: Send the conversation history (including tool call results) back
+ # to the model. The model will now generate a natural language response
+ # that incorporates the tool outputs.
+ response = client.responses.create(
+ model="gpt-5",
+ instructions="Respond using the results provided to you by the tools.",
+ tools=tools, # pyright: ignore[reportArgumentType]
+ input=input_list,
+ reasoning={"effort": "high", "summary": "detailed"},
+ )
+
+ # Step 5: Print the final response from the model.
+ print("Final output:")
+ print(response.model_dump_json(indent=2))
+ print("\n" + response.output_text)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/logging-samples/openai-responses/pyproject.toml b/examples/logging-samples/openai-responses/pyproject.toml
new file mode 100644
index 00000000..46fdc1b8
--- /dev/null
+++ b/examples/logging-samples/openai-responses/pyproject.toml
@@ -0,0 +1,11 @@
+[project]
+name = "openai-responses"
+version = "0.1.0"
+description = "Add your description here"
+readme = "README.md"
+requires-python = ">=3.12"
+dependencies = [
+ "galileo>=1.42.0",
+ "openai>=2.15.0",
+ "packaging>=26.0",
+]
diff --git a/examples/logging-samples/openai-responses/requirements.txt b/examples/logging-samples/openai-responses/requirements.txt
new file mode 100644
index 00000000..9a39dcec
--- /dev/null
+++ b/examples/logging-samples/openai-responses/requirements.txt
@@ -0,0 +1,83 @@
+# This file was autogenerated by uv via the following command:
+# uv pip compile pyproject.toml -o requirements.txt
+annotated-types==0.7.0
+ # via pydantic
+anyio==4.12.1
+ # via
+ # httpx
+ # openai
+attrs==25.4.0
+ # via galileo
+backoff==2.2.1
+ # via galileo
+certifi==2026.1.4
+ # via
+ # httpcore
+ # httpx
+distro==1.9.0
+ # via openai
+galileo==1.42.0
+ # via openai-responses (pyproject.toml)
+galileo-core==3.84.0
+ # via galileo
+h11==0.16.0
+ # via httpcore
+httpcore==1.0.9
+ # via httpx
+httpx==0.28.1
+ # via
+ # galileo-core
+ # openai
+idna==3.11
+ # via
+ # anyio
+ # httpx
+jiter==0.12.0
+ # via openai
+openai==2.15.0
+ # via openai-responses (pyproject.toml)
+packaging==26.0
+ # via openai-responses (pyproject.toml)
+pydantic==2.12.5
+ # via
+ # galileo
+ # galileo-core
+ # openai
+ # pydantic-partial
+ # pydantic-settings
+pydantic-core==2.41.5
+ # via pydantic
+pydantic-partial==0.10.1
+ # via galileo-core
+pydantic-settings==2.12.0
+ # via galileo-core
+pyjwt==2.10.1
+ # via
+ # galileo
+ # galileo-core
+python-dateutil==2.9.0.post0
+ # via galileo
+python-dotenv==1.2.1
+ # via pydantic-settings
+six==1.17.0
+ # via python-dateutil
+sniffio==1.3.1
+ # via openai
+tqdm==4.67.1
+ # via openai
+typing-extensions==4.15.0
+ # via
+ # anyio
+ # galileo-core
+ # openai
+ # pydantic
+ # pydantic-core
+ # typing-inspection
+typing-inspection==0.4.2
+ # via
+ # pydantic
+ # pydantic-settings
+uvloop==0.21.0
+ # via galileo-core
+wrapt==1.17.3
+ # via galileo
diff --git a/examples/rag/cli-rag-demo/.env.example b/examples/rag/cli-rag-demo/.env.example
new file mode 100644
index 00000000..89176901
--- /dev/null
+++ b/examples/rag/cli-rag-demo/.env.example
@@ -0,0 +1,11 @@
+# Galileo Environment Variables
+GALILEO_API_KEY=your-galileo-api-key # Your Galileo API key.
+GALILEO_PROJECT=your-galileo-project-name # Your Galileo project name.
+GALILEO_LOG_STREAM=your-galileo-log-stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# GALILEO_CONSOLE_URL=your-galileo-console-url # Optional if you are using a hosted version of Galileo
+
+OPENAI_API_KEY=your-openai-api-key
+OPENAI_ORGANIZATION=your-openai-organization
+
diff --git a/examples/rag/cli-rag-demo/.gitignore b/examples/rag/cli-rag-demo/.gitignore
new file mode 100644
index 00000000..0a197900
--- /dev/null
+++ b/examples/rag/cli-rag-demo/.gitignore
@@ -0,0 +1,174 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# UV
+# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+#uv.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
+.pdm.toml
+.pdm-python
+.pdm-build/
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# PyCharm
+# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+# and can be added to the global gitignore or merged into this file. For a more nuclear
+# option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
+
+# Ruff stuff:
+.ruff_cache/
+
+# PyPI configuration file
+.pypirc
diff --git a/examples/rag/cli-rag-demo/README.md b/examples/rag/cli-rag-demo/README.md
new file mode 100644
index 00000000..ce36f26f
--- /dev/null
+++ b/examples/rag/cli-rag-demo/README.md
@@ -0,0 +1,78 @@
+# Terminal-based RAG Demo
+
+This is a terminal-based Retrieval-Augmented Generation (RAG) demo that uses the Splunk AO SDK for observability.
+
+## Features
+
+- Interactive terminal UI with rich text formatting
+- Simulated document retrieval with the `@log(span_type="retriever")` decorator for Splunk AO observability
+- OpenAI GPT-4o integration for answering questions
+
+## Prerequisites
+
+- Python 3.8+
+- OpenAI API key
+- Splunk AO API key (optional, for observability)
+
+## Installation
+
+1. Create a virtual environment:
+
+```bash
+python -m venv venv
+source venv/bin/activate # On Windows use `venv\Scripts\activate`
+```
+
+2. Install dependencies:
+
+```bash
+pip install -r requirements.txt
+```
+
+3. Set up environment variables by creating a `.env` file:
+
+```
+# Splunk AO Environment Variables
+SPLUNK_AO_API_KEY=your-splunk-ao-api-key # Your Splunk AO API key.
+SPLUNK_AO_PROJECT=your-splunk-ao-project-name # Your Splunk AO project name.
+SPLUNK_AO_LOG_STREAM=your-splunk-ao-log-stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# SPLUNK_AO_CONSOLE_URL=your-splunk-ao-console-url # Optional if you are using a hosted version of Splunk AO
+
+OPENAI_API_KEY=your-openai-api-key
+```
+
+## Usage
+
+Run the application:
+
+```bash
+python app.py
+```
+
+The application will:
+1. Prompt you to enter a question
+2. Retrieve relevant documents (simulated in this demo)
+3. Generate an answer using OpenAI's GPT-4o
+4. Display the answer
+5. Ask if you want to continue with another question
+
+To exit the application, type `exit`, `quit`, or `q` when prompted for a question, or press `Ctrl+C` at any time.
+
+## Understanding the Splunk AO Integration
+
+This demo uses the Splunk AO SDK for observability:
+
+- The `@log(span_type="retriever")` decorator is applied to the `retrieve_documents` function
+- This allows Splunk AO to track and analyze the retrieval process
+- The `span_type="retriever"` parameter specifically identifies this as a retrieval operation in the observability pipeline
+
+When Splunk AO logging is enabled (by setting the appropriate environment variables), you can view detailed metrics and traces in the Splunk AO console.
+
+## Customization
+
+To implement a real retrieval system:
+1. Replace the simulated document list in `retrieve_documents()` with actual vector database queries
+2. Keep the `@log(span_type="retriever")` decorator to maintain observability
+3. Adjust the prompt in the `rag()` function as needed for your specific use case
\ No newline at end of file
diff --git a/examples/rag/cli-rag-demo/app.py b/examples/rag/cli-rag-demo/app.py
new file mode 100644
index 00000000..8217279d
--- /dev/null
+++ b/examples/rag/cli-rag-demo/app.py
@@ -0,0 +1,157 @@
+import os
+from dotenv import load_dotenv
+from splunk_ao import openai, log, SplunkAOLogger
+from rich.console import Console
+from rich.panel import Panel
+from rich.markdown import Markdown
+import questionary
+import sys
+
+load_dotenv()
+
+# Initialize console for rich output
+console = Console()
+
+# Check if Splunk AO logging is enabled
+logging_enabled = os.environ.get("SPLUNK_AO_API_KEY") is not None
+
+logger = SplunkAOLogger(
+ project="rag-test",
+ log_stream="dev",
+)
+
+# Initialize OpenAI client directly
+client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
+
+
+@log(span_type="retriever")
+def retrieve_documents(query: str):
+ # TODO: Replace with actual RAG retrieval
+ documents = [
+ {
+ "id": "doc1",
+ "text": (
+ "Splunk AO is an observability platform for LLM applications. It helps developers monitor, debug, and improve their AI systems by tracking inputs, outputs, and performance metrics."
+ ),
+ "metadata": {"source": "galileo_docs", "category": "product_overview"},
+ },
+ {
+ "id": "doc2",
+ "text": (
+ "RAG (Retrieval-Augmented Generation) is a technique that enhances LLM responses by retrieving relevant information from external knowledge sources before generating an answer."
+ ),
+ "metadata": {"source": "ai_techniques", "category": "methodology"},
+ },
+ {
+ "id": "doc3",
+ "text": (
+ "Common RAG challenges include hallucinations, retrieval quality issues, and context window limitations. Proper evaluation metrics include relevance, faithfulness, and answer correctness."
+ ),
+ "metadata": {"source": "ai_techniques", "category": "challenges"},
+ },
+ {
+ "id": "doc4",
+ "text": (
+ "Vector databases like Pinecone, Weaviate, and Chroma are optimized for storing embeddings and performing similarity searches, making them ideal for RAG applications."
+ ),
+ "metadata": {"source": "tech_stack", "category": "databases"},
+ },
+ {
+ "id": "doc5",
+ "text": (
+ "Prompt engineering is crucial for RAG systems. Well-crafted prompts should instruct the model to use retrieved context, avoid making up information, and cite sources when possible."
+ ),
+ "metadata": {"source": "best_practices", "category": "prompting"},
+ },
+ ]
+ return documents
+
+
+def rag(query: str):
+ documents = retrieve_documents(query)
+
+ # Format documents for better readability in the prompt
+ formatted_docs = ""
+ for i, doc in enumerate(documents):
+ formatted_docs += f"Document {i+1} (Source: {doc['metadata']['source']}):\n{doc['text']}\n\n"
+
+ prompt = f"""
+ Answer the following question based on the context provided. If the answer is not in the context, say you don't know.
+
+ Question: {query}
+
+ Context:
+ {formatted_docs}
+ """
+
+ try:
+ console.print("[bold blue]Generating answer...[/bold blue]")
+ response = client.chat.completions.create(
+ model="gpt-4o",
+ messages=[
+ {
+ "role": "system",
+ "content": "You are a helpful assistant that answers questions based only on the provided context.",
+ },
+ {"role": "user", "content": prompt},
+ ],
+ )
+ return response.choices[0].message.content.strip()
+ except Exception as e:
+ return f"Error generating response: {str(e)}"
+
+
+def main():
+ console.print(
+ Panel.fit(
+ "[bold]RAG Demo[/bold]\nThis demo uses a simulated RAG system to answer your questions.",
+ title="Splunk AO RAG Terminal Demo",
+ border_style="blue",
+ )
+ )
+
+ # Check environment setup
+ if logging_enabled:
+ console.print("[green]✅ Splunk AO logging is enabled[/green]")
+ else:
+ console.print("[yellow]⚠️ Splunk AO logging is disabled[/yellow]")
+
+ api_key = os.environ.get("OPENAI_API_KEY")
+ if api_key:
+ console.print("[green]✅ OpenAI API Key is set[/green]")
+ else:
+ console.print("[red]❌ OpenAI API Key is missing[/red]")
+ sys.exit(1)
+
+ # Main interaction loop
+ while True:
+ # Get user query
+ query = questionary.text(
+ "Enter your question about Splunk AO, RAG, or AI techniques:",
+ validate=lambda text: len(text) > 0,
+ ).ask()
+
+ if query.lower() in ["exit", "quit", "q"]:
+ break
+
+ try:
+ result = rag(query)
+
+ console.print("\n[bold green]Answer:[/bold green]")
+ console.print(Panel(Markdown(result), border_style="green"))
+
+ # Ask if user wants to continue
+ continue_session = questionary.confirm("Do you want to ask another question?", default=True).ask()
+
+ if not continue_session:
+ break
+
+ except Exception as e:
+ console.print(f"[bold red]Error:[/bold red] {str(e)}")
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ console.print("\n[bold]Exiting RAG Demo. Goodbye![/bold]")
diff --git a/examples/rag/cli-rag-demo/challenges/chunk-utilization.py b/examples/rag/cli-rag-demo/challenges/chunk-utilization.py
new file mode 100644
index 00000000..c915d092
--- /dev/null
+++ b/examples/rag/cli-rag-demo/challenges/chunk-utilization.py
@@ -0,0 +1,468 @@
+import os
+from dotenv import load_dotenv
+from splunk_ao import openai, SplunkAOLogger
+from rich.console import Console
+from rich.panel import Panel
+from rich.markdown import Markdown
+import questionary
+import sys
+import faiss
+from sentence_transformers import SentenceTransformer
+import random
+from time import perf_counter_ns
+
+load_dotenv()
+
+# Initialize console for rich output
+console = Console()
+
+# Check if Splunk AO logging is enabled
+logging_enabled = os.environ.get("SPLUNK_AO_API_KEY") is not None
+
+
+# Initialize Splunk AO logger
+logger = SplunkAOLogger(
+ project="chunk-utilization",
+ log_stream="dev",
+)
+
+# Initialize OpenAI client
+client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
+
+# Initialize the sentence transformer model
+encoder = SentenceTransformer("all-MiniLM-L6-v2")
+
+
+class DocumentStore:
+ def __init__(self):
+ self.documents = []
+ self.document_embeddings = None
+ self.index = None
+ self._initialize_documents()
+ self._build_index()
+
+ def _initialize_documents(self):
+ # Solar System documents
+ self.documents.extend(
+ [
+ {
+ "id": "solar_system_1",
+ "text": (
+ "The Solar System is the gravitationally bound system of the Sun and the objects that orbit it. It formed 4.6 billion years ago from the gravitational collapse of a giant interstellar molecular cloud. The vast majority of the system's mass is in the Sun, with most of the remaining mass contained in the planet Jupiter."
+ ),
+ "metadata": {
+ "source": "astronomy_encyclopedia",
+ "category": "planetary systems",
+ "relevance": "high",
+ },
+ },
+ {
+ "id": "solar_system_2",
+ "text": (
+ "The four inner system planets—Mercury, Venus, Earth and Mars—are terrestrial planets, being composed primarily of rock and metal. The four giant planets of the outer system are substantially larger and more massive than the terrestrials. The two largest, Jupiter and Saturn, are gas giants, being composed mainly of hydrogen and helium; the next two, Uranus and Neptune, are ice giants."
+ ),
+ "metadata": {
+ "source": "astronomy_textbook",
+ "category": "planetary systems",
+ "relevance": "high",
+ },
+ },
+ {
+ "id": "solar_system_3",
+ "text": (
+ "The history of Solar System observation dates back to ancient times when astronomers first noticed that certain lights moved across the sky in a different way than the fixed stars. Ancient Greeks called these lights 'planetai' or wanderers, giving rise to our modern term 'planet'."
+ ),
+ "metadata": {
+ "source": "astronomy_history",
+ "category": "astronomy history",
+ "relevance": "low",
+ },
+ },
+ ]
+ )
+
+ # Photosynthesis documents
+ self.documents.extend(
+ [
+ {
+ "id": "photosynthesis_1",
+ "text": (
+ "Photosynthesis is the process by which plants, algae, and certain bacteria convert light energy, typically from the Sun, into chemical energy in the form of glucose or other sugars. These organisms are called photoautotrophs since they can create their own food."
+ ),
+ "metadata": {
+ "source": "biology_textbook",
+ "category": "cellular processes",
+ "relevance": "high",
+ },
+ },
+ {
+ "id": "photosynthesis_2",
+ "text": (
+ "The light-dependent reactions of photosynthesis occur in the thylakoid membranes of chloroplasts. Here, light energy is captured by chlorophyll pigments and converted into chemical energy in the form of ATP and NADPH."
+ ),
+ "metadata": {
+ "source": "biochemistry_journal",
+ "category": "cellular processes",
+ "relevance": "high",
+ },
+ },
+ {
+ "id": "photosynthesis_3",
+ "text": (
+ "The evolution of photosynthesis occurred early in Earth's history, with the earliest photosynthetic organisms appearing between 3.4 and 2.9 billion years ago. This development dramatically changed Earth's atmosphere by introducing oxygen."
+ ),
+ "metadata": {
+ "source": "evolutionary_biology",
+ "category": "evolution",
+ "relevance": "low",
+ },
+ },
+ ]
+ )
+
+ # Add more topics similarly...
+ # (Blockchain, Renaissance, and Machine Learning documents would be added here)
+
+ def _build_index(self):
+ # Generate embeddings for all documents
+ texts = [doc["text"] for doc in self.documents]
+ self.document_embeddings = encoder.encode(texts)
+
+ # Build FAISS index
+ dimension = self.document_embeddings.shape[1]
+ self.index = faiss.IndexFlatL2(dimension)
+ self.index.add(self.document_embeddings.astype("float32"))
+
+ def search(self, query: str, k: int = 3, mixed_relevance: bool = False) -> list:
+ # Encode the query
+ query_vector = encoder.encode([query])[0].reshape(1, -1)
+
+ # Search the index
+ distances, indices = self.index.search(query_vector.astype("float32"), k)
+
+ # Get the retrieved documents
+ retrieved_docs = []
+ for idx in indices[0]:
+ doc = self.documents[idx]
+ retrieved_docs.append(
+ {
+ "content": doc["text"],
+ "metadata": {
+ "id": doc["id"],
+ "source": doc["metadata"]["source"],
+ "category": doc["metadata"]["category"],
+ "relevance": doc["metadata"]["relevance"],
+ },
+ }
+ )
+
+ if mixed_relevance:
+ # Replace some highly relevant documents with low relevance ones
+ low_relevance_docs = [doc for doc in self.documents if doc["metadata"]["relevance"] == "low"]
+ if low_relevance_docs:
+ num_to_replace = min(len(retrieved_docs) // 2, len(low_relevance_docs))
+ for i in range(num_to_replace):
+ low_rel_doc = random.choice(low_relevance_docs)
+ retrieved_docs[i] = {
+ "content": low_rel_doc["text"],
+ "metadata": {
+ "id": low_rel_doc["id"],
+ "source": low_rel_doc["metadata"]["source"],
+ "category": low_rel_doc["metadata"]["category"],
+ "relevance": low_rel_doc["metadata"]["relevance"],
+ },
+ }
+
+ return retrieved_docs
+
+
+# Initialize the document store
+doc_store = DocumentStore()
+
+
+def retrieve_verbose_documents(query: str, mixed_relevance: bool = False):
+ """
+ Retrieves documents using FAISS vector similarity search.
+ """
+ start_time = perf_counter_ns()
+ try:
+ documents = doc_store.search(query, k=3, mixed_relevance=mixed_relevance)
+ logger.add_retriever_span(input=query, output=documents, duration_ns=perf_counter_ns() - start_time)
+ return documents
+ except Exception as e:
+ logger.add_retriever_span(
+ input=query,
+ output=str(e),
+ duration_ns=perf_counter_ns() - start_time,
+ status_code=500,
+ )
+ raise e
+
+
+def rag_with_poor_utilization(query: str, mixed_relevance: bool = False):
+ """
+ RAG implementation that demonstrates poor chunk utilization.
+ """
+ start_time = perf_counter_ns()
+ try:
+ documents = retrieve_verbose_documents(query, mixed_relevance=mixed_relevance)
+
+ # Format documents for the prompt
+ formatted_docs = ""
+ for i, doc in enumerate(documents):
+ formatted_docs += f"Document {i+1} (Source: {doc['metadata']['source']}, Relevance: {doc['metadata']['relevance']}):\n{doc['content']}\n\n"
+
+ # Basic prompt
+ basic_prompt = f"""
+ Answer the following question based on the provided documents.
+
+ Question: {query}
+
+ Documents:
+ {formatted_docs}
+ """
+
+ console.print("[bold blue]Generating answer (with poor chunk utilization)...[/bold blue]")
+ response = client.chat.completions.create(
+ model="gpt-4",
+ messages=[
+ {"role": "system", "content": "You are a helpful assistant."},
+ {"role": "user", "content": basic_prompt},
+ ],
+ )
+ result = response.choices[0].message.content.strip()
+
+ logger.add_llm_span(
+ input=basic_prompt,
+ name="poor_chunk_utilization",
+ output=result,
+ model="gpt-4",
+ duration_ns=perf_counter_ns() - start_time,
+ )
+
+ logger.conclude(output=result)
+ logger.flush()
+
+ return result
+ except Exception as e:
+ error_msg = f"Error generating response: {str(e)}"
+ logger.add_llm_span(
+ input=query,
+ output=error_msg,
+ model="gpt-4",
+ duration_ns=perf_counter_ns() - start_time,
+ status_code=500,
+ )
+ return error_msg
+
+
+def rag_with_better_utilization(query: str, mixed_relevance: bool = False):
+ """
+ RAG implementation that demonstrates better chunk utilization.
+ """
+ start_time = perf_counter_ns()
+ try:
+ documents = retrieve_verbose_documents(query, mixed_relevance=mixed_relevance)
+
+ # Format documents for the prompt
+ formatted_docs = ""
+ for i, doc in enumerate(documents):
+ formatted_docs += f"Document {i+1} (Source: {doc['metadata']['source']}, Relevance: {doc['metadata']['relevance']}):\n{doc['content']}\n\n"
+
+ # Enhanced prompt
+ enhanced_prompt = f"""
+ Answer the following question based on the provided documents.
+
+ IMPORTANT INSTRUCTIONS:
+ 1. First, identify and extract the key facts and information from each document that are relevant to the question.
+ 2. Organize these key points in a structured way.
+ 3. Use these extracted points to formulate your complete answer.
+ 4. Make sure to utilize all relevant information from the documents.
+ 5. If the documents contain information that directly answers the question, be sure to include it.
+ 6. Pay attention to the relevance score of each document and prioritize information from highly relevant sources.
+
+ Question: {query}
+
+ Documents:
+ {formatted_docs}
+ """
+
+ console.print("[bold green]Generating answer (with improved chunk utilization)...[/bold green]")
+ response = client.chat.completions.create(
+ model="gpt-4",
+ messages=[
+ {
+ "role": "system",
+ "content": (
+ "You are a helpful assistant that thoroughly extracts and utilizes all relevant information from provided documents. Your goal is to ensure no important details are missed while prioritizing information from highly relevant sources."
+ ),
+ },
+ {"role": "user", "content": enhanced_prompt},
+ ],
+ )
+ result = response.choices[0].message.content.strip()
+
+ logger.add_llm_span(
+ input=enhanced_prompt,
+ name="better_chunk_utilization",
+ output=result,
+ model="gpt-4",
+ duration_ns=perf_counter_ns() - start_time,
+ )
+
+ logger.conclude(output=result)
+ logger.flush()
+
+ return result
+ except Exception as e:
+ error_msg = f"Error generating response: {str(e)}"
+ logger.add_llm_span(
+ input=query,
+ output=error_msg,
+ model="gpt-4",
+ duration_ns=perf_counter_ns() - start_time,
+ status_code=500,
+ )
+ return error_msg
+
+
+def main():
+ start_time = perf_counter_ns()
+ try:
+ # Start trace with a meaningful name, actual input will be added when we get the query
+ logger.start_trace(
+ name="Chunk Utilization Demo",
+ input=None, # Will be set when we get the actual query
+ )
+
+ console.print(
+ Panel.fit(
+ "[bold]Chunk Utilization RAG Demo[/bold]\nThis demo shows how RAG systems can struggle with verbose chunks and how to improve information extraction.",
+ title="Splunk AO RAG Challenge: Chunk Utilization",
+ border_style="blue",
+ )
+ )
+
+ # Check environment setup
+ if logging_enabled:
+ console.print("[green]✅ Splunk AO logging is enabled[/green]")
+ else:
+ console.print("[yellow]⚠️ Splunk AO logging is disabled[/yellow]")
+
+ api_key = os.environ.get("OPENAI_API_KEY")
+ if api_key:
+ console.print("[green]✅ OpenAI API Key is set[/green]")
+ else:
+ console.print("[red]❌ OpenAI API Key is missing[/red]")
+ sys.exit(1)
+
+ # Suggested queries
+ suggested_queries = [
+ "What are the planets in our solar system?",
+ "Explain the process of photosynthesis simply.",
+ "How does blockchain technology work?",
+ "What were the key characteristics of the Renaissance period?",
+ "What are the different types of machine learning?",
+ ]
+
+ console.print("\n[bold yellow]Suggested queries (these will demonstrate the chunk utilization problem):[/bold yellow]")
+ for i, q in enumerate(suggested_queries):
+ console.print(f"[yellow]{i+1}. {q}[/yellow]")
+
+ # Choose workflow
+ workflow = questionary.select(
+ "Choose which workflow to run:",
+ choices=[
+ "Poor Chunk Utilization (Bad State)",
+ "Improved Chunk Utilization (Good State)",
+ "Exit",
+ ],
+ ).ask()
+
+ if workflow == "Exit":
+ return
+
+ # Main interaction loop
+ while True:
+ # Get user query
+ query = questionary.text(
+ "Enter your question (or type a number 1-5 to use a suggested query):",
+ validate=lambda text: len(text) > 0,
+ ).ask()
+
+ if query.lower() in ["exit", "quit", "q"]:
+ break
+
+ # Check if user entered a number for suggested queries
+ if query.isdigit() and 1 <= int(query) <= len(suggested_queries):
+ query = suggested_queries[int(query) - 1]
+ console.print(f"[bold]Using query:[/bold] {query}")
+
+ # Update trace with actual query input
+ logger.conclude(output=None) # End previous trace if any
+ logger.start_trace(name="Chunk Utilization Demo", input=query)
+
+ # Ask about mixed relevance
+ mixed_relevance = questionary.confirm(
+ "Would you like to include mixed relevance results (some less relevant documents)?",
+ default=False,
+ ).ask()
+
+ try:
+ # Display the retrieved context - using direct search without tracing
+ display_documents = doc_store.search(query, k=3, mixed_relevance=mixed_relevance)
+ console.print("\n[bold cyan]Retrieved Context (Verbose Chunks):[/bold cyan]")
+ for i, doc in enumerate(display_documents):
+ relevance_color = "green" if doc["metadata"]["relevance"] == "high" else "yellow"
+ console.print(
+ Panel(
+ f"[bold]Source:[/bold] {doc['metadata']['source']}\n[bold]Relevance:[/bold] [{relevance_color}]{doc['metadata']['relevance']}[/{relevance_color}]\n\n[dim]{doc['content']}[/dim]",
+ title=f"Document {i+1} ({len(doc['content'])} characters)",
+ border_style="cyan",
+ )
+ )
+
+ # Generate and display response based on chosen workflow
+ if workflow == "Poor Chunk Utilization (Bad State)":
+ result = rag_with_poor_utilization(query, mixed_relevance=mixed_relevance)
+ console.print("\n[bold red]Response with Poor Chunk Utilization:[/bold red]")
+ console.print(Panel(Markdown(result), border_style="red"))
+ else: # Improved Chunk Utilization
+ result = rag_with_better_utilization(query, mixed_relevance=mixed_relevance)
+ console.print("\n[bold green]Response with Improved Chunk Utilization:[/bold green]")
+ console.print(Panel(Markdown(result), border_style="green"))
+
+ # Conclude this query's trace
+ logger.conclude(
+ output=result, # The result from either poor or better utilization
+ duration_ns=perf_counter_ns() - start_time,
+ )
+
+ # Ask if user wants to continue
+ continue_session = questionary.confirm("Do you want to ask another question?", default=True).ask()
+
+ if not continue_session:
+ break
+
+ except Exception as e:
+ console.print(f"[bold red]Error:[/bold red] {str(e)}")
+
+ # Final conclusion of the demo
+ logger.conclude(
+ output="Demo completed successfully",
+ duration_ns=perf_counter_ns() - start_time,
+ )
+ except Exception as e:
+ logger.conclude(
+ output=f"Demo failed: {str(e)}",
+ duration_ns=perf_counter_ns() - start_time,
+ status_code=500,
+ )
+ raise e
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ console.print("\n[bold]Exiting Chunk Utilization RAG Demo. Goodbye![/bold]")
diff --git a/examples/rag/cli-rag-demo/challenges/chunk-utilizations-basic.py b/examples/rag/cli-rag-demo/challenges/chunk-utilizations-basic.py
new file mode 100644
index 00000000..0230460b
--- /dev/null
+++ b/examples/rag/cli-rag-demo/challenges/chunk-utilizations-basic.py
@@ -0,0 +1,76 @@
+import os
+from pathlib import Path
+from dotenv import load_dotenv
+from splunk_ao.openai import openai
+from rich.console import Console
+from document_store import DocumentStore, format_documents
+from splunk_ao import splunk_ao_context
+
+# Find the .env file in the parent directory
+current_dir = Path(__file__).resolve().parent
+root_dir = current_dir.parent
+dotenv_path = root_dir / ".env"
+
+# Load the .env file
+load_dotenv(dotenv_path)
+
+# Debug: Print environment variables
+print("Environment variables:")
+print("SPLUNK_AO_PROJECT:", os.getenv("SPLUNK_AO_PROJECT"))
+print("SPLUNK_AO_API_KEY:", os.getenv("SPLUNK_AO_API_KEY"))
+print("SPLUNK_AO_BASE_URL:", os.getenv("SPLUNK_AO_BASE_URL"))
+
+EXAMPLE_QUESTION = "What are the fundamental concepts and operations in arithmetic, and how are they used in mathematics?"
+
+
+class Prompts:
+ BASIC = """Answer the following question based on the provided documents.
+
+Question: {query}
+
+Documents:
+{documents}"""
+
+
+def query(question: str):
+
+ # Debug: Print logger configuration
+ print("\nLogger configuration:")
+ print("Project:", os.getenv("SPLUNK_AO_PROJECT", "chunk-utilization"))
+ print("Log stream: basic_approach")
+
+ client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY"), base_url=os.getenv("OPENAI_BASE_URL"))
+
+ # Basic approach: more results but no reranking
+ docs = DocumentStore(num_docs=500, k=5, use_reranking=False).search(question)
+
+ prompt = Prompts.BASIC.format(query=question, documents=format_documents(docs))
+
+ response = client.chat.completions.create(
+ model="gpt-4",
+ messages=[
+ {
+ "role": "system",
+ "content": "You are a helpful assistant. Explain mathematical concepts in a straightforward way.",
+ },
+ {"role": "user", "content": prompt},
+ ],
+ )
+
+ return response.choices[0].message.content.strip()
+
+
+def main():
+ with splunk_ao_context(
+ project=os.getenv("SPLUNK_AO_PROJECT", "chunk-utilization"),
+ log_stream="basic_approach",
+ ):
+ console = Console()
+ console.print("\nBasic Chunk Utilization Demo")
+ console.print("\nUsing example question:", EXAMPLE_QUESTION)
+ console.print("\nResponse:")
+ console.print(query(EXAMPLE_QUESTION))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/rag/cli-rag-demo/challenges/chunk-utilizations-enhanced.py b/examples/rag/cli-rag-demo/challenges/chunk-utilizations-enhanced.py
new file mode 100644
index 00000000..6f0b7587
--- /dev/null
+++ b/examples/rag/cli-rag-demo/challenges/chunk-utilizations-enhanced.py
@@ -0,0 +1,81 @@
+import os
+from pathlib import Path
+from dotenv import load_dotenv
+from splunk_ao.openai import openai
+from rich.console import Console
+from document_store import DocumentStore, format_documents
+from splunk_ao import splunk_ao_context
+
+# Find the .env file in the parent directory
+current_dir = Path(__file__).resolve().parent
+root_dir = current_dir.parent
+dotenv_path = root_dir / ".env"
+
+# Load the .env file
+load_dotenv(dotenv_path)
+
+EXAMPLE_QUESTION = "What are the fundamental concepts and operations in arithmetic, and how are they used in mathematics?"
+
+SYSTEM_PROMPT = """You are a knowledgeable mathematics educator tasked with providing comprehensive answers by analyzing and synthesizing information from multiple provided documents.
+
+IMPORTANT INSTRUCTIONS:
+1. Cross-reference information between documents - identify and connect complementary or contrasting information.
+2. For each concept you discuss, cite the specific documents that support your explanation (e.g., "As shown in Document 1 and expanded in Document 3...").
+3. When multiple documents contain related information, explicitly connect their content (e.g., "While Document 2 introduces basic addition, Document 4 builds on this by...").
+4. If documents present different aspects or perspectives of a concept, synthesize them into a cohesive explanation.
+5. Pay attention to the relevance scores of documents - higher scores often indicate more pertinent information.
+6. Ensure you consider and utilize information from all relevant documents in your response.
+7. Structure your response to build from foundational concepts to more advanced applications, citing the relevant documents throughout.
+
+Your response should demonstrate thorough analysis and integration of information from all relevant documents, making clear how different sources contributed to the complete answer. Explain mathematical concepts clearly, connect related ideas, and highlight fundamental principles while maintaining accuracy."""
+
+
+class Prompts:
+ ENHANCED = """Question: {query}
+
+Documents:
+{documents}"""
+
+
+def format_documents_enhanced(documents: list) -> str:
+ return "\n\n".join(
+ f"Document {i+1} (Source: {doc['metadata']['source']}, Relevance: {doc['metadata']['relevance']}, "
+ f"Score: {doc['metadata'].get('combined_score', doc['metadata'].get('score', 'N/A')):.3f}):\n{doc['text']}"
+ for i, doc in enumerate(documents)
+ )
+
+
+def query(question: str):
+ client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY"), base_url=os.getenv("OPENAI_BASE_URL"))
+
+ # Enhanced approach: use reranking with more initial documents
+ docs = DocumentStore(num_docs=500, k=5, use_reranking=True, reranking_threshold=0.6).search(question)
+
+ prompt = Prompts.ENHANCED.format(query=question, documents=format_documents(docs))
+
+ response = client.chat.completions.create(
+ model="gpt-4",
+ messages=[
+ {"role": "system", "content": SYSTEM_PROMPT},
+ {"role": "user", "content": prompt},
+ ],
+ )
+
+ return response.choices[0].message.content.strip()
+
+
+def main():
+ with splunk_ao_context(
+ project=os.getenv("SPLUNK_AO_PROJECT", "chunk-utilization"),
+ log_stream="enhanced_approach",
+ ):
+ console = Console()
+ console.print("\nEnhanced Chunk Utilization Demo")
+ console.print("\nUsing example question:", EXAMPLE_QUESTION)
+
+ console.print("\nResponse:")
+ console.print(query(EXAMPLE_QUESTION))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/rag/cli-rag-demo/challenges/document_store.py b/examples/rag/cli-rag-demo/challenges/document_store.py
new file mode 100644
index 00000000..1229cef8
--- /dev/null
+++ b/examples/rag/cli-rag-demo/challenges/document_store.py
@@ -0,0 +1,273 @@
+from sentence_transformers import SentenceTransformer, CrossEncoder
+import faiss
+from datasets import load_dataset
+import numpy as np
+from splunk_ao import log
+from typing import List, Dict, Optional
+import re
+from pathlib import Path
+
+
+class DocumentStore:
+ def __init__(
+ self,
+ source: str = "wikipedia", # "wikipedia" or "custom"
+ custom_documents_path: Optional[str] = None,
+ num_docs: int = 1000,
+ k: int = 3,
+ chunk_size: int = 512,
+ reranking_threshold: float = 0.6,
+ use_reranking: bool = False,
+ reranking_multiplier: int = 4,
+ wikipedia_query: Optional[str] = None,
+ ):
+ self.source = source
+ self.documents = []
+ self.k = k
+ self.use_reranking = use_reranking
+ self.reranking_threshold = reranking_threshold
+ self.reranking_multiplier = reranking_multiplier
+
+ # Initialize encoder and cross-encoder
+ self.encoder = SentenceTransformer("all-MiniLM-L6-v2")
+ if use_reranking:
+ print("Loading cross-encoder for reranking...")
+ self.cross_encoder = CrossEncoder("cross-encoder/ms-marco-MiniLM-L-6-v2")
+
+ # Load documents based on source
+ if source == "wikipedia":
+ try:
+ # Load Wikipedia dataset with configurable parameters
+ print(f"Loading {num_docs} Wikipedia articles...")
+ dataset = load_dataset(
+ "wikipedia",
+ "20220301.simple",
+ split=f"train[:{num_docs}]",
+ trust_remote_code=True,
+ )
+
+ if wikipedia_query:
+ # Use the query to filter relevant articles
+ query_terms = wikipedia_query.lower().split()
+ filtered_articles = []
+
+ for article in dataset:
+ article_text = article["text"].lower()
+ # Check if any of the query terms appear in the article
+ if any(term in article_text for term in query_terms):
+ filtered_articles.append(article)
+
+ if not filtered_articles:
+ print(f"No Wikipedia articles found for query: {wikipedia_query}")
+ if custom_documents_path:
+ print("Falling back to custom documents...")
+ self._load_custom_documents(custom_documents_path, chunk_size)
+ else:
+ raise ValueError("No documents found and no custom documents path provided")
+ else:
+ dataset = filtered_articles[:num_docs]
+ self._process_wikipedia_documents(dataset, chunk_size)
+
+ else:
+ self._process_wikipedia_documents(dataset, chunk_size)
+
+ except Exception as e:
+ print(f"Error loading Wikipedia articles: {e}")
+ if custom_documents_path:
+ print("Falling back to custom documents...")
+ self._load_custom_documents(custom_documents_path, chunk_size)
+ else:
+ raise
+
+ elif source == "custom":
+ if not custom_documents_path:
+ raise ValueError("custom_documents_path must be provided when source is 'custom'")
+ self._load_custom_documents(custom_documents_path, chunk_size)
+
+ else:
+ raise ValueError(f"Unsupported source: {source}. Use 'wikipedia' or 'custom'")
+
+ if not self.documents:
+ raise ValueError("No documents were successfully loaded")
+
+ print(f"Processed {len(self.documents)} chunks from {len(set(doc['metadata']['source'] for doc in self.documents))} documents")
+ print(f"Average chunk length: {sum(doc['metadata']['length'] for doc in self.documents) / len(self.documents):.0f} characters")
+
+ self._build_index()
+
+ def _process_wikipedia_documents(self, dataset, chunk_size: int):
+ """Process Wikipedia documents into chunks"""
+ for item in dataset:
+ # Skip empty or very short articles
+ if not item["text"] or len(item["text"]) < 100:
+ continue
+
+ # Split text into chunks
+ chunks = self._chunk_text(item["text"], chunk_size)
+
+ for i, chunk in enumerate(chunks):
+ self.documents.append(
+ {
+ "text": chunk,
+ "metadata": {
+ "source": item["title"],
+ "chunk_id": i,
+ "total_chunks": len(chunks),
+ "relevance": "medium",
+ "length": len(chunk),
+ "url": item.get("url", ""),
+ "original_length": len(item["text"]),
+ },
+ }
+ )
+
+ def _load_custom_documents(self, documents_path: str, chunk_size: int):
+ """Helper method to load custom documents from a file"""
+ documents_path = Path(documents_path)
+ if not documents_path.exists():
+ raise FileNotFoundError(f"Custom documents file not found: {documents_path}")
+
+ with open(documents_path, "r") as f:
+ text = f.read()
+
+ # Split into paragraphs and process as documents
+ paragraphs = [p.strip() for p in text.split("\n\n") if p.strip()]
+
+ # Process and store documents with chunking
+ for i, paragraph in enumerate(paragraphs):
+ # Skip empty or very short paragraphs
+ if not paragraph or len(paragraph) < 50:
+ continue
+
+ # Split text into chunks
+ chunks = self._chunk_text(paragraph, chunk_size)
+
+ for j, chunk in enumerate(chunks):
+ self.documents.append(
+ {
+ "text": chunk,
+ "metadata": {
+ "source": f"Document {i+1}",
+ "chunk_id": j,
+ "total_chunks": len(chunks),
+ "relevance": "medium",
+ "length": len(chunk),
+ "url": "",
+ "original_length": len(paragraph),
+ },
+ }
+ )
+
+ def _chunk_text(self, text: str, chunk_size: int) -> List[str]:
+ """
+ Split text into chunks of approximately chunk_size tokens.
+ Uses sentence boundaries where possible to maintain context.
+ """
+ # First split into sentences
+ sentences = re.split(r"(?<=[.!?])\s+", text)
+
+ chunks = []
+ current_chunk = []
+ current_length = 0
+
+ for sentence in sentences:
+ # Rough estimation of tokens (words + punctuation)
+ sentence_length = len(sentence.split())
+
+ if current_length + sentence_length > chunk_size and current_chunk:
+ # If adding this sentence would exceed chunk_size, save current chunk
+ chunks.append(" ".join(current_chunk))
+ current_chunk = [sentence]
+ current_length = sentence_length
+ else:
+ # Add sentence to current chunk
+ current_chunk.append(sentence)
+ current_length += sentence_length
+
+ # Add the last chunk if it exists
+ if current_chunk:
+ chunks.append(" ".join(current_chunk))
+
+ return chunks
+
+ def _build_index(self):
+ print("Building FAISS index...")
+ texts = [doc["text"] for doc in self.documents]
+ self.embeddings = self.encoder.encode(texts)
+ dimension = self.embeddings.shape[1]
+
+ # Use L2 normalization for better similarity search
+ faiss.normalize_L2(self.embeddings)
+
+ # Create an index that's optimized for cosine similarity
+ self.index = faiss.IndexFlatIP(dimension) # Inner product is equivalent to cosine similarity for normalized vectors
+ self.index.add(self.embeddings.astype("float32"))
+ print("Index built successfully")
+
+ def _rerank_documents(self, docs: List[Dict], query: str) -> List[Dict]:
+ """
+ Rerank documents using a cross-encoder model, which provides more accurate
+ relevance scoring by considering query and document together.
+ """
+ # Create pairs of (query, document) for cross-encoder scoring
+ pairs = [(query, doc["text"]) for doc in docs]
+
+ # Get cross-encoder scores
+ cross_scores = self.cross_encoder.predict(pairs)
+
+ # Normalize scores to 0-1 range for consistency
+ min_score = min(cross_scores)
+ max_score = max(cross_scores)
+ score_range = max_score - min_score
+
+ reranked_docs = []
+ for doc, score in zip(docs, cross_scores):
+ # Normalize score to 0-1 range
+ normalized_score = (score - min_score) / score_range if score_range > 0 else 0.5
+
+ if normalized_score >= self.reranking_threshold:
+ doc["metadata"]["combined_score"] = normalized_score
+ doc["metadata"]["relevance"] = "high" if normalized_score > 0.8 else "medium" if normalized_score > 0.6 else "low"
+ reranked_docs.append(doc)
+
+ # Sort by combined score
+ reranked_docs.sort(key=lambda x: x["metadata"]["combined_score"], reverse=True)
+ return reranked_docs[: self.k]
+
+ @log(span_type="retriever")
+ def search(self, query: str) -> list:
+ # Encode and normalize the query
+ query_vector = self.encoder.encode([query])[0]
+ query_vector = query_vector / np.linalg.norm(query_vector)
+ query_vector = query_vector.reshape(1, -1)
+
+ # Get more initial results if using reranking
+ initial_k = self.k * self.reranking_multiplier if self.use_reranking else self.k
+ scores, indices = self.index.search(query_vector.astype("float32"), initial_k)
+
+ # Process results
+ results = []
+ for score, idx in zip(scores[0], indices[0]):
+ doc = self.documents[idx].copy()
+ doc["metadata"] = doc["metadata"].copy()
+ doc["metadata"]["score"] = float(score)
+ results.append(doc)
+
+ # Apply reranking if enabled
+ if self.use_reranking:
+ print(f"Reranking top {initial_k} results...")
+ return self._rerank_documents(results, query)
+ else:
+ # For basic search, just update relevance based on score
+ for doc in results:
+ doc["metadata"]["relevance"] = "high" if doc["metadata"]["score"] > 0.8 else "medium" if doc["metadata"]["score"] > 0.6 else "low"
+ return results[: self.k]
+
+
+def format_documents(documents: list) -> str:
+ return "\n\n".join(
+ f"Document {i+1} (Source: {doc['metadata']['source']}, Chunk {doc['metadata']['chunk_id'] + 1}/{doc['metadata']['total_chunks']}, "
+ f"Relevance: {doc['metadata']['relevance']}, "
+ f"Score: {doc['metadata'].get('combined_score', doc['metadata'].get('score', 'N/A')):.3f}):\n{doc['text']}"
+ for i, doc in enumerate(documents)
+ )
diff --git a/examples/rag/cli-rag-demo/challenges/document_store_basic.py b/examples/rag/cli-rag-demo/challenges/document_store_basic.py
new file mode 100644
index 00000000..74cb2dc4
--- /dev/null
+++ b/examples/rag/cli-rag-demo/challenges/document_store_basic.py
@@ -0,0 +1,118 @@
+from sentence_transformers import SentenceTransformer
+import faiss
+from typing import Optional
+import re
+from pathlib import Path
+
+
+class DocumentStoreBasic:
+ def __init__(
+ self,
+ source: str = "custom",
+ custom_documents_path: Optional[str] = None,
+ num_docs: int = 1, # Only return 1 document
+ chunk_size: int = 1000, # Larger chunks, less precise
+ ):
+ self.source = source
+ self.documents = []
+ self.num_docs = num_docs
+
+ # Use a simpler embedding model
+ self.encoder = SentenceTransformer("all-MiniLM-L6-v2")
+
+ # Load documents based on source
+ if source == "custom":
+ if not custom_documents_path:
+ raise ValueError("custom_documents_path must be provided when source is 'custom'")
+ self._load_custom_documents(custom_documents_path, chunk_size)
+ else:
+ raise ValueError(f"Unsupported source: {source}. Use 'custom'")
+
+ if not self.documents:
+ raise ValueError("No documents were successfully loaded")
+
+ print(f"Processed {len(self.documents)} chunks")
+
+ self._build_index()
+
+ def _load_custom_documents(self, documents_path: str, chunk_size: int):
+ """Helper method to load custom documents from a file"""
+ documents_path = Path(documents_path)
+ if not documents_path.exists():
+ raise FileNotFoundError(f"Custom documents file not found: {documents_path}")
+
+ with open(documents_path, "r") as f:
+ text = f.read()
+
+ # Simple chunking by paragraphs
+ paragraphs = [p.strip() for p in text.split("\n\n") if p.strip()]
+
+ # Process and store documents with basic chunking
+ for i, paragraph in enumerate(paragraphs):
+ if not paragraph or len(paragraph) < 50:
+ continue
+
+ # Simple chunking - just split by sentences
+ sentences = re.split(r"(?<=[.!?])\s+", paragraph)
+ chunks = []
+ current_chunk = []
+ current_length = 0
+
+ for sentence in sentences:
+ if current_length + len(sentence) > chunk_size and current_chunk:
+ chunks.append(" ".join(current_chunk))
+ current_chunk = [sentence]
+ current_length = len(sentence)
+ else:
+ current_chunk.append(sentence)
+ current_length += len(sentence)
+
+ if current_chunk:
+ chunks.append(" ".join(current_chunk))
+
+ for j, chunk in enumerate(chunks):
+ self.documents.append(
+ {
+ "text": chunk,
+ "metadata": {
+ "source": f"Document {i+1}",
+ "chunk_id": j,
+ "total_chunks": len(chunks),
+ "relevance": "medium",
+ "length": len(chunk),
+ },
+ }
+ )
+
+ def _build_index(self):
+ print("Building basic FAISS index...")
+ texts = [doc["text"] for doc in self.documents]
+ self.embeddings = self.encoder.encode(texts)
+ dimension = self.embeddings.shape[1]
+
+ # Use basic L2 distance instead of cosine similarity
+ self.index = faiss.IndexFlatL2(dimension)
+ self.index.add(self.embeddings.astype("float32"))
+ print("Index built successfully")
+
+ def search(self, query: str) -> list:
+ # Encode the query
+ query_vector = self.encoder.encode([query])[0]
+ query_vector = query_vector.reshape(1, -1)
+
+ # Get only one result
+ distances, indices = self.index.search(query_vector.astype("float32"), self.num_docs)
+
+ # Process results
+ results = []
+ for distance, idx in zip(distances[0], indices[0]):
+ doc = self.documents[idx].copy()
+ doc["metadata"] = doc["metadata"].copy()
+ doc["metadata"]["score"] = float(1 / (1 + distance)) # Simple distance to score conversion
+ results.append(doc)
+
+ return results
+
+
+def format_documents(documents: list) -> str:
+ return "\n\n".join(f"Document {i+1}:\n{doc['text']}" for i, doc in enumerate(documents))
diff --git a/examples/rag/cli-rag-demo/challenges/ensure-completeness-basic.py b/examples/rag/cli-rag-demo/challenges/ensure-completeness-basic.py
new file mode 100644
index 00000000..c40a04d8
--- /dev/null
+++ b/examples/rag/cli-rag-demo/challenges/ensure-completeness-basic.py
@@ -0,0 +1,73 @@
+import os
+from pathlib import Path
+from dotenv import load_dotenv
+from splunk_ao.openai import openai
+from rich.console import Console
+from document_store_basic import DocumentStoreBasic, format_documents
+from splunk_ao import splunk_ao_context
+
+# Find the .env file in the parent directory
+current_dir = Path(__file__).resolve().parent
+dotenv_path = ".env"
+
+# Load the .env file
+load_dotenv(dotenv_path)
+
+EXAMPLE_QUESTION = "Who discovered penicillin and what were the key details of this discovery?"
+
+SYSTEM_PROMPT = "You are a helpful assistant. Answer questions based on the provided document."
+
+
+class Prompts:
+ BASIC = """Question: {query}
+
+Document:
+{documents}
+
+Please provide an answer based on the document above."""
+
+
+def query(question: str):
+ client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY"), base_url=os.getenv("OPENAI_BASE_URL"))
+
+ # Basic approach: single document, no reranking
+ current_dir = Path(__file__).resolve().parent
+ custom_docs_path = current_dir / "penicillin_documents.txt"
+
+ store = DocumentStoreBasic(
+ source="custom",
+ custom_documents_path=str(custom_docs_path),
+ num_docs=1, # Only one document
+ chunk_size=1000, # Larger chunks, less precise
+ )
+ docs = store.search(question)
+
+ prompt = Prompts.BASIC.format(query=question, documents=format_documents(docs))
+
+ response = client.chat.completions.create(
+ model="gpt-4",
+ messages=[
+ {"role": "system", "content": SYSTEM_PROMPT},
+ {"role": "user", "content": prompt},
+ ],
+ )
+
+ return response.choices[0].message.content.strip()
+
+
+def main():
+ with splunk_ao_context(
+ project=os.getenv("SPLUNK_AO_PROJECT", "ensure-completeness"),
+ log_stream="basic_approach",
+ ):
+ console = Console()
+ console.print("\nBasic Completeness Demo")
+ console.print("\nUsing example question:", EXAMPLE_QUESTION)
+
+ response = query(EXAMPLE_QUESTION)
+ console.print("\nResponse:")
+ console.print(response)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/rag/cli-rag-demo/challenges/ensure-completeness-enhanced.py b/examples/rag/cli-rag-demo/challenges/ensure-completeness-enhanced.py
new file mode 100644
index 00000000..b960561d
--- /dev/null
+++ b/examples/rag/cli-rag-demo/challenges/ensure-completeness-enhanced.py
@@ -0,0 +1,98 @@
+import os
+from pathlib import Path
+from dotenv import load_dotenv
+from splunk_ao.openai import openai
+from rich.console import Console
+from document_store import DocumentStore
+from splunk_ao import splunk_ao_context
+
+# Find the .env file in the parent directory
+current_dir = Path(__file__).resolve().parent
+dotenv_path = ".env"
+
+# Load the .env file
+load_dotenv(dotenv_path)
+
+EXAMPLE_QUESTION = "Who discovered penicillin and what were the key details of this discovery?"
+
+SYSTEM_PROMPT = """You are a knowledgeable science historian tasked with providing comprehensive answers by analyzing and synthesizing information from multiple provided documents.
+
+IMPORTANT INSTRUCTIONS:
+1. You MUST use ALL relevant information from the retrieved documents in your response.
+2. For each key fact or detail you mention, explicitly cite the source document number (e.g., "As shown in Document 1...").
+3. If multiple documents contain related information, synthesize them into a cohesive explanation while citing all relevant sources.
+4. Do not omit any significant details present in the retrieved documents.
+5. If documents present different aspects of the same information, combine them to provide a complete picture.
+6. Pay attention to the relevance scores of documents - higher scores often indicate more pertinent information.
+7. Structure your response to build from foundational facts to more detailed information, citing the relevant documents throughout.
+
+Your response should demonstrate thorough analysis and integration of ALL information from the retrieved documents, making clear how each source contributed to the complete answer."""
+
+
+class Prompts:
+ ENHANCED = """Question: {query}
+
+Documents:
+{documents}
+
+IMPORTANT: Your response must:
+1. Use ALL relevant information from the documents above
+2. Cite specific document numbers for each fact
+3. Synthesize information from multiple documents when they contain related details
+4. Do not omit any significant details present in the documents
+5. Structure your response to build from foundational facts to more detailed information"""
+
+
+def format_documents_with_citations(documents: list) -> str:
+ return "\n\n".join(
+ f"Document {i+1} (Source: {doc['metadata']['source']}, Relevance: {doc['metadata']['relevance']}, "
+ f"Score: {doc['metadata'].get('combined_score', doc['metadata'].get('score', 'N/A')):.3f}):\n{doc['text']}"
+ for i, doc in enumerate(documents)
+ )
+
+
+def query(question: str):
+ client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY"), base_url=os.getenv("OPENAI_BASE_URL"))
+
+ # Enhanced approach: more documents with reranking
+ current_dir = Path(__file__).resolve().parent
+ custom_docs_path = current_dir / "penicillin_documents.txt"
+
+ store = DocumentStore(
+ source="custom",
+ custom_documents_path=str(custom_docs_path),
+ num_docs=10, # More documents
+ use_reranking=True, # Use reranking
+ reranking_threshold=0.6,
+ )
+ docs = store.search(question)
+
+ prompt = Prompts.ENHANCED.format(query=question, documents=format_documents_with_citations(docs))
+
+ response = client.chat.completions.create(
+ model="gpt-4",
+ messages=[
+ {"role": "system", "content": SYSTEM_PROMPT},
+ {"role": "user", "content": prompt},
+ ],
+ )
+
+ return response.choices[0].message.content.strip()
+
+
+def main():
+ with splunk_ao_context(
+ project=os.getenv("SPLUNK_AO_PROJECT", "ensure-completeness"),
+ log_stream="enhanced_approach",
+ ):
+ console = Console()
+ console.print("\nEnhanced Completeness Demo")
+ console.print("\nUsing example question:", EXAMPLE_QUESTION)
+
+ response = query(EXAMPLE_QUESTION)
+ console.print("\nResponse:")
+ console.print(response)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/rag/cli-rag-demo/challenges/out-of-context.py b/examples/rag/cli-rag-demo/challenges/out-of-context.py
new file mode 100644
index 00000000..b726bc5d
--- /dev/null
+++ b/examples/rag/cli-rag-demo/challenges/out-of-context.py
@@ -0,0 +1,259 @@
+import os
+from dotenv import load_dotenv
+from splunk_ao import openai, log, splunk_ao_context
+import questionary
+
+load_dotenv()
+
+# Check if Splunk AO logging is enabled
+logging_enabled = os.environ.get("SPLUNK_AO_API_KEY") is not None
+
+splunk_ao_context.init(project="out-of-context", log_stream="dev")
+
+# Initialize OpenAI client
+client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
+
+
+@log(span_type="retriever")
+def retrieve_documents(query: str):
+ """
+ Simulated document retrieval that intentionally returns incomplete information
+ to demonstrate the out-of-context problem.
+ """
+ # Dictionary of queries and their intentionally incomplete contexts
+ incomplete_contexts = {
+ "eiffel tower": [
+ {
+ "content": "The Eiffel Tower is an iron lattice tower located in Paris, France. It was designed by Gustave Eiffel.",
+ "metadata": {
+ "id": "doc1",
+ "source": "travel_guide",
+ "category": "landmarks",
+ "relevance": "high",
+ },
+ }
+ ],
+ "python language": [
+ {
+ "content": "Python is a high-level programming language known for its readability and simple syntax.",
+ "metadata": {
+ "id": "doc1",
+ "source": "programming_guide",
+ "category": "languages",
+ "relevance": "high",
+ },
+ }
+ ],
+ "climate change": [
+ {
+ "content": (
+ "Climate change refers to long-term shifts in temperatures and weather patterns. Human activities have been the main driver of climate change since the 1800s."
+ ),
+ "metadata": {
+ "id": "doc1",
+ "source": "environmental_science",
+ "category": "global_issues",
+ "relevance": "high",
+ },
+ }
+ ],
+ "artificial intelligence": [
+ {
+ "content": "Artificial intelligence involves creating systems capable of performing tasks that typically require human intelligence.",
+ "metadata": {
+ "id": "doc1",
+ "source": "technology_overview",
+ "category": "ai",
+ "relevance": "high",
+ },
+ }
+ ],
+ "quantum computing": [
+ {
+ "content": "Quantum computing uses quantum bits or qubits that can represent multiple states simultaneously.",
+ "metadata": {
+ "id": "doc1",
+ "source": "computing_technology",
+ "category": "quantum",
+ "relevance": "high",
+ },
+ }
+ ],
+ }
+
+ # Default case for queries not in our predefined list
+ default_docs = [
+ {
+ "content": "This is a generic response with limited information about the query topic.",
+ "metadata": {
+ "id": "default_doc",
+ "source": "general_knowledge",
+ "category": "miscellaneous",
+ "relevance": "low",
+ },
+ }
+ ]
+
+ # Find the most relevant predefined query
+ for key in incomplete_contexts:
+ if key in query.lower():
+ return incomplete_contexts[key]
+
+ return default_docs
+
+
+@log(name="rag_with_hallucination")
+def rag_with_hallucination(query: str):
+ """
+ RAG implementation that demonstrates the out-of-context problem by using
+ a system prompt that doesn't properly constrain the model.
+ """
+ documents = retrieve_documents(query)
+
+ # Format documents for better readability in the prompt
+ formatted_docs = ""
+ for i, doc in enumerate(documents):
+ formatted_docs += f"Document {i+1} (Source: {doc['metadata']['source']}):\n{doc['content']}\n\n"
+
+ # This prompt doesn't strongly constrain the model to only use the provided context
+ weak_prompt = f"""
+ Answer the following question based on the context provided.
+
+ Question: {query}
+
+ Context:
+ {formatted_docs}
+ """
+
+ try:
+ print("Generating answer (prone to out-of-context information)...")
+ response = client.chat.completions.create(
+ model="gpt-4o",
+ messages=[
+ {"role": "system", "content": "You are a helpful assistant."},
+ {"role": "user", "content": weak_prompt},
+ ],
+ )
+ return response.choices[0].message.content.strip()
+ except Exception as e:
+ return f"Error generating response: {str(e)}"
+
+
+@log(name="rag_with_constraint")
+def rag_with_constraint(query: str):
+ """
+ RAG implementation that demonstrates how to mitigate the out-of-context problem
+ by using a stronger system prompt and explicit instructions.
+ """
+ documents = retrieve_documents(query)
+
+ # Format documents for better readability in the prompt
+ formatted_docs = ""
+ for i, doc in enumerate(documents):
+ formatted_docs += f"Document {i+1} (Source: {doc['metadata']['source']}):\n{doc['content']}\n\n"
+
+ # This prompt strongly constrains the model to only use the provided context
+ strong_prompt = f"""
+ Answer the following question based STRICTLY on the context provided.
+ If the information needed to answer the question is not explicitly contained in the context,
+ respond with: "I don't have enough information in the provided context to answer this question."
+
+ DO NOT use any knowledge outside of the provided context.
+
+ Question: {query}
+
+ Context:
+ {formatted_docs}
+ """
+
+ try:
+ print("Generating answer (constrained to context)...")
+ response = client.chat.completions.create(
+ model="gpt-4o",
+ messages=[
+ {
+ "role": "system",
+ "content": "You are a helpful assistant that ONLY answers based on the provided context. Never use external knowledge.",
+ },
+ {"role": "user", "content": strong_prompt},
+ ],
+ )
+ return response.choices[0].message.content.strip()
+ except Exception as e:
+ return f"Error generating response: {str(e)}"
+
+
+@log
+def main():
+ print("Out-of-Context RAG Demo")
+ print("This demo shows how RAG systems can generate out-of-context information and how to prevent it.")
+
+ # Check environment setup
+ if logging_enabled:
+ print("Splunk AO logging is enabled")
+ else:
+ print("Splunk AO logging is disabled")
+
+ api_key = os.environ.get("OPENAI_API_KEY")
+ if not api_key:
+ print("OpenAI API Key is missing")
+ return
+
+ # Suggested queries
+ suggested_queries = [
+ "When was the Eiffel Tower completed?",
+ "Who created the Python language and when?",
+ "What are the main effects of climate change?",
+ "When was artificial intelligence first developed?",
+ "How many qubits are in the most powerful quantum computer?",
+ ]
+
+ print("\nSuggested queries (these will demonstrate the problem):")
+ for i, q in enumerate(suggested_queries):
+ print(f"{i+1}. {q}")
+
+ # Main interaction loop
+ while True:
+ try:
+ # Get user query
+ query = questionary.text(
+ "Enter your question (or type a number 1-5 to use a suggested query):",
+ validate=lambda text: len(text) > 0,
+ ).ask()
+
+ if query.lower() in ["exit", "quit", "q"]:
+ break
+
+ # Check if user entered a number for suggested queries
+ if query.isdigit() and 1 <= int(query) <= len(suggested_queries):
+ query = suggested_queries[int(query) - 1]
+ print(f"Using query: {query}")
+
+ # Generate both types of responses
+ hallucinated_result = rag_with_hallucination(query)
+ constrained_result = rag_with_constraint(query)
+
+ # Display the responses
+ print("\nUnconstrained Response (Prone to Out-of-Context Information):")
+ print(hallucinated_result)
+
+ print("\nConstrained Response (Limited to Context):")
+ print(constrained_result)
+
+ # Ask if user wants to continue
+ continue_session = questionary.confirm("Do you want to ask another question?", default=True).ask()
+
+ if not continue_session:
+ break
+
+ except Exception as e:
+ print(f"Error: {str(e)}")
+
+
+if __name__ == "__main__":
+ try:
+ main()
+ except KeyboardInterrupt:
+ print("\nExiting Out-of-Context RAG Demo. Goodbye!")
+ finally:
+ splunk_ao_context.flush() # Only flush at the very end
diff --git a/examples/rag/cli-rag-demo/challenges/penicillin_documents.txt b/examples/rag/cli-rag-demo/challenges/penicillin_documents.txt
new file mode 100644
index 00000000..7ef9b48a
--- /dev/null
+++ b/examples/rag/cli-rag-demo/challenges/penicillin_documents.txt
@@ -0,0 +1,21 @@
+Alexander Fleming was a Scottish bacteriologist who made one of the most important medical discoveries of the 20th century. Born in 1881, Fleming worked at St. Mary's Hospital in London where he conducted research on antibacterial substances.
+
+In 1928, while studying staphylococcus bacteria, Fleming made a chance observation that would change medicine forever. He noticed that a mold called Penicillium notatum had contaminated one of his culture plates and was killing the surrounding bacteria. This accidental discovery occurred when Fleming returned from a vacation to find his laboratory in disarray.
+
+Fleming's initial experiments with the mold showed that it produced a substance that could kill a wide range of bacteria. He named this substance "penicillin" after the mold that produced it. His 1929 paper describing this discovery was published in the British Journal of Experimental Pathology.
+
+While Fleming recognized the potential of penicillin, he faced significant challenges in producing it in large quantities. The substance was unstable and difficult to isolate. Fleming's work laid the foundation, but it wasn't until the 1940s that penicillin could be mass-produced.
+
+The development of penicillin as a practical antibiotic was achieved by a team of scientists at Oxford University, led by Howard Florey and Ernst Chain. They built upon Fleming's discovery and developed methods to purify and produce penicillin in large quantities.
+
+During World War II, penicillin proved to be a life-saving drug, treating infections that would have been fatal. Its impact on medicine was revolutionary, leading to the development of many other antibiotics and transforming the treatment of bacterial infections.
+
+Fleming, Florey, and Chain were jointly awarded the Nobel Prize in Physiology or Medicine in 1945 for their work on penicillin. Fleming's discovery is considered one of the most important medical breakthroughs in history, saving countless lives and ushering in the age of antibiotics.
+
+The discovery of penicillin marked the beginning of modern antibiotic therapy. Before penicillin, bacterial infections were often fatal, and there were few effective treatments available. The development of penicillin and subsequent antibiotics revolutionized medicine and significantly increased life expectancy.
+
+Fleming's work demonstrated the importance of careful observation in scientific research. His discovery was partly accidental, but it was his scientific training and curiosity that allowed him to recognize its significance. This serendipitous discovery has become a classic example of how chance observations can lead to major scientific breakthroughs.
+
+The story of penicillin's discovery also highlights the importance of collaboration in science. While Fleming made the initial discovery, it took the work of many other scientists to develop it into a practical treatment. This collaborative effort between different researchers and institutions was crucial to penicillin's success.
+
+Today, penicillin and its derivatives remain essential tools in modern medicine, though the rise of antibiotic resistance has become a significant challenge. Fleming himself warned about the potential for bacteria to develop resistance to antibiotics if they were not used properly.
\ No newline at end of file
diff --git a/examples/rag/cli-rag-demo/requirements.txt b/examples/rag/cli-rag-demo/requirements.txt
new file mode 100644
index 00000000..e6e920f2
--- /dev/null
+++ b/examples/rag/cli-rag-demo/requirements.txt
@@ -0,0 +1,26 @@
+galileo>=0.3.0
+rich>=13.7.0
+questionary>=2.0.1
+openai==1.61.1
+pydantic==2.10.6
+aiohappyeyeballs==2.4.6
+aiohttp==3.11.12
+aiosignal==1.3.2
+attrs==25.1.0
+certifi==2025.1.31
+frozenlist==1.5.0
+idna==3.10
+multidict==6.1.0
+pinecone==6.0.1
+pinecone-plugin-interface==0.0.7
+propcache==0.2.1
+python-dateutil==2.9.0.post0
+six==1.17.0
+typing_extensions==4.12.2
+urllib3==2.3.0
+yarl==1.18.3
+faiss-cpu>=1.7.4
+sentence-transformers>=2.5.1
+numpy>=1.24.0 # Required by FAISS and sentence-transformers
+python-dotenv>=1.0.0 # Added for dotenv support
+datasets>=2.18.0 # Added for loading example datasets
diff --git a/examples/rag/cli-rag-demo/test.py b/examples/rag/cli-rag-demo/test.py
new file mode 100644
index 00000000..8cc1d94f
--- /dev/null
+++ b/examples/rag/cli-rag-demo/test.py
@@ -0,0 +1,25 @@
+import os
+from dotenv import load_dotenv
+
+from splunk_ao import splunk_ao_context, openai
+
+load_dotenv()
+
+# If you've set your SPLUNK_AO_PROJECT and SPLUNK_AO_LOG_STREAM env vars, you can skip this step
+splunk_ao_context.init(project="your-project-name", log_stream="your-log-stream-name")
+
+# Initialize the Splunk AO wrapped OpenAI client
+client = openai.OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
+
+
+def call_openai():
+ chat_completion = client.chat.completions.create(messages=[{"role": "user", "content": "Say this is a test"}], model="gpt-4o")
+
+ return chat_completion.choices[0].message.content
+
+
+# This will create a single span trace with the OpenAI call
+call_openai()
+
+# This will upload the trace to Splunk AO
+splunk_ao_context.flush()
diff --git a/examples/rag/elastic-chatbot-rag-app/.dockerignore b/examples/rag/elastic-chatbot-rag-app/.dockerignore
new file mode 100644
index 00000000..d634fdf0
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/.dockerignore
@@ -0,0 +1,2 @@
+.venv
+*/node_modules
diff --git a/examples/rag/elastic-chatbot-rag-app/.gitignore b/examples/rag/elastic-chatbot-rag-app/.gitignore
new file mode 100644
index 00000000..e96833be
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/.gitignore
@@ -0,0 +1,8 @@
+frontend/build
+frontend/node_modules
+api/__pycache__
+.venv
+venv
+.DS_Store
+.env
+!frontend/src/lib
diff --git a/examples/rag/elastic-chatbot-rag-app/Dockerfile b/examples/rag/elastic-chatbot-rag-app/Dockerfile
new file mode 100644
index 00000000..90295d76
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/Dockerfile
@@ -0,0 +1,29 @@
+FROM node:22-alpine AS build-step
+WORKDIR /app
+ENV PATH=/node_modules/.bin:$PATH
+COPY frontend ./frontend
+RUN cd frontend && yarn install
+RUN cd frontend && REACT_APP_API_HOST=/api yarn build
+
+# Use glibc-based image to get pre-compiled wheels for grpcio and tiktoken
+FROM python:3.12-slim
+
+WORKDIR /app
+RUN mkdir -p ./frontend/build
+COPY --from=build-step ./app/frontend/build ./frontend/build
+
+COPY requirements.txt ./requirements.txt
+RUN pip3 install -r ./requirements.txt
+
+RUN mkdir -p ./api ./data
+COPY api ./api
+COPY data ./data
+
+EXPOSE 4000
+
+# Default to disabling instrumentation, can be overridden to false in
+# docker invocations to reenable.
+ENV OTEL_SDK_DISABLED=true
+ENTRYPOINT [ "opentelemetry-instrument" ]
+
+CMD [ "python", "api/app.py" ]
diff --git a/examples/rag/elastic-chatbot-rag-app/README.md b/examples/rag/elastic-chatbot-rag-app/README.md
new file mode 100644
index 00000000..e5708d60
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/README.md
@@ -0,0 +1,293 @@
+# Elastic Chatbot RAG App + Splunk AO
+
+Read more on how to leverage [Splunk AO for your chat app](https://docs.galileo.ai/cookbooks/use-cases/rag-elastic-langchain-integration)
+
+This is a sample app that combines Elasticsearch, Langchain and a number of different LLMs to create a chatbot experience with ELSER with your own private data.
+
+**Requires at least 8.11.0 of Elasticsearch.**
+
+
+
+## Setup a Splunk AO project:
+
+On your cluster or [https://app.galileo.ai](https://app.galileo.ai) create an account, a logstream project and api keys. You can follow [this guide](https://docs.galileo.ai/concepts/projects#whats-in-a-project).
+
+Make sure to set your Splunk AO logging env variables
+
+```bash
+# Splunk AO Environment Variables
+SPLUNK_AO_API_KEY=your-splunk-ao-api-key # Your Splunk AO API key.
+SPLUNK_AO_PROJECT=your-splunk-ao-project-name # Your Splunk AO project name.
+SPLUNK_AO_LOG_STREAM=your-splunk-ao-log-stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# SPLUNK_AO_CONSOLE_URL=your-splunk-ao-console-url # Optional if you are using a hosted version of Splunk AO
+```
+
+## Download the Project
+
+Download the project from Github and extract the `chatbot-rag-app` folder from python/rag.
+
+```bash
+git clone https://github.com/rungalileo/sdk-examples.git
+```
+
+## Make your .env file
+
+Copy [env.example](env.example) to `.env` and fill in values noted inside.
+
+## Installing and connecting to Elasticsearch
+
+There are a number of ways to install Elasticsearch. Cloud is best for most
+use-cases. We also have [docker-compose-elastic.yml][docker-compose-elastic],
+that starts Elasticsearch, Kibana, and APM Server on your laptop in one step.
+
+Once you decided your approach, edit your `.env` file accordingly.
+
+For more information, visit our [Install Elasticsearch][install-es] tutorial.
+
+## Connecting to LLM
+
+We support several LLM providers, but only one is used at runtime, and selected
+by the `LLM_TYPE` entry in your `.env` file. Edit that file to choose an LLM,
+and configure its templated connection settings:
+
+- azure: [Azure OpenAI Service](https://learn.microsoft.com/azure/ai-services/openai/)
+- bedrock: [Amazon Bedrock](https://docs.aws.amazon.com/bedrock/)
+- openai: [OpenAI Platform](https://platform.openai.com/docs/overview) and
+ services compatible with its API.
+- vertex: [Google Vertex AI](https://cloud.google.com/vertex-ai/docs)
+- mistral: [Mistral AI](https://docs.mistral.ai/)
+- cohere: [Cohere](https://docs.cohere.com/)
+
+## Running the App
+
+This application contains two services:
+
+- create-index: Installs ELSER and ingests data into elasticsearch
+- api-frontend: Hosts the chatbot-rag-app application on http://localhost:4000
+
+There are two ways to run the app: via Docker or locally. Docker is advised for
+ease while locally is advised if you are making changes to the application.
+
+### Run with docker
+
+Docker compose is the easiest way to get started, as you don't need to have a
+working Python environment.
+
+**Double-check you have a `.env` file with all your variables set first!**
+
+```bash
+docker compose up --pull always --force-recreate
+```
+
+_Note_: The first run may take several minutes to become available.
+
+Clean up when finished, like this:
+
+```bash
+docker compose down
+```
+
+### Run with Kubernetes
+
+Kubernetes is more complicated than Docker, but closer to the production
+experience for many users. [k8s-manifest.yml](k8s-manifest.yml) creates the
+same services, but needs additional configuration first.
+
+First step is to setup your environment. [env.example](env.example) must be
+copied to a file name `.env` and updated with `ELASTICSEARCH_URL` and
+`OTEL_EXPORTER_OTLP_ENDPOINT` values visible to you Kubernetes deployment.
+
+For example, if you started your Elastic Stack with [k8s-manifest-elastic.yml][k8s-manifest-elastic],
+you would update these values:
+
+```
+ELASTICSEARCH_URL=http://elasticsearch:9200
+OTEL_EXPORTER_OTLP_ENDPOINT=http://apm-server:8200
+```
+
+Then, import your `.env` file as a configmap like this:
+
+```bash
+kubectl create configmap chatbot-rag-app-env --from-env-file=.env
+```
+
+
+To use Vertex AI, set `LLM_TYPE=vertex` in your `.env` and follow these steps
+
+The `api-frontend container` needs access to your Google Cloud credentials.
+Share your `application_default_credentials.json` as a Kubernetes secret:
+
+```bash
+# Logs you into Google Cloud and creates application_default_credentials.json
+gcloud auth application-default login
+# Adds your credentials to a Kubernetes secret named gcloud-credentials
+kubectl create secret generic gcloud-credentials \
+ --from-file=application_default_credentials.json=$HOME/.config/gcloud/application_default_credentials.json
+```
+
+
+
+Now that your configuration is applied, create the `chatbot-rag-app` deployment
+and service by applying this manifest:
+
+```bash
+kubectl apply -f k8s-manifest.yml
+```
+
+Next, block until `chatbot-rag-app` is available.
+
+```bash
+kubectl wait --for=condition=available --timeout=20m deployment/chatbot-rag-app
+```
+
+_Note_: The first run may take several minutes to become available. Here's how
+to follow logs on this stage:
+
+```bash
+kubectl logs deployment.apps/chatbot-rag-app -c create-index -f
+```
+
+Next, forward the web UI port:
+
+```bash
+kubectl port-forward deployment.apps/chatbot-rag-app 4000:4000 &
+```
+
+Clean up when finished, like this:
+
+```bash
+kubectl delete -f k8s-manifest.yml
+```
+
+### Run with Python
+
+If you want to run this example with Python, you need to do a few things listed
+in the [Dockerfile](Dockerfile) to build it first. The below uses the same
+production mode as used in Docker to avoid problems in debug mode.
+
+**Double-check you have a `.env` file with all your variables set first!**
+
+#### Build the frontend
+
+The web assets are in the [frontend](frontend) directory, and built with yarn.
+
+```bash
+# Install and use a recent node, if you don't have one.
+nvm install --lts
+nvm use --lts
+# Build the frontend web assets
+(cd frontend; yarn install; REACT_APP_API_HOST=/api yarn build)
+```
+
+#### Configure your Python environment
+
+Before we can run the app, we need a working Python environment with the
+correct packages installed:
+
+```bash
+python3 -m venv .venv
+source .venv/bin/activate
+# Install dotenv which is a portable way to load environment variables.
+pip install "python-dotenv[cli]"
+pip install -r requirements.txt
+```
+
+#### Create your Elasticsearch index
+
+First, ingest the data into elasticsearch:
+
+```bash
+dotenv run -- flask create-index
+```
+
+_Note_: This may take several minutes to complete
+
+#### Run the application
+
+Now, run the app, which listens on http://localhost:4000
+
+```bash
+dotenv run -- python api/app.py
+```
+
+## Advanced
+
+### OpenTelemetry
+
+If you set `OTEL_SDK_DISABLED=false` in your `.env` file, the app will send
+logs, metrics and traces to an OpenTelemetry compatible endpoint.
+
+This happens automatically, when using docker. If running with python directly,
+prefix `python` with `opentelemetry-instrument` to enable OpenTelemetry.
+
+```bash
+dotenv run -- opentelemetry-instrument python api/app.py
+```
+
+[env.example](env.example) defaults to use Elastic APM server, started by
+[docker-compose-elastic.yml](../../docker). If you start your Elastic stack
+this way, you can access Kibana like this, authenticating with the username
+"elastic" and password "elastic":
+
+http://localhost:5601/app/apm/traces?rangeFrom=now-15m&rangeTo=now
+
+Under the scenes, chatbot-rag-app is automatically instrumented by the Elastic
+Distribution of OpenTelemetry (EDOT) Python. You can see more details about
+EDOT Python [here](https://github.com/elastic/elastic-otel-python).
+
+OpenTelemetry support for LLM providers not included in EDOT Python are provided
+by the [Langtrace Python SDK](https://docs.langtrace.ai/sdk/python_sdk).
+
+### Updating package versions
+
+To update package versions, recreate [requirements.txt](requirements.txt) and
+reinstall like this. Once checked in, any commands above will use updates.
+
+```bash
+rm -rf .venv requirements.txt
+python3 -m venv .venv
+source .venv/bin/activate
+# Install dev requirements for pip-compile and edot-bootstrap
+pip install pip-tools elastic-opentelemetry
+# Recreate requirements.txt
+pip-compile
+# Install main dependencies
+pip install -r requirements.txt
+# Add opentelemetry instrumentation for these dependencies
+edot-bootstrap >> requirements.txt
+# Install opentelemetry dependencies
+pip install -r requirements.txt
+```
+
+### Elasticsearch index and chat_history index
+
+By default, the app will use the `workplace-app-docs` index and the chat
+history index will be `workplace-app-docs-chat-history`. If you want to change
+these, edit `ES_INDEX` and `ES_INDEX_CHAT_HISTORY` entries in your `.env` file.
+
+### Indexing your own data
+
+The ingesting logic is stored in [data/index_data.py](data/index_data.py). This
+is a simple script that uses Langchain to index data into Elasticsearch, using
+`RecursiveCharacterTextSplitter` to split the large JSON documents into
+passages. Modify this script to index your own data.
+
+See [Langchain documentation][loader-docs] for more ways to load documents.
+
+### Running from source with Docker
+
+To build the app from source instead of using published images, pass the
+`--build` flag to Docker Compose instead of `--pull always`
+
+```bash
+docker compose up --build --force-recreate
+```
+
+---
+
+[loader-docs]: https://python.langchain.com/docs/how_to/#document-loaders
+[install-es]: https://www.elastic.co/search-labs/tutorials/install-elasticsearch
+[docker-compose-elastic]: ../../docker/docker-compose-elastic.yml
+[k8s-manifest-elastic]: ../../k8s/k8s-manifest-elastic.yml
diff --git a/examples/rag/elastic-chatbot-rag-app/api/app.py b/examples/rag/elastic-chatbot-rag-app/api/app.py
new file mode 100644
index 00000000..a94f4a24
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/api/app.py
@@ -0,0 +1,41 @@
+import os
+import sys
+from uuid import uuid4
+
+from chat import ask_question
+from flask import Flask, Response, jsonify, request
+from flask_cors import CORS
+
+app = Flask(__name__, static_folder="../frontend/build", static_url_path="/")
+CORS(app)
+
+
+@app.route("/")
+def api_index():
+ return app.send_static_file("index.html")
+
+
+@app.route("/api/chat", methods=["POST"])
+def api_chat():
+ request_json = request.get_json()
+ question = request_json.get("question")
+ if question is None:
+ return jsonify({"msg": "Missing question from request JSON"}), 400
+
+ session_id = request.args.get("session_id", str(uuid4()))
+ return Response(ask_question(question, session_id), mimetype="text/event-stream")
+
+
+@app.cli.command()
+def create_index():
+ """Create or re-create the Elasticsearch index."""
+ basedir = os.path.abspath(os.path.dirname(__file__))
+ sys.path.append(f"{basedir}/../")
+
+ from data import index_data
+
+ index_data.main()
+
+
+if __name__ == "__main__":
+ app.run(host="0.0.0.0", port=4000, debug=False)
diff --git a/examples/rag/elastic-chatbot-rag-app/api/chat.py b/examples/rag/elastic-chatbot-rag-app/api/chat.py
new file mode 100644
index 00000000..7d790f6f
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/api/chat.py
@@ -0,0 +1,123 @@
+import json
+import os
+
+from elasticsearch_client import (
+ elasticsearch_client,
+ get_elasticsearch_chat_message_history,
+)
+from flask import current_app, render_template, stream_with_context
+from functools import cache
+from langchain_elasticsearch import (
+ ElasticsearchStore,
+ SparseVectorStrategy,
+)
+from langchain_core.messages.ai import AIMessageChunk
+
+from langgraph.graph import START, StateGraph
+from splunk_ao.handlers.langchain import SplunkAOCallback
+
+
+from utils import State
+
+from llm_integrations import get_llm
+
+# Make sure to set your Splunk AO logging env variables
+callback = SplunkAOCallback()
+
+
+INDEX = os.getenv("ES_INDEX", "workplace-app-docs")
+INDEX_CHAT_HISTORY = os.getenv("ES_INDEX_CHAT_HISTORY", "workplace-app-docs-chat-history")
+ELSER_MODEL = os.getenv("ELSER_MODEL", ".elser_model_2")
+SESSION_ID_TAG = "[SESSION_ID]"
+SOURCE_TAG = "[SOURCE]"
+DONE_TAG = "[DONE]"
+
+store = ElasticsearchStore(
+ es_connection=elasticsearch_client,
+ index_name=INDEX,
+ strategy=SparseVectorStrategy(model_id=ELSER_MODEL),
+)
+
+store_retriever = store.as_retriever()
+
+
+@cache
+def get_lazy_llm():
+ return get_llm()
+
+
+@stream_with_context
+def ask_question(question, session_id):
+ llm = get_lazy_llm()
+
+ yield f"data: {SESSION_ID_TAG} {session_id}\n\n"
+ current_app.logger.debug("Chat session ID: %s", session_id)
+
+ chat_history = get_elasticsearch_chat_message_history(INDEX_CHAT_HISTORY, session_id)
+
+ # Define application steps
+ def retrieve(state: State):
+ question = state["question"]
+ if len(chat_history.messages) > 0:
+ # create a condensed question
+ condense_question_prompt = render_template(
+ "condense_question_prompt.txt",
+ question=question,
+ chat_history=chat_history.messages,
+ )
+ condensed_question = llm.invoke(condense_question_prompt).content
+ else:
+ condensed_question = question
+ current_app.logger.debug("Condensed question: %s", condensed_question)
+ current_app.logger.debug("Question: %s", question)
+
+ retrieved_docs = store_retriever.invoke(condensed_question)
+
+ return {"context": retrieved_docs}
+
+ def generate(state: State):
+ question = state["question"]
+ docs = state["context"]
+
+ qa_prompt = render_template(
+ "rag_prompt.txt",
+ question=question,
+ docs=docs,
+ chat_history=chat_history.messages,
+ )
+
+ response = llm.invoke(qa_prompt)
+ return {"answer": response.content}
+
+ graph_builder = StateGraph(State).add_sequence([retrieve, generate])
+ graph_builder.add_edge(START, "retrieve")
+ graph = graph_builder.compile()
+ retrieved = False
+ answer = ""
+ for mode, step in graph.stream(
+ {"question": question},
+ stream_mode=["updates", "messages"],
+ config={"callbacks": [callback]},
+ ):
+ if mode == "updates":
+ if not retrieved and "retrieve" in step:
+ retrieved = True
+ for doc in step["retrieve"]["context"]:
+ doc_source = {**doc.metadata, "page_content": doc.page_content}
+ current_app.logger.debug("Retrieved document passage from: %s", doc.metadata["name"])
+ yield f"data: {SOURCE_TAG} {json.dumps(doc_source)}\n\n"
+ if "generate" in step:
+ answer = step["generate"]["answer"]
+ answer = answer.replace("\n", " ")
+ yield f"data: {DONE_TAG}\n\n"
+ elif mode == "messages":
+ for message in step:
+ if not isinstance(message, AIMessageChunk):
+ continue
+ content = message.content.replace("\n", " ") # the stream can get messed up with newlines
+ yield f"data: {content}\n\n"
+
+ current_app.logger.debug("Answer: %s", answer)
+
+ chat_history.add_user_message(question)
+ chat_history.add_ai_message(answer)
diff --git a/examples/rag/elastic-chatbot-rag-app/api/elasticsearch_client.py b/examples/rag/elastic-chatbot-rag-app/api/elasticsearch_client.py
new file mode 100644
index 00000000..a76aa5e0
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/api/elasticsearch_client.py
@@ -0,0 +1,23 @@
+import os
+
+from elasticsearch import Elasticsearch
+from langchain_elasticsearch import ElasticsearchChatMessageHistory
+
+ELASTICSEARCH_URL = os.getenv("ELASTICSEARCH_URL")
+ELASTICSEARCH_USER = os.getenv("ELASTICSEARCH_USER")
+ELASTICSEARCH_PASSWORD = os.getenv("ELASTICSEARCH_PASSWORD")
+ELASTICSEARCH_API_KEY = os.getenv("ELASTICSEARCH_API_KEY")
+
+if ELASTICSEARCH_USER:
+ elasticsearch_client = Elasticsearch(
+ hosts=[ELASTICSEARCH_URL],
+ basic_auth=(ELASTICSEARCH_USER, ELASTICSEARCH_PASSWORD),
+ )
+elif ELASTICSEARCH_API_KEY:
+ elasticsearch_client = Elasticsearch(hosts=[ELASTICSEARCH_URL], api_key=ELASTICSEARCH_API_KEY)
+else:
+ raise ValueError("Please provide either ELASTICSEARCH_USER or ELASTICSEARCH_API_KEY")
+
+
+def get_elasticsearch_chat_message_history(index, session_id):
+ return ElasticsearchChatMessageHistory(es_connection=elasticsearch_client, index=index, session_id=session_id)
diff --git a/examples/rag/elastic-chatbot-rag-app/api/llm_integrations.py b/examples/rag/elastic-chatbot-rag-app/api/llm_integrations.py
new file mode 100644
index 00000000..5b371ee1
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/api/llm_integrations.py
@@ -0,0 +1,64 @@
+import os
+from langchain.chat_models import init_chat_model
+
+LLM_TYPE = os.getenv("LLM_TYPE", "openai")
+
+
+def init_openai_chat(temperature):
+ # Include streaming usage as this allows recording of LLM metrics
+ return init_chat_model(os.getenv("CHAT_MODEL"), model_provider="openai", temperature=temperature)
+
+
+def init_vertex_chat(temperature):
+ # VertexAI is not yet in EDOT. Use the Langtrace Python SDK instead
+ from langtrace_python_sdk.instrumentation import VertexAIInstrumentation
+
+ VertexAIInstrumentation().instrument()
+ return init_chat_model(os.getenv("CHAT_MODEL"), model_provider="google_vertexai", temperature=temperature)
+
+
+def init_azure_chat(temperature):
+ # Include streaming usage as this allows recording of LLM metrics
+ return init_chat_model(os.getenv("CHAT_DEPLOYMENT"), model_provider="azure_openai", temperature=temperature)
+
+
+def init_bedrock(temperature):
+ # Bedrock is not yet in EDOT. Use the Langtrace Python SDK instead
+ from langtrace_python_sdk.instrumentation import AWSBedrockInstrumentation
+
+ AWSBedrockInstrumentation().instrument()
+ return init_chat_model(os.getenv("CHAT_MODEL"), model_provider="bedrock", temperature=temperature)
+
+
+def init_mistral_chat(temperature):
+ return init_chat_model(os.getenv("CHAT_MODEL"), model_provider="mistralai", temperature=temperature)
+
+
+def init_cohere_chat(temperature):
+ # Cohere is not yet in EDOT. Use the Langtrace Python SDK instead
+ from langtrace_python_sdk.instrumentation import CohereInstrumentation
+
+ CohereInstrumentation().instrument()
+ return init_chat_model(os.getenv("CHAT_MODEL"), model_provider="cohere", temperature=temperature)
+
+
+def init_anthropic_chat(temperature):
+ return init_chat_model(os.getenv("CHAT_MODEL"), model_provider="anthropic", temperature=temperature)
+
+
+MAP_LLM_TYPE_TO_CHAT_MODEL = {
+ "azure": init_azure_chat,
+ "bedrock": init_bedrock,
+ "openai": init_openai_chat,
+ "vertex": init_vertex_chat,
+ "mistral": init_mistral_chat,
+ "cohere": init_cohere_chat,
+ "anthropic": init_anthropic_chat,
+}
+
+
+def get_llm(temperature=0):
+ if LLM_TYPE not in MAP_LLM_TYPE_TO_CHAT_MODEL:
+ raise Exception("LLM type not found. Please set LLM_TYPE to one of: " + ", ".join(MAP_LLM_TYPE_TO_CHAT_MODEL.keys()) + ".")
+
+ return MAP_LLM_TYPE_TO_CHAT_MODEL[LLM_TYPE](temperature=temperature)
diff --git a/examples/rag/elastic-chatbot-rag-app/api/templates/condense_question_prompt.txt b/examples/rag/elastic-chatbot-rag-app/api/templates/condense_question_prompt.txt
new file mode 100644
index 00000000..6a79142b
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/api/templates/condense_question_prompt.txt
@@ -0,0 +1,8 @@
+Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question, in its original language.
+
+Chat history:
+{% for dialogue_turn in chat_history -%}
+{% if dialogue_turn.type == 'human' %}Question: {{ dialogue_turn.content }}{% elif dialogue_turn.type == 'ai' %}Response: {{ dialogue_turn.content }}{% endif %}
+{% endfor -%}
+Follow Up Question: {{ question }}
+Standalone question:
diff --git a/examples/rag/elastic-chatbot-rag-app/api/templates/rag_prompt.txt b/examples/rag/elastic-chatbot-rag-app/api/templates/rag_prompt.txt
new file mode 100644
index 00000000..0935116a
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/api/templates/rag_prompt.txt
@@ -0,0 +1,31 @@
+Use the following passages and chat history to answer the user's question.
+Each passage has a NAME which is the title of the document. After your answer, leave a blank line and then give the source name of the passages you answered from. Put them in a comma separated list, prefixed with SOURCES:.
+
+Example:
+
+Question: What is the meaning of life?
+Response:
+The meaning of life is 42.
+
+SOURCES: Hitchhiker's Guide to the Galaxy
+
+If you don't know the answer, just say that you don't know, don't try to make up an answer.
+
+----
+
+{% for doc in docs -%}
+---
+NAME: {{ doc.metadata.name }}
+PASSAGE:
+{{ doc.page_content }}
+---
+
+{% endfor -%}
+----
+Chat history:
+{% for dialogue_turn in chat_history -%}
+{% if dialogue_turn.type == 'human' %}Question: {{ dialogue_turn.content }}{% elif dialogue_turn.type == 'ai' %}Response: {{ dialogue_turn.content }}{% endif %}
+{% endfor -%}
+
+Question: {{ question }}
+Response:
diff --git a/examples/rag/elastic-chatbot-rag-app/api/utils.py b/examples/rag/elastic-chatbot-rag-app/api/utils.py
new file mode 100644
index 00000000..25b5ee3f
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/api/utils.py
@@ -0,0 +1,9 @@
+from typing_extensions import List, TypedDict
+from langchain_core.documents import Document
+
+
+# Define state for application
+class State(TypedDict):
+ question: str
+ context: List[Document]
+ answer: str
diff --git a/examples/rag/elastic-chatbot-rag-app/app-demo.gif b/examples/rag/elastic-chatbot-rag-app/app-demo.gif
new file mode 100644
index 00000000..b1c47481
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/app-demo.gif differ
diff --git a/examples/rag/elastic-chatbot-rag-app/data/data.json b/examples/rag/elastic-chatbot-rag-app/data/data.json
new file mode 100644
index 00000000..fccd6420
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/data/data.json
@@ -0,0 +1,161 @@
+[
+ {
+ "content": "Effective: March 2020\nPurpose\n\nThe purpose of this full-time work-from-home policy is to provide guidelines and support for employees to conduct their work remotely, ensuring the continuity and productivity of business operations during the COVID-19 pandemic and beyond.\nScope\n\nThis policy applies to all employees who are eligible for remote work as determined by their role and responsibilities. It is designed to allow employees to work from home full time while maintaining the same level of performance and collaboration as they would in the office.\nEligibility\n\nEmployees who can perform their work duties remotely and have received approval from their direct supervisor and the HR department are eligible for this work-from-home arrangement.\nEquipment and Resources\n\nThe necessary equipment and resources will be provided to employees for remote work, including a company-issued laptop, software licenses, and access to secure communication tools. Employees are responsible for maintaining and protecting the company's equipment and data.\nWorkspace\n\nEmployees working from home are responsible for creating a comfortable and safe workspace that is conducive to productivity. This includes ensuring that their home office is ergonomically designed, well-lit, and free from distractions.\nCommunication\n\nEffective communication is vital for successful remote work. Employees are expected to maintain regular communication with their supervisors, colleagues, and team members through email, phone calls, video conferences, and other approved communication tools.\nWork Hours and Availability\n\nEmployees are expected to maintain their regular work hours and be available during normal business hours, unless otherwise agreed upon with their supervisor. Any changes to work hours or availability must be communicated to the employee's supervisor and the HR department.\nPerformance Expectations\n\nEmployees working from home are expected to maintain the same level of performance and productivity as if they were working in the office. Supervisors and team members will collaborate to establish clear expectations and goals for remote work.\nTime Tracking and Overtime\n\nEmployees are required to accurately track their work hours using the company's time tracking system. Non-exempt employees must obtain approval from their supervisor before working overtime.\nConfidentiality and Data Security\n\nEmployees must adhere to the company's confidentiality and data security policies while working from home. This includes safeguarding sensitive information, securing personal devices and internet connections, and reporting any security breaches to the IT department.\nHealth and Well-being\n\nThe company encourages employees to prioritize their health and well-being while working from home. This includes taking regular breaks, maintaining a work-life balance, and seeking support from supervisors and colleagues when needed.\nPolicy Review and Updates\n\nThis work-from-home policy will be reviewed periodically and updated as necessary, taking into account changes in public health guidance, business needs, and employee feedback.\nQuestions and Concerns\n\nEmployees are encouraged to direct any questions or concerns about this policy to their supervisor or the HR department.\n",
+ "summary": "This policy outlines the guidelines for full-time remote work, including eligibility, equipment and resources, workspace requirements, communication expectations, performance expectations, time tracking and overtime, confidentiality and data security, health and well-being, and policy reviews and updates. Employees are encouraged to direct any questions or concerns",
+ "name": "Work From Home Policy",
+ "url": "./sharepoint/Work from home policy.txt",
+ "created_on": "2020-03-01",
+ "updated_at": "2020-03-01",
+ "category": "teams",
+ "_run_ml_inference": true,
+ "rolePermissions": ["demo", "manager"]
+ },
+ {
+ "content": "Starting May 2022, the company will be implementing a two-day in-office work requirement per week for all eligible employees. Please coordinate with your supervisor and HR department to schedule your in-office workdays while continuing to follow all safety protocols.\n",
+ "summary": "Starting May 2022, employees will need to work two days a week in the office. Coordinate with your supervisor and HR department for these days while following safety protocols.",
+ "name": "April Work From Home Update",
+ "url": "./sharepoint/April work from home update.txt",
+ "created_on": "2022-04-29",
+ "updated_at": "2022-04-29",
+ "category": "teams",
+ "_run_ml_inference": true,
+ "rolePermissions": ["demo", "manager"]
+ },
+ {
+ "content": "As we continue to prioritize the well-being of our employees, we are making a slight adjustment to our hybrid work policy. Starting May 1, 2023, employees will be required to work from the office three days a week, with two days designated for remote work. Please communicate with your supervisor and HR department to establish your updated in-office workdays.\n",
+ "summary": "Starting May 1, 2023, our hybrid work policy will require employees to work from the office three days a week and two days remotely.",
+ "name": "Wfh Policy Update May 2023",
+ "url": "./sharepoint/WFH policy update May 2023.txt",
+ "created_on": "2023-05-01",
+ "updated_at": "2023-05-01",
+ "category": "teams",
+ "_run_ml_inference": true,
+ "rolePermissions": ["demo", "manager"]
+ },
+ {
+ "content": "Executive Summary:\nThis sales strategy document outlines the key objectives, focus areas, and action plans for our tech company's sales operations in fiscal year 2024. Our primary goal is to increase revenue, expand market share, and strengthen customer relationships in our target markets.\n\nI. Objectives for Fiscal Year 2024\n\nIncrease revenue by 20% compared to fiscal year 2023.\nExpand market share in key segments by 15%.\nRetain 95% of existing customers and increase customer satisfaction ratings.\nLaunch at least two new products or services in high-demand market segments.\n\nII. Focus Areas\nA. Target Markets:\nContinue to serve existing markets with a focus on high-growth industries.\nIdentify and penetrate new markets with high potential for our products and services.\n\nB. Customer Segmentation:\nStrengthen relationships with key accounts and strategic partners.\nPursue new customers in underserved market segments.\nDevelop tailored offerings for different customer segments based on their needs and preferences.\n\nC. Product/Service Portfolio:\nOptimize the existing product/service portfolio by focusing on high-demand solutions.\nDevelop and launch innovative products/services in emerging technology areas.\nEnhance post-sales support and customer service to improve customer satisfaction.\n\nIII. Action Plans\nA. Sales Team Development:\nExpand the sales team to cover new markets and industries.\nProvide ongoing training to sales staff on product knowledge, sales techniques, and industry trends.\nImplement a performance-based incentive system to reward top performers.\n\nB. Marketing and Promotion:\nDevelop targeted marketing campaigns for different customer segments and industries.\nLeverage digital marketing channels to increase brand visibility and lead generation.\nParticipate in industry events and trade shows to showcase our products and services.\n\nC. Partner Ecosystem:\nStrengthen existing partnerships and establish new strategic alliances to expand market reach.\nCollaborate with partners on joint marketing and sales initiatives.\nProvide partner training and support to ensure they effectively represent our products and services.\n\nD. Customer Success:\nImplement a proactive customer success program to improve customer retention and satisfaction.\nDevelop a dedicated customer support team to address customer inquiries and concerns promptly.\nCollect and analyze customer feedback to identify areas for improvement in our products, services, and processes.\n\nIV. Monitoring and Evaluation\nEstablish key performance indicators (KPIs) to track progress toward our objectives.\nConduct regular sales team meetings to review performance, share best practices, and address challenges.\nConduct quarterly reviews of our sales strategy to ensure alignment with market trends and adjust as needed.\n\nBy following this sales strategy for fiscal year 2024, our tech company aims to achieve significant growth and success in our target markets, while also providing exceptional value and service to our customers.\n",
+ "summary": "This sales strategy document outlines objectives, focus areas, and action plans for our tech company's sales operations in fiscal year 2024. Our primary goal is to increase revenue, expand market share, and strengthen customer relationships in our target markets. Focus areas include targeting new markets, segmenting customers, enhancing",
+ "name": "Fy2024 Company Sales Strategy",
+ "url": "./sharepoint/FY2024 Company Sales Strategy.txt",
+ "category": "teams",
+ "created_on": "2023-04-15",
+ "updated_at": "2023-04-15",
+ "_run_ml_inference": true,
+ "rolePermissions": ["demo", "manager"]
+ },
+ {
+ "content": "Purpose\n\nThe purpose of this vacation policy is to outline the guidelines and procedures for requesting and taking time off from work for personal and leisure purposes. This policy aims to promote a healthy work-life balance and encourage employees to take time to rest and recharge.\nScope\n\nThis policy applies to all full-time and part-time employees who have completed their probationary period.\nVacation Accrual\n\nFull-time employees accrue vacation time at a rate of [X hours] per month, equivalent to [Y days] per year. Part-time employees accrue vacation time on a pro-rata basis, calculated according to their scheduled work hours.\n\nVacation time will begin to accrue from the first day of employment, but employees are eligible to take vacation time only after completing their probationary period. Unused vacation time will be carried over to the next year, up to a maximum of [Z days]. Any additional unused vacation time will be forfeited.\nVacation Scheduling\n\nEmployees are required to submit vacation requests to their supervisor at least [A weeks] in advance, specifying the start and end dates of their vacation. Supervisors will review and approve vacation requests based on business needs, ensuring adequate coverage during the employee's absence.\n\nEmployees are encouraged to plan their vacations around the company's peak and non-peak periods to minimize disruptions. Vacation requests during peak periods may be subject to limitations and require additional advance notice.\nVacation Pay\n\nEmployees will receive their regular pay during their approved vacation time. Vacation pay will be calculated based on the employee's average earnings over the [B weeks] preceding their vacation.\nUnplanned Absences and Vacation Time\n\nIn the event of an unplanned absence due to illness or personal emergencies, employees may use their accrued vacation time, subject to supervisor approval. Employees must inform their supervisor as soon as possible and provide any required documentation upon their return to work.\nVacation Time and Termination of Employment\n\nIf an employee's employment is terminated, they will be paid out for any unused vacation time, calculated based on their current rate of pay.\nPolicy Review and Updates\n\nThis vacation policy will be reviewed periodically and updated as necessary, taking into account changes in labor laws, business needs, and employee feedback.\nQuestions and Concerns\n\nEmployees are encouraged to direct any questions or concerns about this policy to their supervisor or the HR department.\n",
+ "summary": ": This policy outlines the guidelines and procedures for requesting and taking time off from work for personal and leisure purposes. Full-time employees accrue vacation time at a rate of [X hours] per month, equivalent to [Y days] per year. Vacation requests must be submitted to supervisors at least",
+ "name": "Company Vacation Policy",
+ "url": "https://example.com/sharepoint/msbuilddemo/company-vacation-policy",
+ "created_on": "2018-04-15",
+ "updated_at": "2018-04-16",
+ "category": "sharepoint",
+ "_run_ml_inference": true,
+ "rolePermissions": ["demo", "manager"]
+ },
+
+ {
+ "content": "This career leveling matrix provides a framework for understanding the various roles and responsibilities of Software Engineers, as well as the skills and experience required for each level. This matrix is intended to support employee development, facilitate performance evaluations, and provide a clear career progression path.\nJunior Software Engineer\n\nResponsibilities:\nCollaborate with team members to design, develop, and maintain software applications and components.\nWrite clean, well-structured, and efficient code following established coding standards.\nParticipate in code reviews, providing and receiving constructive feedback.\nTroubleshoot and resolve software defects and issues.\nAssist with the creation of technical documentation.\nContinuously learn and stay up-to-date with new technologies and best practices.\n\nSkills & Experience:\nBachelor\u2019s degree in Computer Science or a related field, or equivalent work experience.\nBasic understanding of software development principles and methodologies.\nProficiency in at least one programming language.\nStrong problem-solving and analytical skills.\nEffective communication and collaboration skills.\nEagerness to learn and grow within the field.\nSenior Software Engineer\n\nResponsibilities:\nDesign, develop, and maintain complex software applications and components.\nLead and mentor junior team members in software development best practices and techniques.\nConduct code reviews and ensure adherence to coding standards and best practices.\nCollaborate with cross-functional teams to define, design, and deliver software solutions.\nIdentify, troubleshoot, and resolve complex software defects and issues.\nContribute to the creation and maintenance of technical documentation.\nEvaluate and recommend new technologies, tools, and practices to improve software quality and efficiency.\n\nSkills & Experience:\nBachelor\u2019s degree in Computer Science or a related field, or equivalent work experience.\n5+ years of software development experience.\nProficiency in multiple programming languages and technologies.\nDemonstrated ability to design and implement complex software solutions.\nStrong leadership, mentoring, and collaboration skills.\nExcellent problem-solving, analytical, and communication skills.\nPrincipal Software Engineer\n\nResponsibilities:\nLead the design, development, and maintenance of large-scale, mission-critical software applications and components.\nProvide technical leadership and mentorship to software engineering teams.\nDrive the adoption of advanced software development practices and technologies.\nCollaborate with product management, architecture, and other stakeholders to define and deliver strategic software initiatives.\nIdentify, troubleshoot, and resolve the most complex software defects and issues.\nCreate and maintain technical documentation, including architectural designs and best practice guidelines.\nRepresent [Company Name] as a thought leader in the software engineering community, including speaking at conferences, publishing articles, and contributing to open-source projects.\n\nSkills & Experience:\nBachelor\u2019s degree in Computer Science or a related field, or equivalent work experience.\n10+ years of software development experience, with a focus on large-scale, mission-critical applications.\nExpertise in multiple programming languages, technologies, and software development methodologies.\nProven ability to lead and mentor high-performing software engineering teams.\nExceptional problem-solving, analytical, and communication skills.\nStrong business acumen and ability to influence decision-making at the executive level.\n\nBy following this career leveling matrix, we aim to support the growth and development of Software Engineers, enabling them to reach their full potential and contribute meaningfully to the success of the organization.\n",
+ "summary": "\nThis career leveling matrix provides a framework for understanding the various roles and responsibilities of Software Engineers, as well as the skills and experience required for each level. It is intended to support employee development, facilitate performance evaluations, and provide a clear career progression path.",
+ "name": "Swe Career Matrix",
+ "url": "https://example.com/sharepoint/msbuilddemo/swe-career-matrix",
+ "created_on": "2018-04-15",
+ "category": "sharepoint",
+ "_run_ml_inference": true,
+ "rolePermissions": ["demo", "manager"]
+ },
+ {
+ "content": "Title: Working with the Sales Team as an Engineer in a Tech Company\n\nIntroduction:\nAs an engineer in a tech company, collaboration with the sales team is essential to ensure the success of the company's products and services. This guidance document aims to provide an overview of how engineers can effectively work with the sales team, fostering a positive and productive working environment.\nUnderstanding the Sales Team's Role:\nThe sales team is responsible for promoting and selling the company's products and services to potential clients. Their role involves establishing relationships with customers, understanding their needs, and ensuring that the offered solutions align with their requirements.\n\nAs an engineer, it is important to understand the sales team's goals and objectives, as this will help you to provide them with the necessary information, tools, and support to successfully sell your company's products and services.\nCommunication:\nEffective communication is key to successfully working with the sales team. Make sure to maintain open lines of communication, and be responsive to their questions and concerns. This includes:\n\na. Attending sales meetings and conference calls when required.\nb. Providing regular product updates and training sessions to the sales team.\nc. Being available to answer technical questions and clarifications.\nCollaboration:\nCollaborate with the sales team in developing and refining sales materials, such as product presentations, demos, and technical documents. This will ensure that the sales team has accurate and up-to-date information to present to clients.\n\nAdditionally, work closely with the sales team on customer projects or product customizations, providing technical guidance, and ensuring that the solutions meet the customer's requirements.\nCustomer Engagement:\nAt times, engineers may be asked to join sales meetings or calls with potential clients to provide technical expertise. In these situations, it is important to:\n\na. Be prepared and understand the customer's needs and pain points.\nb. Clearly explain the technical aspects of the product or solution in a simple language that the customer can understand.\nc. Address any concerns or questions the customer may have.\nContinuous Improvement:\nActively seek feedback from the sales team regarding product performance, customer experiences, and market trends. Use this feedback to identify areas of improvement and collaborate with other engineers to enhance the product or service offerings.\nMutual Respect and Support:\nIt is essential to treat your colleagues in the sales team with respect and professionalism. Recognize and appreciate their efforts in promoting and selling the company's products and services. In turn, the sales team should also respect and appreciate the technical expertise and knowledge of the engineering team.\n\nBy working together, both the engineering and sales teams can contribute to the overall success of the company.\n\nConclusion:\nCollaboration between engineers and the sales team is crucial for a tech company's success. By understanding each other's roles, maintaining effective communication, collaborating on projects, and supporting one another, both teams can work together to achieve the company's goals and ensure customer satisfaction.\n",
+ "summary": ": This guide provides an overview of how engineers can effectively collaborate with the sales team to ensure the success of a tech company. It includes understanding the sales team's role, communicating and collaborating on projects, engaging customers, and providing mutual respect and support.",
+ "name": "Sales Engineering Collaboration",
+ "url": "https://example.com/sharepoint/msbuilddemo/sales-engineering-collaboration",
+ "created_on": "2019-04-15",
+ "category": "sharepoint",
+ "_run_ml_inference": true,
+ "rolePermissions": ["demo", "manager"]
+ },
+ {
+ "content": "Purpose\nThe purpose of this Intellectual Property Policy is to establish guidelines and procedures for the ownership, protection, and utilization of intellectual property generated by employees during their employment. This policy aims to encourage creativity and innovation while ensuring that the interests of both the company and its employees are protected.\n\nScope\nThis policy applies to all employees, including full-time, part-time, temporary, and contract employees.\n\nDefinitions\na. Intellectual Property (IP): Refers to creations of the mind, such as inventions, literary and artistic works, designs, symbols, and images, that are protected by copyright, trademark, patent, or other forms of legal protection.\nb. Company Time: Refers to the time during which an employee is actively engaged in performing their job duties.\nc. Outside Company Time: Refers to the time during which an employee is not engaged in performing their job duties.\n\nOwnership of Intellectual Property\na. Work Generated on Company Time\ni. Any intellectual property created, conceived, or developed by an employee during company time or using company resources, equipment, or facilities shall be considered the property of the Company.\nii. Employees are required to promptly disclose any such intellectual property to their supervisor or the appropriate department head.\nb. Work Generated Outside Company Time\ni. Intellectual property created, conceived, or developed by an employee outside of company time and without the use of company resources, equipment, or facilities shall generally remain the property of the employee.\nii. However, if the intellectual property is directly related to the employee's job responsibilities, or if the employee has used company resources, equipment, or facilities in its creation, it may be considered the property of the Company.\nProtection and Utilization of Intellectual Property\na. The Company shall have the right to protect, license, and commercialize any intellectual property owned by the company as it deems appropriate.\nb. Employees are expected to cooperate with the Company in obtaining any necessary legal protection for intellectual property owned by the company, including by signing any documents or providing any necessary information or assistance.\nConfidentiality\nEmployees are expected to maintain the confidentiality of any intellectual property owned by the Company and not disclose it to any third parties without the express written consent of an authorized representative of the company.\nEmployee Acknowledgment\nAll employees are required to sign an acknowledgment of this Intellectual Property Policy as a condition of their employment with [Company Name]. By signing the acknowledgment, employees agree to abide by the terms of this policy and understand that any violations may result in disciplinary action, up to and including termination of employment.\nPolicy Review\nThis Intellectual Property Policy shall be reviewed periodically and may be amended as necessary to ensure its continued effectiveness and compliance with applicable laws and regulations. Employees will be notified of any significant changes to this policy.\n",
+ "summary": "This Intellectual Property Policy outlines guidelines and procedures for the ownership, protection, and utilization of intellectual property generated by employees during their employment. It establishes the company's ownership of work generated on company time, while recognizing employee ownership of work generated outside of company time without the use of company resources. The policy",
+ "name": "Intellectual Property Policy",
+ "url": "https://example.com/sharepoint/msbuilddemo/intellectual-property-policy",
+ "created_on": "2021-06-15",
+ "category": "sharepoint",
+ "_run_ml_inference": true,
+ "rolePermissions": ["demo", "manager"]
+ },
+
+ {
+ "content": "Code of Conduct\nPurpose\n\nThe purpose of this code of conduct is to establish guidelines for professional and ethical behavior in the workplace. It outlines the principles and values that all employees are expected to uphold in their interactions with colleagues, customers, partners, and other stakeholders.\nScope\n\nThis code of conduct applies to all employees, contractors, and volunteers within the organization, regardless of their role or seniority.\nCore Values\n\nEmployees are expected to adhere to the following core values:\n\na. Integrity: Act honestly, ethically, and in the best interests of the organization at all times.\nb. Respect: Treat all individuals with dignity, courtesy, and fairness, regardless of their background, beliefs, or position.\nc. Accountability: Take responsibility for one's actions and decisions, and be willing to learn from mistakes.\nd. Collaboration: Work cooperatively with colleagues and partners to achieve shared goals and promote a positive work environment.\ne. Excellence: Strive for the highest standards of performance and continuously seek opportunities for improvement.\nCompliance with Laws and Regulations\n\nEmployees must comply with all applicable laws, regulations, and organizational policies in the course of their work. This includes, but is not limited to, employment laws, data protection regulations, and industry-specific guidelines.\nConflicts of Interest\n\nEmployees should avoid situations where their personal interests may conflict with or influence their professional judgment. If a potential conflict of interest arises, employees must disclose it to their supervisor or the appropriate authority within the organization.\nConfidentiality and Information Security\n\nEmployees are responsible for safeguarding the organization's confidential information, as well as any sensitive information entrusted to them by clients, partners, or other third parties. This includes adhering to data protection policies and using secure communication channels.\nHarassment and Discrimination\n\nThe organization is committed to providing a workplace free from harassment, discrimination, and bullying. Employees are expected to treat others with respect and report any incidents of inappropriate behavior to their supervisor or the human resources department.\nHealth and Safety\n\nEmployees must follow all health and safety guidelines and procedures to maintain a safe and healthy work environment. This includes reporting any hazards or unsafe conditions to the appropriate personnel.\nUse of Company Resources\n\nEmployees are expected to use company resources, including time, equipment, and funds, responsibly and for their intended purposes. Misuse or theft of company resources is strictly prohibited.\nReporting Violations\n\nEmployees have a responsibility to report any suspected violations of this code of conduct, as well as any illegal or unethical behavior, to their supervisor or the appropriate authority within the organization. The organization will protect the confidentiality of employees who report violations and will not tolerate retaliation against those who raise concerns.\nConsequences of Non-Compliance\n\nFailure to adhere to this code of conduct may result in disciplinary action, up to and including termination of employment. The organization reserves the right to take legal action against individuals who engage in illegal or unethical conduct.\nPolicy Review and Updates\n\nThis code of conduct will be reviewed periodically and updated as necessary to ensure it remains relevant and effective in promoting ethical behavior and professional standards within the organization.\nQuestions and Concerns\n\nEmployees are encouraged to seek guidance from their supervisor or the human resources department if they have questions or concerns about this code of conduct or its application to specific situations.\n",
+ "summary": "This code of conduct outlines the principles and values that all employees are expected to uphold in their interactions with colleagues, customers, partners, and other stakeholders. It sets out core values such as integrity, respect, accountability, collaboration and excellence. Employees must comply with all applicable laws, regulations, and organizational",
+ "name": "Code Of Conduct",
+ "url": "https://example.com/sharepoint/msbuilddemo/code-of-conduct",
+ "created_on": "2018-01-12",
+ "category": "sharepoint",
+ "_run_ml_inference": true,
+ "rolePermissions": ["demo", "manager"]
+ },
+ {
+ "content": "Content:\nThe purpose of this office pet policy is to outline the guidelines and procedures for bringing pets into the workplace. This policy aims to create a positive and inclusive work environment while ensuring the comfort, safety, and well-being of all employees, visitors, and pets.\nScope\n\nThis policy applies to all employees who wish to bring their pets to the office. Pets covered under this policy include dogs, cats, and other small, non-exotic animals, subject to approval by the HR department.\nPet Approval Process\n\nEmployees must obtain prior approval from their supervisor and the HR department before bringing their pets to the office. The approval process includes:\n\na. Submitting a written request, including a description of the pet, its breed, age, and temperament.\nb. Providing proof of up-to-date vaccinations and any required licenses or permits.\nc. Obtaining written consent from all employees who share the workspace with the pet owner.\n\nThe HR department reserves the right to deny or revoke pet approval based on the specific circumstances or concerns raised by other employees.\nPet Behavior and Supervision\n\nEmployees are responsible for the behavior and well-being of their pets while in the office. Pets must be:\n\na. Well-behaved, non-aggressive, and not disruptive to the work environment.\nb. House-trained and able to eliminate waste in designated areas outside the office.\nc. Kept on a leash or in a secure enclosure when not in the employee's immediate work area.\n\nEmployees must closely supervise their pets and promptly address any issues or concerns raised by other staff members.\nAllergies and Phobias\n\nEmployees with allergies or phobias related to pets must inform the HR department, which will work with the affected employees and pet owners to find a suitable solution. This may include adjusting workspaces, limiting the number or types of pets allowed, or implementing additional safety measures.\nCleanliness and Hygiene\n\nEmployees are responsible for maintaining a clean and hygienic work environment. This includes:\n\na. Cleaning up after their pets, both indoors and outdoors.\nb. Regularly grooming their pets to minimize shedding and odors.\nc. Ensuring their pets are free of pests, such as fleas and ticks.\nLiability\n\nPet owners are liable for any damage or injury caused by their pets. Employees are encouraged to obtain pet liability insurance to cover potential incidents.\nRestricted Areas\n\nPets are not allowed in certain areas of the office, including meeting rooms, restrooms, kitchen and dining areas, and any other designated spaces. Signage will be posted to indicate these restricted areas.\nPolicy Review and Updates\n\nThis office pet policy will be reviewed periodically and updated as necessary, taking into account employee feedback, changes in legislation, and best practices for maintaining a safe and inclusive work environment.\nQuestions and Concerns\n\nEmployees are encouraged to direct any questions or concerns about this policy to their supervisor or the HR department.\n",
+ "summary": "This policy outlines the guidelines and procedures for bringing pets into the workplace. It covers approval process, pet behavior and supervision, allergies and phobias, cleanliness and hygiene, liability, restricted areas, and policy review. Employees must obtain prior approval from their supervisor and the HR department before bringing their",
+ "name": "Office Pet Policy",
+ "url": "https://example.com/sharepoint/msbuilddemo/office-pet-policy",
+ "created_on": "2018-01-12",
+ "category": "sharepoint",
+ "_run_ml_inference": true,
+ "rolePermissions": ["demo", "manager"]
+ },
+ {
+ "content": "Performance Management Policy\nPurpose and Scope\nThe purpose of this Performance Management Policy is to establish a consistent and transparent process for evaluating, recognizing, and rewarding employee performance. This policy applies to all employees and aims to foster a culture of continuous improvement, professional growth, and open communication between employees and management.\nPerformance Planning and Goal Setting\nAt the beginning of each performance cycle, employees and their supervisors will collaborate to set clear, achievable, and measurable performance goals. These goals should align with the company\u2019s strategic objectives and take into account the employee\u2019s job responsibilities, professional development, and career aspirations.\nOngoing Feedback and Communication\nThroughout the performance cycle, employees and supervisors are encouraged to engage in regular, constructive feedback and open communication. This includes discussing progress towards goals, addressing challenges, and identifying opportunities for improvement or additional support. Regular check-ins and updates help ensure that employees stay on track and receive the guidance they need to succeed.\nPerformance Evaluation\nAt the end of each performance cycle, employees will participate in a formal performance evaluation with their supervisor. This evaluation will assess the employee\u2019s overall performance, including their achievements, areas for improvement, and progress towards goals. Both the employee and supervisor should come prepared to discuss specific examples, accomplishments, and challenges from the performance period.\nPerformance Ratings\nBased on the performance evaluation, employees will receive a performance rating that reflects their overall performance during the cycle. The rating system should be clearly defined and consistently applied across the organization. Performance ratings will be used to inform decisions regarding promotions, salary increases, and other rewards or recognition.\nPromotions and Advancements\nHigh-performing employees who consistently demonstrate strong performance, leadership, and a commitment to the company\u2019s values may be considered for promotions or other advancement opportunities. Promotions will be based on factors such as performance ratings, skills, experience, and the needs of the organization. Employees interested in pursuing a promotion should discuss their career goals and development plans with their supervisor.\nPerformance Improvement Plans\nEmployees who receive a low performance rating or are struggling to meet their performance goals may be placed on a Performance Improvement Plan (PIP). A PIP is a structured plan designed to help the employee address specific areas of concern, set achievable improvement goals, and receive additional support or resources as needed. Employees on a PIP will be closely monitored and re-evaluated at the end of the improvement period to determine if satisfactory progress has been made.\nRecognition and Rewards\nOur company believes in recognizing and rewarding employees for their hard work and dedication. In addition to promotions and salary increases, employees may be eligible for other forms of recognition or rewards based on their performance. This may include bonuses, awards, or other incentives designed to motivate and celebrate employee achievements. The specific criteria and eligibility for these rewards will be communicated by the HR department or management.\n",
+ "summary": "This Performance Management Policy outlines a consistent and transparent process for evaluating, recognizing, and rewarding employees. It includes goal setting, ongoing feedback, performance evaluations, ratings, promotions, and rewards. The policy applies to all employees and encourages open communication and professional growth.",
+ "name": "Performance Management Policy",
+ "url": "https://example.com/sharepoint/msbuilddemo/performance-management-policy",
+ "created_on": "2018-01-12",
+ "category": "sharepoint",
+ "_run_ml_inference": true,
+ "rolePermissions": ["demo", "manager"]
+ },
+
+ {
+ "content": "Our sales organization is structured to effectively serve our customers and achieve our business objectives across multiple regions. The organization is divided into the following main regions:\n\nThe Americas: This region includes the United States, Canada, Mexico, as well as Central and South America. The North America South America region (NASA) has two Area Vice-Presidents: Laura Martinez is the Area Vice-President of North America, and Gary Johnson is the Area Vice-President of South America.\n\nEurope: Our European sales team covers the entire continent, including the United Kingdom, Germany, France, Spain, Italy, and other countries. The team is responsible for understanding the unique market dynamics and cultural nuances, enabling them to effectively target and engage with customers across the region. The Area Vice-President for Europe is Rajesh Patel.\nAsia-Pacific: This region encompasses countries such as China, Japan, South Korea, India, Australia, and New Zealand. Our sales team in the Asia-Pacific region works diligently to capitalize on growth opportunities and address the diverse needs of customers in this vast and rapidly evolving market. The Area Vice-President for Asia-Pacific is Mei Li.\nMiddle East & Africa: This region comprises countries across the Middle East and Africa, such as the United Arab Emirates, Saudi Arabia, South Africa, and Nigeria. Our sales team in this region is responsible for navigating the unique market challenges and identifying opportunities to expand our presence and better serve our customers. The Area Vice-President for Middle East & Africa is Jamal Abdi.\n\nEach regional sales team consists of dedicated account managers, sales representatives, and support staff, led by their respective Area Vice-Presidents. They are responsible for identifying and pursuing new business opportunities, nurturing existing client relationships, and ensuring customer satisfaction. The teams collaborate closely with other departments, such as marketing, product development, and customer support, to ensure we consistently deliver high-quality products and services to our clients.\n",
+ "summary": "\nOur sales organization is divided into four regions: The Americas, Europe, Asia-Pacific, and Middle East & Africa. Each region is led by an Area Vice-President and consists of dedicated account managers, sales representatives, and support staff. They collaborate with other departments to ensure the delivery of high",
+ "name": "Sales Organization Overview",
+ "url": "https://example.com/sharepoint/msbuilddemo/sales-organization-overview",
+ "created_on": "2018-01-15",
+ "category": "sharepoint",
+ "_run_ml_inference": true,
+ "rolePermissions": ["demo", "manager"]
+ },
+ {
+ "content": "Introduction:\nThis document outlines the compensation bands strategy for the various teams within our IT company. The goal is to establish a fair and competitive compensation structure that aligns with industry standards, rewards performance, and attracts top talent. By implementing this strategy, we aim to foster employee satisfaction and retention while ensuring the company's overall success.\n\nPurpose:\nThe purpose of this compensation bands strategy is to:\na. Define clear guidelines for salary ranges based on job levels and market benchmarks.\nb. Support equitable compensation practices across different teams.\nc. Encourage employee growth and performance.\nd. Enable effective budgeting and resource allocation.\n\nJob Levels:\nTo establish a comprehensive compensation structure, we have defined distinct job levels within each team. These levels reflect varying degrees of skills, experience, and responsibilities. The levels include:\na. Entry-Level: Employees with limited experience or early career professionals.\nb. Intermediate-Level: Employees with moderate experience and demonstrated competence.\nc. Senior-Level: Experienced employees with advanced skills and leadership capabilities.\nd. Leadership-Level: Managers and team leaders responsible for strategic decision-making.\n\nCompensation Bands:\nBased on the job levels, the following compensation bands have been established:\na. Entry-Level Band: This band encompasses salary ranges for employees in entry-level positions. It aims to provide competitive compensation for individuals starting their careers within the company.\n\nb. Intermediate-Level Band: This band covers salary ranges for employees who have gained moderate experience and expertise in their respective roles. It rewards employees for their growing skill set and contributions.\n\nc. Senior-Level Band: The senior-level band includes salary ranges for experienced employees who have attained advanced skills and have a proven track record of delivering results. It reflects the increased responsibilities and expectations placed upon these individuals.\n\nd. Leadership-Level Band: This band comprises salary ranges for managers and team leaders responsible for guiding and overseeing their respective teams. It considers their leadership abilities, strategic thinking, and the impact they have on the company's success.\n\nMarket Benchmarking:\nTo ensure our compensation remains competitive, regular market benchmarking will be conducted. This involves analyzing industry salary trends, regional compensation data, and market demand for specific roles. The findings will inform periodic adjustments to our compensation bands to maintain alignment with the market.\n\nPerformance-Based Compensation:\nIn addition to the defined compensation bands, we emphasize a performance-based compensation model. Performance evaluations will be conducted regularly, and employees exceeding performance expectations will be eligible for bonuses, incentives, and salary increases. This approach rewards high achievers and motivates employees to excel in their roles.\n\nConclusion:\nBy implementing this compensation bands strategy, our IT company aims to establish fair and competitive compensation practices that align with market standards and foster employee satisfaction. Regular evaluations and market benchmarking will enable us to adapt and refine the strategy to meet the evolving needs of our organization.",
+ "summary": "This document outlines a compensation framework for IT teams. It includes job levels, compensation bands, and performance-based incentives to ensure fair and competitive wages. Regular market benchmarking will be conducted to adjust the bands according to industry trends.",
+ "name": "Compensation Framework For It Teams",
+ "url": "https://example.com/sharepoint/msbuilddemo/compensation-framework-for-it-teams",
+ "created_on": "2018-01-12",
+ "category": "sharepoint",
+ "restricted": true,
+ "_run_ml_inference": true,
+ "rolePermissions": ["manager"]
+ },
+ {
+ "content": "As an employee in Canada, it's essential to understand how to update your tax elections forms to ensure accurate tax deductions from your pay. This guide will help you navigate the process of updating your TD1 Personal Tax Credits Return form.\n\nStep 1: Access the TD1 form\nThe TD1 form is available on the Canada Revenue Agency (CRA) website. Your employer might provide you with a paper copy or a link to the online form. You can access the form directly through the following link: https://www.canada.ca/en/revenue-agency/services/forms-publications/td1-personal-tax-credits-returns.html\n\nStep 2: Choose the correct form version\nYou'll need to fill out the federal TD1 form and, if applicable, the provincial or territorial TD1 form. Select the appropriate version based on your province or territory of residence.\n\nStep 3: Download and open the form\nFor the best experience, download and open the TD1 form in Adobe Reader. If you have visual impairments, consider using the large print version available on the CRA website.\n\nStep 4: Complete the form\nFill out the form by entering your personal information, such as your name, Social Insurance Number (SIN), and address. Then, go through each section to claim any personal tax credits that apply to you. These credits may include:\nBasic personal amount\nAmount for an eligible dependant\nAmount for infirm dependants age 18 or older\nCaregiver amount\nDisability amount\nTuition and education amounts\n\nRead the instructions carefully for each section to ensure you claim the correct amounts.\n\nStep 5: Sign and date the form\nOnce you've completed the form, sign and date it at the bottom.\n\nStep 6: Submit the form to your employer\nSubmit the completed and signed TD1 form to your employer. You can either scan and send it electronically, or provide a printed copy. Your employer will use the information on your TD1 form to calculate the correct amount of tax to be deducted from your pay.\n\nStep 7: Update your TD1 form as needed\nIt's essential to update your TD1 form whenever your personal circumstances change, such as getting married, having a child, or becoming eligible for a new tax credit. Inform your employer of these changes and submit an updated TD1 form to ensure accurate tax deductions.\n\nUpdating your tax elections forms is a crucial step in ensuring the correct tax deductions from your pay as a new employee in Canada. Follow this guide and keep your TD1 form up to date to avoid any discrepancies in your tax filings.\n",
+ "summary": ": This guide gives a step-by-step explanation of how to update your TD1 Personal Tax Credits Return form. Access the form from the CRA website and choose the correct version based on your province or territory of residence. Download and open the form in Adobe Reader, fill out the form by entering",
+ "name": "Updating Your Tax Elections Forms",
+ "url": "./github/Updating Your Tax Elections Forms.txt",
+ "created_on": "2022-12-20",
+ "category": "github",
+ "_run_ml_inference": true,
+ "rolePermissions": ["demo", "manager"]
+ },
+ {
+ "content": "Welcome to our team! We are excited to have you on board and look forward to your valuable contributions. This onboarding guide is designed to help you get started by providing essential information about our policies, procedures, and resources. Please read through this guide carefully and reach out to the HR department if you have any questions.\nIntroduction to Our Company Culture and Values\nOur company is committed to creating a diverse, inclusive, and supportive work environment. We believe that our employees are our most valuable asset and strive to foster a culture of collaboration, innovation, and continuous learning. Our core values include:\nIntegrity: We act ethically and honestly in all our interactions.\nTeamwork: We work together to achieve common goals and support each other's growth.\nExcellence: We strive for the highest quality in our products, services, and relationships.\nInnovation: We encourage creativity and embrace change to stay ahead in the market.\nRespect: We treat each other with dignity and value the unique perspectives of all our colleagues.\nKey Onboarding Steps\nTo ensure a smooth onboarding process, please complete the following steps within your first week:\nAttend orientation: You will be invited to an orientation session to meet your colleagues and learn more about our company's history, mission, and values.\nReview policies and procedures: Familiarize yourself with our employee handbook, which contains important information about our policies and procedures. Please read it thoroughly and adhere to the guidelines.\nComplete required training: You may be required to complete mandatory training sessions, such as safety training or anti-harassment training. Ensure that you attend and complete these sessions as soon as possible.\nUpdating Tax Elections and Documents\nIt is crucial to ensure your tax information is accurate and up-to-date, regardless of the country you work in. Please follow these steps to update your tax elections and documents:\nComplete tax forms: Fill out the necessary tax forms for your country or region, which determine the amount of income tax withheld from your paycheck. You should complete new tax forms if your personal or financial situation changes, such as marriage, divorce, or a change in the number of dependents.\nSubmit regional tax forms: Depending on your location, you may be required to complete additional regional or local tax forms. Check with the HR department to determine which forms are necessary.\nUpdate your address: If you move, make sure to update your address with the HR department to ensure accurate tax reporting.\nBenefits Enrollment\nAs a new employee, you are eligible for various benefits, including health insurance, retirement plans, and paid time off. You will receive detailed information about our benefits package during orientation. To enroll in the benefits, please follow these steps:\nReview benefits options: Carefully review the benefits package and choose the options that best meet your needs.\nComplete enrollment forms: Fill out the necessary forms to enroll in your chosen benefits. Submit these forms to the HR department within 30 days of your start date.\nDesignate beneficiaries: If applicable, designate beneficiaries for your life insurance and retirement plans.\nGetting Settled in Your Workspace\nTo help you feel comfortable and productive in your new workspace, take the following steps:\nSet up your workstation: Organize your desk, chair, and computer according to your preferences. If you require any additional equipment or accommodations, please contact the HR department.\nObtain necessary supplies: Request any necessary office supplies, such as pens, notepads, or folders, from the designated supply area or by contacting the appropriate department.\nFamiliarize yourself with office resources: Locate common areas, such as break rooms, restrooms, and meeting rooms. Familiarize yourself with office equipment, including printers, scanners, and telephones.\n",
+ "summary": "\nThis onboarding guide provides essential information to new employees on our company culture and values, key onboarding steps, tax elections and documents, benefits enrollment, and setting up their workspace.",
+ "name": "New Employee Onboarding Guide",
+ "url": "./github/New Employee Onboarding guide.txt",
+ "created_on": "2018-01-12",
+ "category": "github",
+ "_run_ml_inference": true,
+ "rolePermissions": ["demo", "manager"]
+ }
+]
diff --git a/examples/rag/elastic-chatbot-rag-app/data/index_data.py b/examples/rag/elastic-chatbot-rag-app/data/index_data.py
new file mode 100644
index 00000000..0088da2d
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/data/index_data.py
@@ -0,0 +1,181 @@
+import json
+import os
+from sys import stdout
+import time
+from halo import Halo
+from warnings import warn
+
+from elasticsearch import (
+ ApiError,
+ Elasticsearch,
+ NotFoundError,
+ BadRequestError,
+)
+from elastic_transport._exceptions import ConnectionTimeout
+
+from langchain.docstore.document import Document
+from langchain.text_splitter import RecursiveCharacterTextSplitter
+from langchain_elasticsearch import ElasticsearchStore
+
+# Global variables
+# Modify these if you want to use a different file, index or model
+INDEX = os.getenv("ES_INDEX", "workplace-app-docs")
+FILE = os.getenv("FILE", f"{os.path.dirname(__file__)}/data.json")
+ELASTICSEARCH_URL = os.getenv("ELASTICSEARCH_URL")
+ELASTICSEARCH_USER = os.getenv("ELASTICSEARCH_USER")
+ELASTICSEARCH_PASSWORD = os.getenv("ELASTICSEARCH_PASSWORD")
+ELASTICSEARCH_API_KEY = os.getenv("ELASTICSEARCH_API_KEY")
+ELSER_MODEL = os.getenv("ELSER_MODEL", ".elser_model_2")
+
+if ELASTICSEARCH_USER:
+ es = Elasticsearch(
+ hosts=[ELASTICSEARCH_URL],
+ basic_auth=(ELASTICSEARCH_USER, ELASTICSEARCH_PASSWORD),
+ )
+elif ELASTICSEARCH_API_KEY:
+ es = Elasticsearch(hosts=[ELASTICSEARCH_URL], api_key=ELASTICSEARCH_API_KEY)
+else:
+ raise ValueError("Please provide either ELASTICSEARCH_USER or ELASTICSEARCH_API_KEY")
+
+
+def install_elser():
+ # This script is re-entered on ctrl-c or someone just running it twice.
+ # Hence, both steps need to be careful about being potentially redundant.
+
+ # Step 1: Ensure ELSER_MODEL is defined
+ try:
+ es.ml.get_trained_models(model_id=ELSER_MODEL)
+ except NotFoundError:
+ print(f'"{ELSER_MODEL}" model not available, downloading it now')
+ es.ml.put_trained_model(model_id=ELSER_MODEL, input={"field_names": ["text_field"]})
+
+ while True:
+ status = es.ml.get_trained_models(model_id=ELSER_MODEL, include="definition_status")
+ if status["trained_model_configs"][0]["fully_defined"]:
+ break
+ time.sleep(1)
+
+ # Step 2: Ensure ELSER_MODEL is fully allocated
+ if not is_elser_fully_allocated():
+ try:
+ es.ml.start_trained_model_deployment(model_id=ELSER_MODEL, wait_for="fully_allocated")
+ print(f'"{ELSER_MODEL}" model is deployed')
+ except BadRequestError:
+ # Already started, and likely fully allocated
+ pass
+
+ print(f'"{ELSER_MODEL}" model is ready')
+
+
+def is_elser_fully_allocated():
+ stats = es.ml.get_trained_models_stats(model_id=ELSER_MODEL)
+ deployment_stats = stats["trained_model_stats"][0].get("deployment_stats", {})
+ allocation_status = deployment_stats.get("allocation_status", {})
+ return allocation_status.get("state") == "fully_allocated"
+
+
+def main():
+ install_elser()
+
+ print(f"Loading data from ${FILE}")
+
+ metadata_keys = ["name", "summary", "url", "category", "updated_at"]
+ workplace_docs = []
+ with open(FILE, "rt") as f:
+ for doc in json.loads(f.read()):
+ workplace_docs.append(
+ Document(
+ page_content=doc["content"],
+ metadata={k: doc.get(k) for k in metadata_keys},
+ )
+ )
+
+ print(f"Loaded {len(workplace_docs)} documents")
+
+ text_splitter = RecursiveCharacterTextSplitter.from_tiktoken_encoder(chunk_size=512, chunk_overlap=256)
+
+ docs = text_splitter.transform_documents(workplace_docs)
+
+ print(f"Split {len(workplace_docs)} documents into {len(docs)} chunks")
+
+ print(f"Creating Elasticsearch sparse vector store for {ELASTICSEARCH_URL}")
+
+ store = ElasticsearchStore(
+ es_connection=es,
+ index_name=INDEX,
+ strategy=ElasticsearchStore.SparseVectorRetrievalStrategy(model_id=ELSER_MODEL),
+ )
+
+ # The first call creates ML tasks to support the index, and typically fails
+ # with the default 10-second timeout, at least when Elasticsearch is a
+ # container running on Apple Silicon.
+ #
+ # Once elastic/elasticsearch#107077 is fixed, we can use bulk_kwargs to
+ # adjust the timeout.
+
+ print(f"Adding documents to index {INDEX}")
+
+ if stdout.isatty():
+ spinner = Halo(text="Processing bulk operation", spinner="dots")
+ spinner.start()
+
+ try:
+ es.indices.delete(index=INDEX, ignore_unavailable=True)
+ store.add_documents(list(docs))
+ except BadRequestError:
+ # This error means the index already exists
+ pass
+ except (ConnectionTimeout, ApiError) as e:
+ if isinstance(e, ApiError) and e.status_code != 408:
+ raise
+ warn(f"Error occurred, will retry after ML jobs complete: {e}")
+ await_ml_tasks()
+ es.indices.delete(index=INDEX, ignore_unavailable=True)
+ store.add_documents(list(docs))
+
+ if stdout.isatty():
+ spinner.stop()
+
+ print(f"Documents added to index {INDEX}")
+
+
+def await_ml_tasks(max_timeout=1200, interval=5):
+ """
+ Waits for all machine learning tasks to complete within a specified timeout period.
+
+ Parameters:
+ max_timeout (int): Maximum time to wait for tasks to complete, in seconds.
+ interval (int): Time to wait between status checks, in seconds.
+
+ Raises:
+ TimeoutError: If the timeout is reached and machine learning tasks are still running.
+ """
+ start_time = time.time()
+ ml_tasks = get_ml_tasks()
+ if not ml_tasks:
+ return # likely a lost race on tasks
+
+ print(f"Awaiting {len(ml_tasks)} ML tasks")
+
+ while time.time() - start_time < max_timeout:
+ ml_tasks = get_ml_tasks()
+ if not ml_tasks:
+ return
+ time.sleep(interval)
+
+ raise TimeoutError(f"Timeout reached. ML tasks are still running: {', '.join(ml_tasks)}")
+
+
+def get_ml_tasks():
+ """Return a list of ML task actions from the ES tasks API."""
+ tasks = []
+ resp = es.tasks.list(detailed=True, actions=["cluster:monitor/xpack/ml/*"])
+ for node_info in resp["nodes"].values():
+ for task_info in node_info.get("tasks", {}).values():
+ tasks.append(task_info["action"])
+ return tasks
+
+
+# Unless we run through flask, we can miss critical settings or telemetry signals.
+if __name__ == "__main__":
+ raise RuntimeError("Run via the parent directory: 'flask create-index'")
diff --git a/examples/rag/elastic-chatbot-rag-app/docker-compose.yml b/examples/rag/elastic-chatbot-rag-app/docker-compose.yml
new file mode 100644
index 00000000..5a9e781d
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/docker-compose.yml
@@ -0,0 +1,35 @@
+name: chatbot-rag-app
+
+services:
+ create-index:
+ image: ghcr.io/elastic/elasticsearch-labs/chatbot-rag-app
+ build:
+ context: .
+ container_name: create-index
+ restart: 'no' # no need to re-ingest on successive runs
+ env_file:
+ - .env
+ command: flask create-index
+ volumes:
+ # VertexAI uses a file for GOOGLE_APPLICATION_CREDENTIALS, not an API key
+ - ${HOME}/.config/gcloud:/root/.config/gcloud
+ extra_hosts: # send localhost traffic to the docker host, e.g. your laptop
+ - "localhost:host-gateway"
+
+ api-frontend:
+ depends_on:
+ create-index:
+ condition: service_completed_successfully
+ container_name: api-frontend
+ image: ghcr.io/elastic/elasticsearch-labs/chatbot-rag-app
+ build:
+ context: .
+ env_file:
+ - .env
+ volumes:
+ # VertexAI uses a file for GOOGLE_APPLICATION_CREDENTIALS, not an API key
+ - ${HOME}/.config/gcloud:/root/.config/gcloud
+ ports:
+ - "4000:4000"
+ extra_hosts: # send localhost traffic to the docker host, e.g. your laptop
+ - "localhost:host-gateway"
diff --git a/examples/rag/elastic-chatbot-rag-app/env.example b/examples/rag/elastic-chatbot-rag-app/env.example
new file mode 100644
index 00000000..f016e3e2
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/env.example
@@ -0,0 +1,106 @@
+# Make a copy of this file with the name .env and assign values to variables
+
+# Location of the application routes
+FLASK_APP=api/app.py
+# Ensure print statements appear as they happen
+PYTHONUNBUFFERED=1
+
+# How you connect to Elasticsearch: change details to your instance
+# This defaults to a Elastic Stack accessible via localhost.
+#
+# When running inside Kubernetes, set to http://elasticsearch.default.svc:9200
+# or similar.
+ELASTICSEARCH_URL=http://localhost:9200
+ELASTICSEARCH_USER=elastic
+ELASTICSEARCH_PASSWORD=elastic
+# If running serverless make sure to update the OTEL endpoint
+# ELASTICSEARCH_API_KEY=
+
+# The name of the Elasticsearch indexes
+ES_INDEX=workplace-app-docs
+ES_INDEX_CHAT_HISTORY=workplace-app-docs-chat-history
+
+# Optional if running serverless
+# ELSER_MODEL=.elser_model_2_linux-x86_64
+
+# Uncomment and complete if you want to use OpenAI
+# LLM_TYPE=openai
+# OPENAI_API_KEY=
+# CHAT_MODEL=gpt-4o-mini
+
+# Uncomment and complete if you want to use Azure OpenAI
+# LLM_TYPE=azure
+## "Azure OpenAI Endpoint" in https://oai.azure.com/resource/overview
+# AZURE_OPENAI_ENDPOINT=https://YOUR_RESOURCE_NAME.openai.azure.com/
+## "API key 1 (or 2)" in https://oai.azure.com/resource/overview
+# AZURE_OPENAI_API_KEY=
+## "Inference version" from https://learn.microsoft.com/en-us/azure/ai-services/openai/api-version-deprecation
+# OPENAI_API_VERSION=2024-10-01-preview
+## "Name" from https://oai.azure.com/resource/deployments
+# CHAT_DEPLOYMENT=YOUR_DEPLOYMENT_NAME
+
+# Uncomment and complete if you want to use Bedrock LLM
+# LLM_TYPE=bedrock
+# AWS_ACCESS_KEY_ID=
+# AWS_SECRET_ACCESS_KEY=
+# AWS_DEFAULT_REGION=
+# CHAT_MODEL=amazon.titan-text-lite-v1
+
+# Uncomment and complete if you want to use Vertex AI
+# LLM_TYPE=vertex
+## Project that has the service "aiplatform.googleapis.com" enabled
+# GOOGLE_CLOUD_PROJECT=
+# GOOGLE_CLOUD_REGION=
+# CHAT_MODEL=gemini-1.5-flash-002
+## Needed if you haven't run `gcloud auth application-default login`
+# GOOGLE_APPLICATION_CREDENTIALS=
+
+# Uncomment and complete if you want to use Mistral AI
+# LLM_TYPE=mistral
+## Key in https://console.mistral.ai/api-keys/
+# MISTRAL_API_KEY=
+## 'API Endpoints' from https://docs.mistral.ai/getting-started/models/models_overview/
+# CHAT_MODEL=open-mistral-nemo
+## Only set this if not using the default Mistral base URL
+# MISTRAL_BASE_URL=
+
+# Uncomment and complete if you want to use Cohere
+# LLM_TYPE=cohere
+## Key in https://dashboard.cohere.com/api-keys
+# COHERE_API_KEY=
+# CHAT_MODEL=command-r7b-12-2024
+
+# Set to false, if you want to record logs, traces and metrics.
+OTEL_SDK_DISABLED=true
+
+# Assign the service name that shows up in Kibana
+OTEL_SERVICE_NAME=chatbot-rag-app
+
+# Default to send logs, traces and metrics to an Elastic APM server accessible
+# via localhost.
+#
+# When running inside Kubernetes, set to http://elasticsearch.default.svc:9200
+# or similar.
+OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:8200
+OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
+
+# Change to 'false' to hide prompt and completion content
+OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true
+
+# Export metrics every 3 seconds instead of every minute
+OTEL_METRIC_EXPORT_INTERVAL=3000
+# Export traces every 3 seconds instead of every 5 seconds
+OTEL_BSP_SCHEDULE_DELAY=3000
+# Change to affect behavior of which resources are detected. Note: these
+# choices are specific to the language, in this case Python.
+OTEL_EXPERIMENTAL_RESOURCE_DETECTORS=process_runtime,os,otel,telemetry_distro
+
+# Splunk AO Environment Variables
+SPLUNK_AO_API_KEY=your-splunk-ao-api-key # Your Splunk AO API key.
+SPLUNK_AO_PROJECT=your-splunk-ao-project-name # Your Splunk AO project name.
+SPLUNK_AO_LOG_STREAM=your-splunk-ao-log-stream # The name of the log stream you want to use for logging.
+
+# Provide the console url below if you are using a custom deployment, and not using app.galileo.ai
+# SPLUNK_AO_CONSOLE_URL=your-splunk-ao-console-url # Optional if you are using a hosted version of Splunk AO
+
+
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/.prettierrc.json b/examples/rag/elastic-chatbot-rag-app/frontend/.prettierrc.json
new file mode 100644
index 00000000..fa51da29
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/.prettierrc.json
@@ -0,0 +1,6 @@
+{
+ "trailingComma": "es5",
+ "tabWidth": 2,
+ "semi": false,
+ "singleQuote": true
+}
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/package.json b/examples/rag/elastic-chatbot-rag-app/frontend/package.json
new file mode 100644
index 00000000..544470e9
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/package.json
@@ -0,0 +1,69 @@
+{
+ "name": "chatbot-rag-frontend",
+ "version": "0.1.0",
+ "private": true,
+ "proxy": "http://localhost:3001",
+ "dependencies": {
+ "@microsoft/fetch-event-source": "^2.0.1",
+ "@radix-ui/react-slot": "^1.1.1",
+ "@reduxjs/toolkit": "^2.5.0",
+ "@testing-library/jest-dom": "^6.6.3",
+ "@testing-library/react": "^16.1.0",
+ "@testing-library/user-event": "^14.5.2",
+ "@types/jest": "^29.5.14",
+ "@types/node": "^22.10.2",
+ "@types/react": "^19.0.2",
+ "@types/react-dom": "^19.0.2",
+ "autosize": "^6.0.1",
+ "class-variance-authority": "^0.7.1",
+ "clsx": "^2.1.1",
+ "lucide-react": "^0.468.0",
+ "react": "^19.0.0",
+ "react-dom": "^19.0.0",
+ "react-redux": "^9.2.0",
+ "react-scripts": "^5.0.1",
+ "react-spinners": "^0.15.0",
+ "sass": "^1.83.0",
+ "tailwind-merge": "^2.5.5",
+ "tailwindcss-animate": "^1.0.7",
+ "typescript": "^5.7.2",
+ "use-reducer-async": "^2.1.1",
+ "web-vitals": "^4.2.4"
+ },
+ "scripts": {
+ "start": "react-scripts start",
+ "build": "react-scripts build",
+ "format": "prettier --write .",
+ "test": "react-scripts test",
+ "eject": "react-scripts eject"
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ },
+ "devDependencies": {
+ "@testing-library/dom": "^10.4.0",
+ "@typescript-eslint/eslint-plugin": "^8.18.1",
+ "@typescript-eslint/parser": "^8.18.1",
+ "eslint": "^9.17.0",
+ "eslint-config-airbnb": "^19.0.4",
+ "eslint-config-airbnb-typescript": "^18.0.0",
+ "eslint-config-prettier": "^9.1.0",
+ "eslint-plugin-import": "^2.31.0",
+ "eslint-plugin-jest": "^28.9.0",
+ "eslint-plugin-jsx-a11y": "^6.10.2",
+ "eslint-plugin-prettier": "^5.2.1",
+ "eslint-plugin-react": "^7.37.2",
+ "eslint-plugin-react-hooks": "^5.1.0",
+ "prettier": "^3.4.2",
+ "tailwindcss": "^3.4.17"
+ }
+}
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/public/favicon.ico b/examples/rag/elastic-chatbot-rag-app/frontend/public/favicon.ico
new file mode 100644
index 00000000..9aa824a1
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/public/favicon.ico differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/public/index.html b/examples/rag/elastic-chatbot-rag-app/frontend/public/index.html
new file mode 100644
index 00000000..8aae6905
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/public/index.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Elastic Workplace Sample App
+
+
+ You need to enable JavaScript to run this app.
+
+
+
+
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/public/logo192.png b/examples/rag/elastic-chatbot-rag-app/frontend/public/logo192.png
new file mode 100644
index 00000000..fc44b0a3
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/public/logo192.png differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/public/logo512.png b/examples/rag/elastic-chatbot-rag-app/frontend/public/logo512.png
new file mode 100644
index 00000000..a4e47a65
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/public/logo512.png differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/public/manifest.json b/examples/rag/elastic-chatbot-rag-app/frontend/public/manifest.json
new file mode 100644
index 00000000..080d6c77
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/public/manifest.json
@@ -0,0 +1,25 @@
+{
+ "short_name": "React App",
+ "name": "Create React App Sample",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ },
+ {
+ "src": "logo192.png",
+ "type": "image/png",
+ "sizes": "192x192"
+ },
+ {
+ "src": "logo512.png",
+ "type": "image/png",
+ "sizes": "512x512"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/public/robots.txt b/examples/rag/elastic-chatbot-rag-app/frontend/public/robots.txt
new file mode 100644
index 00000000..e9e57dc4
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/public/robots.txt
@@ -0,0 +1,3 @@
+# https://www.robotstxt.org/robotstxt.html
+User-agent: *
+Disallow:
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/App.test.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/App.test.tsx
new file mode 100644
index 00000000..b7d0ba26
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/App.test.tsx
@@ -0,0 +1,10 @@
+import React from 'react'
+import { render, screen } from '@testing-library/react'
+import '@testing-library/jest-dom'
+import App from './App'
+
+test('renders learn react link', () => {
+ render( )
+ const linkElement = screen.getByText(/learn react/i)
+ expect(linkElement).toBeInTheDocument()
+})
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/App.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/App.tsx
new file mode 100644
index 00000000..8c3f04eb
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/App.tsx
@@ -0,0 +1,122 @@
+import React, { useState } from 'react'
+
+import {
+ actions,
+ AppStatus,
+ thunkActions,
+ useAppDispatch,
+ useAppSelector,
+} from 'store/provider'
+import { Header } from 'components/header'
+import { Chat } from 'components/chat/chat'
+import SearchInput from 'components/search_input'
+import { ReactComponent as ChatIcon } from 'images/chat_icon.svg'
+import { ReactComponent as ElasticLogo } from 'images/elastic_logo.svg'
+import { SearchResults } from './components/search_results'
+
+const App = () => {
+ const dispatch = useAppDispatch()
+ const status = useAppSelector((state) => state.status)
+ const sources = useAppSelector((state) => state.sources)
+ const [summary, ...messages] = useAppSelector((state) => state.conversation)
+ const hasSummary = useAppSelector(
+ (state) => !!state.conversation?.[0]?.content
+ )
+ const [searchQuery, setSearchQuery] = useState('')
+
+ const handleSearch = (query: string) => {
+ dispatch(thunkActions.search(query))
+ }
+ const handleSendChatMessage = (query: string) => {
+ dispatch(thunkActions.askQuestion(query))
+ }
+ const handleAbortRequest = () => {
+ dispatch(thunkActions.abortRequest())
+ }
+ const handleToggleSource = (name) => {
+ dispatch(actions.sourceToggle({ name }))
+ }
+ const handleSourceClick = (name) => {
+ dispatch(actions.sourceToggle({ name, expanded: true }))
+
+ setTimeout(() => {
+ document
+ .querySelector(`[data-source="${name}"]`)
+ ?.scrollIntoView({ behavior: 'smooth' })
+ }, 300)
+ }
+
+ const suggestedQueries = [
+ 'What is our work from home policy?',
+ "What's the NASA sales team?",
+ 'Does the company own my side project?',
+ 'What job openings do we have?',
+ 'How does compensation work?',
+ ]
+
+ return (
+ <>
+
+
+
+
+
+ {status === AppStatus.Idle ? (
+
+
+ Common questions
+
+
+ {suggestedQueries.map((query) => (
+ {
+ e.preventDefault()
+ setSearchQuery(query)
+ handleSearch(query)
+ }}
+ >
+ {query}
+
+ ))}
+
+
+ ) : (
+ <>
+ {hasSummary ? (
+
+
+
+
+
+ ) : (
+
+
+
+ Looking that up for you...
+
+
+ )}
+ >
+ )}
+
+ >
+ )
+}
+
+export default App
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/components/chat/answer_message.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/chat/answer_message.tsx
new file mode 100644
index 00000000..d615e26a
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/chat/answer_message.tsx
@@ -0,0 +1,45 @@
+import { Sources } from './sources'
+import { ChatMessageType } from '../../types'
+
+interface AnswerMessageProps {
+ text: ChatMessageType['content']
+ sources: ChatMessageType['sources']
+ onSourceClick: (source: string) => void
+}
+
+export const AnswerMessage: React.FC = ({
+ text,
+ sources,
+ onSourceClick,
+}) => {
+ return (
+
+
+
+
+
+ Answer
+
+
+ Powered by Elasticsearch
+
+
+
+
+
+ {text && (
+
+ )}
+ {sources && (
+
+ )}
+
+ )
+}
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/components/chat/chat.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/chat/chat.tsx
new file mode 100644
index 00000000..4a9bbee6
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/chat/chat.tsx
@@ -0,0 +1,57 @@
+import { cn } from 'lib/utils'
+import { AppStatus } from 'store/provider'
+import ChatInput from 'components/chat/input'
+import { AnswerMessage } from 'components/chat/answer_message'
+import { ChatMessageList } from 'components/chat/message_list'
+import { ChatMessageType } from 'types'
+
+interface ChatProps {
+ status: AppStatus
+ messages: ChatMessageType[]
+ summary: ChatMessageType
+ onSend: (message: string) => void
+ onAbortRequest: () => void
+ onSourceClick: (sourceName: string) => void
+}
+
+export const Chat: React.FC = ({
+ status,
+ messages,
+ summary,
+ onSend,
+ onAbortRequest,
+ onSourceClick,
+}) => (
+
+
+
+
+ {!!messages.length && (
+ <>
+
+
+ >
+ )}
+
+
+
+
+)
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/components/chat/input.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/chat/input.tsx
new file mode 100644
index 00000000..5060b870
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/chat/input.tsx
@@ -0,0 +1,92 @@
+import {
+ ChangeEvent,
+ FormEvent,
+ KeyboardEvent,
+ useLayoutEffect,
+ useRef,
+ useState,
+} from 'react'
+import autosize from 'autosize'
+import { cn } from 'lib/utils'
+import Conversation from 'images/conversation'
+import { ReactComponent as SendIcon } from 'images/paper_airplane_icon.svg'
+import { ReactComponent as StopIcon } from 'images/stop_icon.svg'
+
+export default function ChatInput({
+ isMessageLoading,
+ onSubmit,
+ onAbortRequest,
+}) {
+ const [message, setMessage] = useState()
+ const textareaReference = useRef(null)
+ const isSubmitDisabled =
+ !message || message.trim().length === 0 || isMessageLoading
+
+ const handleSubmit = (event?: FormEvent) => {
+ event?.preventDefault()
+
+ if (!isSubmitDisabled) {
+ onSubmit(message)
+
+ setMessage('')
+ autosize(textareaReference.current)
+ }
+ }
+ const onChange = (event: ChangeEvent) => {
+ autosize(textareaReference.current)
+ setMessage(event.target.value)
+ }
+ const handleKeyDown = (event: KeyboardEvent) => {
+ if (event.key === 'Enter' && !event.shiftKey) {
+ event.preventDefault()
+ handleSubmit()
+ }
+ }
+
+ useLayoutEffect(() => {
+ const ref = textareaReference?.current
+
+ ref?.focus()
+ autosize(ref)
+
+ return () => {
+ autosize.destroy(ref)
+ }
+ }, [])
+
+ return (
+
+ )
+}
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/components/chat/message.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/chat/message.tsx
new file mode 100644
index 00000000..c3dd8cca
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/chat/message.tsx
@@ -0,0 +1,55 @@
+import React from 'react'
+import { ChatMessageType, SourceType } from 'types'
+import { Loader } from 'components/loader'
+import { Sources } from 'components/chat/sources'
+import { ReactComponent as UserLogo } from 'images/user.svg'
+import { ReactComponent as ElasticLogo } from 'images/elastic_logo.svg'
+
+type ChatMessageProps = Omit & {
+ onSourceClick: (source: string) => void
+}
+export const ChatMessage: React.FC = ({
+ content,
+ isHuman,
+ sources,
+ loading,
+ onSourceClick,
+}) => {
+ const messageIcon = isHuman ? (
+
+
+
+ ) : (
+
+
+
+ )
+
+ return (
+
+
+ {messageIcon}
+
+
+
+ {loading && }
+
+
+ {!!sources?.length && (
+
+ {messageIcon}
+
+
+ )}
+
+ )
+}
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/components/chat/message_list.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/chat/message_list.tsx
new file mode 100644
index 00000000..6c4b8405
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/chat/message_list.tsx
@@ -0,0 +1,56 @@
+import React, { useEffect, useRef, useState } from 'react'
+import { ChatMessage } from './message'
+import { ChatMessageType } from 'types'
+
+type ChatMessageListType = {
+ messages: ChatMessageType[]
+ isMessageLoading: boolean
+ onSourceClick: (source: string) => void
+}
+export const ChatMessageList: React.FC = ({
+ messages,
+ isMessageLoading,
+ onSourceClick,
+}) => {
+ const containerRef = useRef(null)
+ const [userScrolled, setUserScrolled] = useState(false)
+
+ useEffect(() => {
+ const container = containerRef.current
+ // Scroll to bottom when new messages come in and the user hasn't scrolled up
+ if (container && !userScrolled) {
+ container.scrollTop = container.scrollHeight
+ }
+ }, [messages, userScrolled])
+
+ const handleScroll = () => {
+ const container = containerRef.current
+ // Check if the user has scrolled up
+ if (container) {
+ const { scrollTop, clientHeight, scrollHeight } = container
+ const isAtBottom = scrollTop + clientHeight >= scrollHeight
+ setUserScrolled(!isAtBottom)
+ }
+ }
+
+ return (
+
+ {messages.map((message, index) => (
+
+ ))}
+
+ )
+}
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/components/chat/sources.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/chat/sources.tsx
new file mode 100644
index 00000000..a63ab1ac
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/chat/sources.tsx
@@ -0,0 +1,35 @@
+import { SourceItem } from '../source_item'
+import { SourceType } from 'types'
+
+export type SourcesProps = {
+ sources: SourceType[]
+ showDisclaimer?: boolean
+ onSourceClick: (source: string) => void
+}
+export const Sources: React.FC = ({
+ sources,
+ showDisclaimer,
+ onSourceClick,
+}) => {
+ return (
+ (sources.length > 0 && (
+ <>
+ {showDisclaimer && (
+ Sourced from
+ )}
+
+
+ {sources.map((source) => (
+
+ ))}
+
+ >
+ )) ||
+ null
+ )
+}
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/components/header.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/header.tsx
new file mode 100644
index 00000000..c8c3af01
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/header.tsx
@@ -0,0 +1,11 @@
+import elasticTypeMark from 'images/elasticTypeMark.png'
+
+export const Header = () => (
+
+)
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/components/loader.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/loader.tsx
new file mode 100644
index 00000000..200d103a
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/loader.tsx
@@ -0,0 +1,13 @@
+import { BeatLoader } from 'react-spinners'
+
+export const Loader = ({
+ className,
+ size = 7,
+}: {
+ className?: string
+ size?: number
+}) => (
+
+
+
+)
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/components/search_input.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/search_input.tsx
new file mode 100644
index 00000000..135bc991
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/search_input.tsx
@@ -0,0 +1,59 @@
+import { ChangeEvent, FormEvent, useEffect, useState } from 'react'
+import { ReactComponent as RefreshIcon } from 'images/refresh_icon.svg'
+import { ReactComponent as SearchIcon } from 'images/search_icon.svg'
+import { ReactComponent as ArrowIcon } from 'images/arrow_icon.svg'
+import { AppStatus } from 'store/provider'
+
+export default function SearchInput({ onSearch, value, appStatus }) {
+ const [query, setQuery] = useState(value)
+ const handleSubmit = (event: FormEvent) => {
+ event.preventDefault()
+ if (!!query.length) {
+ onSearch(query)
+ }
+ }
+ const handleChange = (event: ChangeEvent) =>
+ setQuery(event.target.value)
+
+ useEffect(() => {
+ setQuery(value)
+ }, [value])
+
+ return (
+
+
+
+
+
+
+ {appStatus === AppStatus.Idle ? (
+
+
+
+ ) : (
+
+
+
+
+ Start over
+
+ )}
+
+
+ )
+}
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/components/search_result.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/search_result.tsx
new file mode 100644
index 00000000..c237f604
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/search_result.tsx
@@ -0,0 +1,97 @@
+import React, { useEffect, useRef, useState } from 'react'
+import { SourceIcon } from './source_icon'
+import { SourceType } from '../types'
+import { ReactComponent as ArrowDown } from 'images/chevron_down_icon.svg'
+
+interface SearchResultProps extends SourceType {
+ toggleSource: (source: string) => void
+}
+
+const TITLE_HEIGHT = 59
+
+export const SearchResult: React.FC = ({
+ name,
+ icon,
+ url,
+ summary,
+ updated_at,
+ expanded,
+ toggleSource,
+}) => {
+ const ref = useRef(null)
+ const [blockHeight, setBlockHeight] = useState(0)
+
+ // Prevent expand when click is on link
+ const onToggle = (event) => !event.target.href && toggleSource(name)
+
+ useEffect(() => {
+ const blockHeight = ref.current?.clientHeight
+
+ if (blockHeight) {
+ setBlockHeight(blockHeight)
+ }
+ }, [summary])
+
+ const updatedAtDate = new Date(updated_at || '')
+
+ return (
+
+
+
+
+
+
+ URL
+
+
+ {url}
+
+ {summary?.map((text, index) => (
+
+
+ Snippet
+
+
+ ...{text}
+
+
+ ))}
+
+
+ {updated_at && (
+
+ {`UPDATED ${updatedAtDate.toLocaleDateString('common', {
+ month: 'short',
+ })} ${updatedAtDate.toLocaleDateString('common', {
+ day: 'numeric',
+ })}, ${updatedAtDate.getFullYear()}`}
+
+ )}
+
+ )
+}
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/components/search_results.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/search_results.tsx
new file mode 100644
index 00000000..c7355a06
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/search_results.tsx
@@ -0,0 +1,31 @@
+import React, { Fragment } from 'react'
+import { ReactComponent as LightBulb } from 'images/light_bulb_icon.svg'
+import { SourceType } from '../types'
+import { SourceIcon } from './source_icon'
+import { SearchResult } from './search_result'
+
+interface SearchResultsProps {
+ results: SourceType[]
+ toggleSource: (source: string) => void
+}
+
+export const SearchResults: React.FC = ({
+ results,
+ toggleSource,
+}) =>
+ !!results?.length ? (
+ <>
+
+ Search results
+
+
+ {results?.map((result) => (
+
+ ))}
+
+ >
+ ) : null
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/components/source_icon.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/source_icon.tsx
new file mode 100644
index 00000000..239a361d
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/source_icon.tsx
@@ -0,0 +1,59 @@
+import React from 'react'
+
+import confluence from 'images/confluence.png'
+import docs from 'images/docs.png'
+import dropbox from 'images/dropbox.png'
+import excel from 'images/excel.png'
+import onedrive from 'images/onedrive.png'
+import pdf from 'images/pdf.png'
+import github from 'images/github.png'
+import sharepoint from 'images/sharepoint.png'
+import sheets from 'images/sheets.png'
+import slides from 'images/slides.png'
+import teams from 'images/teams.png'
+import sql_server from 'images/sql server.png'
+import word from 'images/word.png'
+import faq from 'images/faq.png'
+
+export type SourceIconType = {
+ className?: string
+ icon:
+ | 'confluence'
+ | 'docs'
+ | 'dropbox'
+ | 'excel'
+ | 'onedrive'
+ | 'pdf'
+ | 'sharepoint'
+ | 'sheets'
+ | 'slides'
+ | 'teams'
+ | 'sql_server'
+ | 'word'
+ | 'github'
+ | 'faq'
+ | string
+}
+export const SourceIcon: React.FC = ({ className, icon }) => {
+ const iconNameToImageMap = {
+ confluence,
+ docs,
+ dropbox,
+ excel,
+ onedrive,
+ pdf,
+ sharepoint,
+ sheets,
+ slides,
+ teams,
+ sql_server,
+ word,
+ github,
+ faq,
+ }
+ return (
+
+
+
+ )
+}
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/components/source_item.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/source_item.tsx
new file mode 100644
index 00000000..998fdade
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/components/source_item.tsx
@@ -0,0 +1,24 @@
+import React from 'react'
+import { SourceIcon } from './source_icon'
+
+export type SourceProps = {
+ name: string
+ icon: string
+ onSourceClick: (sourceName: string) => void
+}
+
+export const SourceItem: React.FC = ({
+ name,
+ icon,
+ onSourceClick,
+}) => (
+ {
+ onSourceClick(name)
+ }}
+ className="hover:text-blue-600 hover:border-blue-500 inline-flex gap-2 items-center cursor-pointer px-4 py-3 border-2 rounded-md border-blue-300 text-blue-500 font-medium"
+ >
+
+ {name}
+
+)
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/arrow_icon.svg b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/arrow_icon.svg
new file mode 100644
index 00000000..afa31223
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/arrow_icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/bug.svg b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/bug.svg
new file mode 100644
index 00000000..2fa0c3c2
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/bug.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/bug.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/bug.tsx
new file mode 100644
index 00000000..06f5a20d
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/bug.tsx
@@ -0,0 +1,21 @@
+export const Bug = () => (
+
+
+
+
+
+
+
+
+
+
+)
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/chat_icon.svg b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/chat_icon.svg
new file mode 100644
index 00000000..54246be1
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/chat_icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/chevron_down_icon.svg b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/chevron_down_icon.svg
new file mode 100644
index 00000000..a161522f
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/chevron_down_icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/confluence.png b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/confluence.png
new file mode 100644
index 00000000..00406ab3
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/confluence.png differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/conversation.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/conversation.tsx
new file mode 100644
index 00000000..e5a1ea20
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/conversation.tsx
@@ -0,0 +1,14 @@
+export default () => (
+
+
+
+)
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/disappointed.svg b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/disappointed.svg
new file mode 100644
index 00000000..c8c3721a
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/disappointed.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/disappointed.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/disappointed.tsx
new file mode 100644
index 00000000..12a56d25
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/disappointed.tsx
@@ -0,0 +1,21 @@
+export const Disappointed = () => (
+
+
+
+
+
+
+
+
+
+
+)
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/docs.png b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/docs.png
new file mode 100644
index 00000000..1d022a70
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/docs.png differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/dropbox.png b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/dropbox.png
new file mode 100644
index 00000000..1d96c90c
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/dropbox.png differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/elasticTypeMark.png b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/elasticTypeMark.png
new file mode 100644
index 00000000..9ec51e43
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/elasticTypeMark.png differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/elastic_logo.png b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/elastic_logo.png
new file mode 100644
index 00000000..8f755b20
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/elastic_logo.png differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/elastic_logo.svg b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/elastic_logo.svg
new file mode 100644
index 00000000..00168c9d
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/elastic_logo.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/excel.png b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/excel.png
new file mode 100644
index 00000000..61b23076
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/excel.png differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/faq.png b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/faq.png
new file mode 100644
index 00000000..80e8f763
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/faq.png differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/github.png b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/github.png
new file mode 100644
index 00000000..1d022a70
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/github.png differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/light_bulb_icon.svg b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/light_bulb_icon.svg
new file mode 100644
index 00000000..db3cbd21
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/light_bulb_icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/neutral.svg b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/neutral.svg
new file mode 100644
index 00000000..ca65293a
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/neutral.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/neutral.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/neutral.tsx
new file mode 100644
index 00000000..051ba5c7
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/neutral.tsx
@@ -0,0 +1,21 @@
+export const Neutral = () => (
+
+
+
+
+
+
+
+
+
+
+)
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/onedrive.png b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/onedrive.png
new file mode 100644
index 00000000..6adb223d
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/onedrive.png differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/paper_airplane_icon.svg b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/paper_airplane_icon.svg
new file mode 100644
index 00000000..aa43cddc
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/paper_airplane_icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/pdf.png b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/pdf.png
new file mode 100644
index 00000000..02348bde
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/pdf.png differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/refresh_icon.svg b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/refresh_icon.svg
new file mode 100644
index 00000000..7ef12b9e
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/refresh_icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/robot-avatar.png b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/robot-avatar.png
new file mode 100644
index 00000000..051fced7
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/robot-avatar.png differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/search_icon.svg b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/search_icon.svg
new file mode 100644
index 00000000..7c1c4baa
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/search_icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/sharepoint.png b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/sharepoint.png
new file mode 100644
index 00000000..35594c91
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/sharepoint.png differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/sheets.png b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/sheets.png
new file mode 100644
index 00000000..1c752667
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/sheets.png differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/slides.png b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/slides.png
new file mode 100644
index 00000000..ca7fc6bc
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/slides.png differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/smile.svg b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/smile.svg
new file mode 100644
index 00000000..b1a4716c
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/smile.svg
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/smile.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/smile.tsx
new file mode 100644
index 00000000..77f12827
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/smile.tsx
@@ -0,0 +1,21 @@
+export const Smile = () => (
+
+
+
+
+
+
+
+
+
+
+)
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/sql server.png b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/sql server.png
new file mode 100644
index 00000000..57debd65
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/sql server.png differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/stop_icon.svg b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/stop_icon.svg
new file mode 100644
index 00000000..8a84be03
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/stop_icon.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/teams.png b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/teams.png
new file mode 100644
index 00000000..0c24a79e
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/teams.png differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/user.svg b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/user.svg
new file mode 100644
index 00000000..6d0ee8c5
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/user.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/images/word.png b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/word.png
new file mode 100644
index 00000000..bcf3b979
Binary files /dev/null and b/examples/rag/elastic-chatbot-rag-app/frontend/src/images/word.png differ
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/index.css b/examples/rag/elastic-chatbot-rag-app/frontend/src/index.css
new file mode 100644
index 00000000..9b9dc805
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/index.css
@@ -0,0 +1,18 @@
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
+
+body {
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
+ sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ @apply bg-gray-100;
+}
+
+code {
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
+ monospace;
+}
\ No newline at end of file
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/index.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/index.tsx
new file mode 100644
index 00000000..44baac3c
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/index.tsx
@@ -0,0 +1,12 @@
+import React from 'react'
+import ReactDOM from 'react-dom/client'
+import './index.css'
+import App from './App'
+import { GlobalStateProvider } from './store/provider'
+
+const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
+root.render(
+
+
+
+)
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/lib/utils.ts b/examples/rag/elastic-chatbot-rag-app/frontend/src/lib/utils.ts
new file mode 100644
index 00000000..fed2fe91
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/lib/utils.ts
@@ -0,0 +1,6 @@
+import { clsx, type ClassValue } from 'clsx'
+import { twMerge } from 'tailwind-merge'
+
+export function cn(...inputs: ClassValue[]) {
+ return twMerge(clsx(inputs))
+}
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/logo.svg b/examples/rag/elastic-chatbot-rag-app/frontend/src/logo.svg
new file mode 100644
index 00000000..9dfc1c05
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/store/provider.tsx b/examples/rag/elastic-chatbot-rag-app/frontend/src/store/provider.tsx
new file mode 100644
index 00000000..b3637540
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/store/provider.tsx
@@ -0,0 +1,315 @@
+import type { TypedUseSelectorHook } from 'react-redux'
+import { Provider, useDispatch, useSelector } from 'react-redux'
+import { fetchEventSource } from '@microsoft/fetch-event-source'
+import { configureStore, createSlice } from '@reduxjs/toolkit'
+import { SourceType, ChatMessageType } from 'types'
+
+type GlobalStateType = {
+ status: AppStatus
+ conversation: ChatMessageType[]
+ sources: SourceType[]
+ sessionId: string | null
+}
+
+class RetriableError extends Error {}
+class FatalError extends Error {}
+export enum AppStatus {
+ Idle = 'idle',
+ StreamingMessage = 'loading',
+ Done = 'done',
+ Error = 'error',
+}
+enum STREAMING_EVENTS {
+ SESSION_ID = '[SESSION_ID]',
+ SOURCE = '[SOURCE]',
+ DONE = '[DONE]',
+}
+
+const GLOBAL_STATE: GlobalStateType = {
+ status: AppStatus.Idle,
+ conversation: [],
+ sessionId: null,
+ sources: [],
+}
+const API_HOST = process.env.REACT_APP_API_HOST || 'http://localhost:3001/api'
+
+let abortController: AbortController | null = null
+const globalSlice = createSlice({
+ name: 'global',
+ initialState: GLOBAL_STATE as GlobalStateType,
+ reducers: {
+ addSource: (state, action) => {
+ const source = action.payload.source
+ const rootSource = state.sources.find((s) => s.name === source.name)
+
+ if (rootSource) {
+ if (!rootSource.summary.find((summary) => summary === source.summary)) {
+ rootSource.summary = [...rootSource.summary, source.summary]
+ }
+ } else {
+ state.sources.push({ ...source, summary: [source.summary] })
+ }
+ },
+ setStatus: (state, action) => {
+ state.status = action.payload.status
+ },
+ setSessionId: (state, action) => {
+ state.sessionId = action.payload.sessionId
+ },
+ addMessage: (state, action) => {
+ state.conversation.push(action.payload.conversation)
+ },
+ updateMessage: (state, action) => {
+ const messageIndex = state.conversation.findIndex(
+ (c) => c.id === action.payload.id
+ )
+
+ if (messageIndex !== -1) {
+ state.conversation[messageIndex] = {
+ ...state.conversation[messageIndex],
+ ...action.payload,
+ }
+ }
+ },
+ setMessageSource: (state, action) => {
+ const message = state.conversation.find((c) => c.id === action.payload.id)
+
+ if (message) {
+ message.sources = action.payload.sources
+ .map((sourceName) =>
+ state.sources.find((stateSource) => stateSource.name === sourceName)
+ )
+ .filter((source) => !!source)
+ }
+ },
+ removeMessage: (state, action) => {
+ const messageIndex = state.conversation.findIndex(
+ (c) => c.id === action.payload.id
+ )
+
+ if (messageIndex !== -1) {
+ state.conversation.splice(messageIndex, 1)
+ }
+ },
+ sourceToggle: (state, action) => {
+ const source = state.sources.find((s) => s.name === action.payload.name)
+
+ if (source) {
+ source.expanded = action.payload.expanded ?? !source.expanded
+ }
+ },
+ reset: (state) => {
+ state.status = AppStatus.Idle
+ state.sessionId = null
+ state.conversation = []
+ state.sources = []
+ },
+ },
+})
+
+const store = configureStore({
+ reducer: globalSlice.reducer,
+})
+
+export type RootState = ReturnType
+export type AppDispatch = typeof store.dispatch
+export const useAppDispatch: () => AppDispatch = useDispatch
+export const useAppSelector: TypedUseSelectorHook = useSelector
+export const actions = globalSlice.actions
+
+export const thunkActions = {
+ search: (query: string) => {
+ return async function fetchSearch(dispatch, getState) {
+ if (getState().status === AppStatus.StreamingMessage) {
+ dispatch(thunkActions.abortRequest())
+ }
+
+ dispatch(actions.reset())
+ dispatch(thunkActions.chat(query))
+ }
+ },
+ askQuestion: (question: string) => {
+ return async function (dispatch, getState) {
+ const state = getState()
+
+ dispatch(
+ actions.addMessage({
+ conversation: {
+ isHuman: true,
+ content: question,
+ id: state.conversation.length + 1,
+ },
+ })
+ )
+ dispatch(thunkActions.chat(question))
+ }
+ },
+ chat: (question: string) => {
+ return async function fetchSearch(dispatch, getState) {
+ abortController = new AbortController()
+ const conversationId = getState().conversation.length + 1
+
+ dispatch(
+ actions.addMessage({
+ conversation: {
+ isHuman: false,
+ content: '',
+ id: conversationId,
+ },
+ })
+ )
+ dispatch(actions.setStatus({ status: AppStatus.StreamingMessage }))
+
+ let countRetiresError = 0
+ let message = ''
+ const sessionId = getState().sessionId
+ const sourcesMap: Map<
+ string,
+ { name: string; url?: string; summary: string[] }
+ > = new Map()
+
+ await fetchEventSource(
+ `${API_HOST}/chat${sessionId ? `?session_id=${sessionId}` : ''}`,
+ {
+ method: 'POST',
+ openWhenHidden: true,
+ body: JSON.stringify({
+ question,
+ }),
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ signal: abortController.signal,
+ async onmessage(event) {
+ if (event.event === 'FatalError') {
+ throw new FatalError(event.data)
+ }
+
+ if (event.data.startsWith(STREAMING_EVENTS.SESSION_ID)) {
+ const sessionId = event.data.split(' ')[1].trim()
+ dispatch(actions.setSessionId({ sessionId }))
+ } else if (event.data.startsWith(STREAMING_EVENTS.SOURCE)) {
+ const source = event.data.replace(
+ `${STREAMING_EVENTS.SOURCE} `,
+ ''
+ )
+
+ try {
+ if (source) {
+ const parsedSource: {
+ name: string
+ page_content: string
+ url?: string
+ category?: string
+ updated_at?: string | null
+ } = JSON.parse(source.replaceAll('\n', ''))
+
+ if (parsedSource.page_content && parsedSource.name) {
+ dispatch(
+ actions.addSource({
+ source: {
+ name: parsedSource.name,
+ url: parsedSource.url,
+ summary: parsedSource.page_content,
+ icon: parsedSource.category,
+ updated_at: parsedSource.updated_at,
+ },
+ })
+ )
+ }
+ }
+ } catch (e) {
+ console.log('error', source, event.data)
+ console.error(e)
+ }
+ } else if (event.data === STREAMING_EVENTS.DONE) {
+ const sources = parseSources(message)
+ dispatch(
+ actions.setMessageSource({
+ id: conversationId,
+ sources,
+ })
+ )
+
+ dispatch(actions.setStatus({ status: AppStatus.Done }))
+ } else {
+ message += event.data
+
+ dispatch(
+ actions.updateMessage({
+ id: conversationId,
+ content: message.replace(/SOURCES:(.+)*/, ''),
+ })
+ )
+ }
+ },
+ async onopen(response) {
+
+ if (response.ok) {
+ return
+ } else if (
+ response.status >= 400 &&
+ response.status < 500 &&
+ response.status !== 429
+ ) {
+ throw new FatalError()
+ } else {
+ throw new RetriableError()
+ }
+ },
+ onerror(err) {
+
+ if (err instanceof FatalError || countRetiresError > 3) {
+ dispatch(actions.setStatus({ status: AppStatus.Error }))
+
+ throw err
+ } else {
+ countRetiresError++
+ console.error(err)
+ }
+ },
+ }
+ )
+ }
+ },
+ abortRequest: () => {
+ return function (dispatch, getState) {
+ const messages = getState().conversation
+ const lastMessage = messages[getState().conversation.length - 1]
+
+ abortController?.abort()
+ abortController = null
+
+ if (!lastMessage.content) {
+ dispatch(
+ actions.removeMessage({
+ id: lastMessage.id,
+ })
+ )
+ }
+ dispatch(
+ actions.setStatus({
+ status: messages.length ? AppStatus.Done : AppStatus.Idle,
+ })
+ )
+ }
+ },
+}
+
+const parseSources = (
+ message: string
+) => {
+ message = message.replaceAll("\"", "");
+ const match = message.match(/SOURCES:(.+)*/)
+ if (match && match[1]) {
+ return match[1].split(',').map(element => {
+ return element.trim();
+ });
+ }
+ return []
+
+}
+
+export const GlobalStateProvider = ({ children }) => {
+ return {children}
+}
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/types/images.d.ts b/examples/rag/elastic-chatbot-rag-app/frontend/src/types/images.d.ts
new file mode 100644
index 00000000..c661e49f
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/types/images.d.ts
@@ -0,0 +1,3 @@
+declare module '*.jpg'
+declare module '*.png'
+declare module '*.svg'
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/src/types/index.ts b/examples/rag/elastic-chatbot-rag-app/frontend/src/types/index.ts
new file mode 100644
index 00000000..0bca219d
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/src/types/index.ts
@@ -0,0 +1,40 @@
+export interface Facet {
+ name: string
+ entries: {
+ count: number
+ value: string
+ }[]
+}
+
+export interface SearchResponse {
+ results: Result[]
+ facets: Facet[]
+ streaming_id: string
+ conversation_id: string
+}
+
+export interface Result {
+ id: string
+ category: [string]
+ content: [string]
+ summary: [string]
+ name: [string]
+ url: [string]
+}
+
+export type SourceType = {
+ name: string
+ summary: string[]
+ url: string
+ icon: string
+ updated_at?: string | null
+ expanded: boolean
+}
+
+export type ChatMessageType = {
+ id: string
+ content: string
+ isHuman?: boolean
+ loading?: boolean
+ sources?: SourceType[]
+}
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/tailwind.config.js b/examples/rag/elastic-chatbot-rag-app/frontend/tailwind.config.js
new file mode 100644
index 00000000..0b44c60c
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/tailwind.config.js
@@ -0,0 +1,5 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: ['./src/**/*.{js,jsx,ts,tsx}'],
+ plugins: [],
+}
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/tsconfig.json b/examples/rag/elastic-chatbot-rag-app/frontend/tsconfig.json
new file mode 100644
index 00000000..59626c9e
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/tsconfig.json
@@ -0,0 +1,24 @@
+{
+ "compilerOptions": {
+ "baseUrl": "./src",
+ "target": "es5",
+ "lib": ["dom", "dom.iterable", "esnext"],
+ "typeRoots": ["node_modules/@types", "src/types"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "noFallthroughCasesInSwitch": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "resolveJsonModule": true,
+ "isolatedModules": true,
+ "noEmit": true,
+ "noImplicitAny": false,
+ "jsx": "react-jsx",
+ },
+ "include": ["src"],
+ "exclude": ["./node_modules"]
+}
diff --git a/examples/rag/elastic-chatbot-rag-app/frontend/yarn.lock b/examples/rag/elastic-chatbot-rag-app/frontend/yarn.lock
new file mode 100644
index 00000000..3f8f3121
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/frontend/yarn.lock
@@ -0,0 +1,10443 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@adobe/css-tools@^4.4.0":
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.4.1.tgz#2447a230bfe072c1659e6815129c03cf170710e3"
+ integrity sha512-12WGKBQzjUAI4ayyF4IAtfw2QR/IDoqk6jTddXDhtYTJF9ASmoE1zst7cVtP0aL/F1jUJL5r+JxKXKEgHNbEUQ==
+
+"@alloc/quick-lru@^5.2.0":
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/@alloc/quick-lru/-/quick-lru-5.2.0.tgz#7bf68b20c0a350f936915fcae06f58e32007ce30"
+ integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==
+
+"@ampproject/remapping@^2.2.0":
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4"
+ integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==
+ dependencies:
+ "@jridgewell/gen-mapping" "^0.3.5"
+ "@jridgewell/trace-mapping" "^0.3.24"
+
+"@apideck/better-ajv-errors@^0.3.1":
+ version "0.3.6"
+ resolved "https://registry.yarnpkg.com/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.6.tgz#957d4c28e886a64a8141f7522783be65733ff097"
+ integrity sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==
+ dependencies:
+ json-schema "^0.4.0"
+ jsonpointer "^5.0.0"
+ leven "^3.1.0"
+
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.0", "@babel/code-frame@^7.25.9", "@babel/code-frame@^7.26.0", "@babel/code-frame@^7.26.2", "@babel/code-frame@^7.8.3":
+ version "7.26.2"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.26.2.tgz#4b5fab97d33338eff916235055f0ebc21e573a85"
+ integrity sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.25.9"
+ js-tokens "^4.0.0"
+ picocolors "^1.0.0"
+
+"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.25.9", "@babel/compat-data@^7.26.0":
+ version "7.26.3"
+ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.26.3.tgz#99488264a56b2aded63983abd6a417f03b92ed02"
+ integrity sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g==
+
+"@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.12.3", "@babel/core@^7.16.0", "@babel/core@^7.7.2", "@babel/core@^7.8.0":
+ version "7.26.0"
+ resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.26.0.tgz#d78b6023cc8f3114ccf049eb219613f74a747b40"
+ integrity sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==
+ dependencies:
+ "@ampproject/remapping" "^2.2.0"
+ "@babel/code-frame" "^7.26.0"
+ "@babel/generator" "^7.26.0"
+ "@babel/helper-compilation-targets" "^7.25.9"
+ "@babel/helper-module-transforms" "^7.26.0"
+ "@babel/helpers" "^7.26.0"
+ "@babel/parser" "^7.26.0"
+ "@babel/template" "^7.25.9"
+ "@babel/traverse" "^7.25.9"
+ "@babel/types" "^7.26.0"
+ convert-source-map "^2.0.0"
+ debug "^4.1.0"
+ gensync "^1.0.0-beta.2"
+ json5 "^2.2.3"
+ semver "^6.3.1"
+
+"@babel/eslint-parser@^7.16.3":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/eslint-parser/-/eslint-parser-7.25.9.tgz#603c68a63078796527bc9d0833f5e52dd5f9224c"
+ integrity sha512-5UXfgpK0j0Xr/xIdgdLEhOFxaDZ0bRPWJJchRpqOSur/3rZoPbqqki5mm0p4NE2cs28krBEiSM2MB7//afRSQQ==
+ dependencies:
+ "@nicolo-ribaudo/eslint-scope-5-internals" "5.1.1-v1"
+ eslint-visitor-keys "^2.1.0"
+ semver "^6.3.1"
+
+"@babel/generator@^7.26.0", "@babel/generator@^7.26.3", "@babel/generator@^7.7.2":
+ version "7.26.3"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.26.3.tgz#ab8d4360544a425c90c248df7059881f4b2ce019"
+ integrity sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==
+ dependencies:
+ "@babel/parser" "^7.26.3"
+ "@babel/types" "^7.26.3"
+ "@jridgewell/gen-mapping" "^0.3.5"
+ "@jridgewell/trace-mapping" "^0.3.25"
+ jsesc "^3.0.2"
+
+"@babel/helper-annotate-as-pure@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz#d8eac4d2dc0d7b6e11fa6e535332e0d3184f06b4"
+ integrity sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==
+ dependencies:
+ "@babel/types" "^7.25.9"
+
+"@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz#55af025ce365be3cdc0c1c1e56c6af617ce88875"
+ integrity sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==
+ dependencies:
+ "@babel/compat-data" "^7.25.9"
+ "@babel/helper-validator-option" "^7.25.9"
+ browserslist "^4.24.0"
+ lru-cache "^5.1.1"
+ semver "^6.3.1"
+
+"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz#7644147706bb90ff613297d49ed5266bde729f83"
+ integrity sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.25.9"
+ "@babel/helper-member-expression-to-functions" "^7.25.9"
+ "@babel/helper-optimise-call-expression" "^7.25.9"
+ "@babel/helper-replace-supers" "^7.25.9"
+ "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9"
+ "@babel/traverse" "^7.25.9"
+ semver "^6.3.1"
+
+"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.25.9":
+ version "7.26.3"
+ resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.26.3.tgz#5169756ecbe1d95f7866b90bb555b022595302a0"
+ integrity sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.25.9"
+ regexpu-core "^6.2.0"
+ semver "^6.3.1"
+
+"@babel/helper-define-polyfill-provider@^0.6.2", "@babel/helper-define-polyfill-provider@^0.6.3":
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.3.tgz#f4f2792fae2ef382074bc2d713522cf24e6ddb21"
+ integrity sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==
+ dependencies:
+ "@babel/helper-compilation-targets" "^7.22.6"
+ "@babel/helper-plugin-utils" "^7.22.5"
+ debug "^4.1.1"
+ lodash.debounce "^4.0.8"
+ resolve "^1.14.2"
+
+"@babel/helper-member-expression-to-functions@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz#9dfffe46f727005a5ea29051ac835fb735e4c1a3"
+ integrity sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==
+ dependencies:
+ "@babel/traverse" "^7.25.9"
+ "@babel/types" "^7.25.9"
+
+"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz#e7f8d20602ebdbf9ebbea0a0751fb0f2a4141715"
+ integrity sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==
+ dependencies:
+ "@babel/traverse" "^7.25.9"
+ "@babel/types" "^7.25.9"
+
+"@babel/helper-module-transforms@^7.25.9", "@babel/helper-module-transforms@^7.26.0":
+ version "7.26.0"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz#8ce54ec9d592695e58d84cd884b7b5c6a2fdeeae"
+ integrity sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==
+ dependencies:
+ "@babel/helper-module-imports" "^7.25.9"
+ "@babel/helper-validator-identifier" "^7.25.9"
+ "@babel/traverse" "^7.25.9"
+
+"@babel/helper-optimise-call-expression@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz#3324ae50bae7e2ab3c33f60c9a877b6a0146b54e"
+ integrity sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==
+ dependencies:
+ "@babel/types" "^7.25.9"
+
+"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.25.9", "@babel/helper-plugin-utils@^7.8.0":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz#9cbdd63a9443a2c92a725cca7ebca12cc8dd9f46"
+ integrity sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==
+
+"@babel/helper-remap-async-to-generator@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz#e53956ab3d5b9fb88be04b3e2f31b523afd34b92"
+ integrity sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.25.9"
+ "@babel/helper-wrap-function" "^7.25.9"
+ "@babel/traverse" "^7.25.9"
+
+"@babel/helper-replace-supers@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz#ba447224798c3da3f8713fc272b145e33da6a5c5"
+ integrity sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==
+ dependencies:
+ "@babel/helper-member-expression-to-functions" "^7.25.9"
+ "@babel/helper-optimise-call-expression" "^7.25.9"
+ "@babel/traverse" "^7.25.9"
+
+"@babel/helper-skip-transparent-expression-wrappers@^7.20.0", "@babel/helper-skip-transparent-expression-wrappers@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz#0b2e1b62d560d6b1954893fd2b705dc17c91f0c9"
+ integrity sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==
+ dependencies:
+ "@babel/traverse" "^7.25.9"
+ "@babel/types" "^7.25.9"
+
+"@babel/helper-string-parser@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz#1aabb72ee72ed35789b4bbcad3ca2862ce614e8c"
+ integrity sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==
+
+"@babel/helper-validator-identifier@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz#24b64e2c3ec7cd3b3c547729b8d16871f22cbdc7"
+ integrity sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==
+
+"@babel/helper-validator-option@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz#86e45bd8a49ab7e03f276577f96179653d41da72"
+ integrity sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==
+
+"@babel/helper-wrap-function@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz#d99dfd595312e6c894bd7d237470025c85eea9d0"
+ integrity sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==
+ dependencies:
+ "@babel/template" "^7.25.9"
+ "@babel/traverse" "^7.25.9"
+ "@babel/types" "^7.25.9"
+
+"@babel/helpers@^7.26.0":
+ version "7.26.0"
+ resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.0.tgz#30e621f1eba5aa45fe6f4868d2e9154d884119a4"
+ integrity sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==
+ dependencies:
+ "@babel/template" "^7.25.9"
+ "@babel/types" "^7.26.0"
+
+"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.25.9", "@babel/parser@^7.26.0", "@babel/parser@^7.26.3":
+ version "7.26.3"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.26.3.tgz#8c51c5db6ddf08134af1ddbacf16aaab48bac234"
+ integrity sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==
+ dependencies:
+ "@babel/types" "^7.26.3"
+
+"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz#cc2e53ebf0a0340777fff5ed521943e253b4d8fe"
+ integrity sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/traverse" "^7.25.9"
+
+"@babel/plugin-bugfix-safari-class-field-initializer-scope@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz#af9e4fb63ccb8abcb92375b2fcfe36b60c774d30"
+ integrity sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz#e8dc26fcd616e6c5bf2bd0d5a2c151d4f92a9137"
+ integrity sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz#807a667f9158acac6f6164b4beb85ad9ebc9e1d1"
+ integrity sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9"
+ "@babel/plugin-transform-optional-chaining" "^7.25.9"
+
+"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz#de7093f1e7deaf68eadd7cc6b07f2ab82543269e"
+ integrity sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/traverse" "^7.25.9"
+
+"@babel/plugin-proposal-class-properties@^7.16.0":
+ version "7.18.6"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3"
+ integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==
+ dependencies:
+ "@babel/helper-create-class-features-plugin" "^7.18.6"
+ "@babel/helper-plugin-utils" "^7.18.6"
+
+"@babel/plugin-proposal-decorators@^7.16.4":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.25.9.tgz#8680707f943d1a3da2cd66b948179920f097e254"
+ integrity sha512-smkNLL/O1ezy9Nhy4CNosc4Va+1wo5w4gzSZeLe6y6dM4mmHfYOCPolXQPHQxonZCF+ZyebxN9vqOolkYrSn5g==
+ dependencies:
+ "@babel/helper-create-class-features-plugin" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/plugin-syntax-decorators" "^7.25.9"
+
+"@babel/plugin-proposal-nullish-coalescing-operator@^7.16.0":
+ version "7.18.6"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz#fdd940a99a740e577d6c753ab6fbb43fdb9467e1"
+ integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.18.6"
+ "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
+
+"@babel/plugin-proposal-numeric-separator@^7.16.0":
+ version "7.18.6"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz#899b14fbafe87f053d2c5ff05b36029c62e13c75"
+ integrity sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.18.6"
+ "@babel/plugin-syntax-numeric-separator" "^7.10.4"
+
+"@babel/plugin-proposal-optional-chaining@^7.16.0":
+ version "7.21.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz#886f5c8978deb7d30f678b2e24346b287234d3ea"
+ integrity sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.20.2"
+ "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0"
+ "@babel/plugin-syntax-optional-chaining" "^7.8.3"
+
+"@babel/plugin-proposal-private-methods@^7.16.0":
+ version "7.18.6"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz#5209de7d213457548a98436fa2882f52f4be6bea"
+ integrity sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==
+ dependencies:
+ "@babel/helper-create-class-features-plugin" "^7.18.6"
+ "@babel/helper-plugin-utils" "^7.18.6"
+
+"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2":
+ version "7.21.0-placeholder-for-preset-env.2"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703"
+ integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==
+
+"@babel/plugin-syntax-async-generators@^7.8.4":
+ version "7.8.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
+ integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-bigint@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea"
+ integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-class-properties@^7.12.13":
+ version "7.12.13"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10"
+ integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.12.13"
+
+"@babel/plugin-syntax-class-static-block@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406"
+ integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.14.5"
+
+"@babel/plugin-syntax-decorators@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.25.9.tgz#986b4ca8b7b5df3f67cee889cedeffc2e2bf14b3"
+ integrity sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-syntax-flow@^7.25.9":
+ version "7.26.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.26.0.tgz#96507595c21b45fccfc2bc758d5c45452e6164fa"
+ integrity sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-syntax-import-assertions@^7.26.0":
+ version "7.26.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.26.0.tgz#620412405058efa56e4a564903b79355020f445f"
+ integrity sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-syntax-import-attributes@^7.24.7", "@babel/plugin-syntax-import-attributes@^7.26.0":
+ version "7.26.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz#3b1412847699eea739b4f2602c74ce36f6b0b0f7"
+ integrity sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-syntax-import-meta@^7.10.4":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51"
+ integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-syntax-json-strings@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a"
+ integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-jsx@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz#a34313a178ea56f1951599b929c1ceacee719290"
+ integrity sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-syntax-logical-assignment-operators@^7.10.4":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699"
+ integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9"
+ integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-numeric-separator@^7.10.4":
+ version "7.10.4"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97"
+ integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-syntax-object-rest-spread@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871"
+ integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-optional-catch-binding@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1"
+ integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-optional-chaining@^7.8.3":
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a"
+ integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-private-property-in-object@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad"
+ integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.14.5"
+
+"@babel/plugin-syntax-top-level-await@^7.14.5":
+ version "7.14.5"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c"
+ integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.14.5"
+
+"@babel/plugin-syntax-typescript@^7.25.9", "@babel/plugin-syntax-typescript@^7.7.2":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz#67dda2b74da43727cf21d46cf9afef23f4365399"
+ integrity sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-syntax-unicode-sets-regex@^7.18.6":
+ version "7.18.6"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357"
+ integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.18.6"
+ "@babel/helper-plugin-utils" "^7.18.6"
+
+"@babel/plugin-transform-arrow-functions@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz#7821d4410bee5daaadbb4cdd9a6649704e176845"
+ integrity sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-async-generator-functions@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz#1b18530b077d18a407c494eb3d1d72da505283a2"
+ integrity sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/helper-remap-async-to-generator" "^7.25.9"
+ "@babel/traverse" "^7.25.9"
+
+"@babel/plugin-transform-async-to-generator@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz#c80008dacae51482793e5a9c08b39a5be7e12d71"
+ integrity sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==
+ dependencies:
+ "@babel/helper-module-imports" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/helper-remap-async-to-generator" "^7.25.9"
+
+"@babel/plugin-transform-block-scoped-functions@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz#5700691dbd7abb93de300ca7be94203764fce458"
+ integrity sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-block-scoping@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz#c33665e46b06759c93687ca0f84395b80c0473a1"
+ integrity sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-class-properties@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz#a8ce84fedb9ad512549984101fa84080a9f5f51f"
+ integrity sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==
+ dependencies:
+ "@babel/helper-create-class-features-plugin" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-class-static-block@^7.26.0":
+ version "7.26.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.26.0.tgz#6c8da219f4eb15cae9834ec4348ff8e9e09664a0"
+ integrity sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==
+ dependencies:
+ "@babel/helper-create-class-features-plugin" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-classes@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz#7152457f7880b593a63ade8a861e6e26a4469f52"
+ integrity sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.25.9"
+ "@babel/helper-compilation-targets" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/helper-replace-supers" "^7.25.9"
+ "@babel/traverse" "^7.25.9"
+ globals "^11.1.0"
+
+"@babel/plugin-transform-computed-properties@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz#db36492c78460e534b8852b1d5befe3c923ef10b"
+ integrity sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/template" "^7.25.9"
+
+"@babel/plugin-transform-destructuring@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz#966ea2595c498224340883602d3cfd7a0c79cea1"
+ integrity sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-dotall-regex@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz#bad7945dd07734ca52fe3ad4e872b40ed09bb09a"
+ integrity sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-duplicate-keys@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz#8850ddf57dce2aebb4394bb434a7598031059e6d"
+ integrity sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-duplicate-named-capturing-groups-regex@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz#6f7259b4de127721a08f1e5165b852fcaa696d31"
+ integrity sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-dynamic-import@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz#23e917de63ed23c6600c5dd06d94669dce79f7b8"
+ integrity sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-exponentiation-operator@^7.25.9":
+ version "7.26.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz#e29f01b6de302c7c2c794277a48f04a9ca7f03bc"
+ integrity sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-export-namespace-from@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz#90745fe55053394f554e40584cda81f2c8a402a2"
+ integrity sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-flow-strip-types@^7.16.0":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.25.9.tgz#85879b42a8f5948fd6317069978e98f23ef8aec1"
+ integrity sha512-/VVukELzPDdci7UUsWQaSkhgnjIWXnIyRpM02ldxaVoFK96c41So8JcKT3m0gYjyv7j5FNPGS5vfELrWalkbDA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/plugin-syntax-flow" "^7.25.9"
+
+"@babel/plugin-transform-for-of@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz#4bdc7d42a213397905d89f02350c5267866d5755"
+ integrity sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9"
+
+"@babel/plugin-transform-function-name@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz#939d956e68a606661005bfd550c4fc2ef95f7b97"
+ integrity sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==
+ dependencies:
+ "@babel/helper-compilation-targets" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/traverse" "^7.25.9"
+
+"@babel/plugin-transform-json-strings@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz#c86db407cb827cded902a90c707d2781aaa89660"
+ integrity sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-literals@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz#1a1c6b4d4aa59bc4cad5b6b3a223a0abd685c9de"
+ integrity sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-logical-assignment-operators@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz#b19441a8c39a2fda0902900b306ea05ae1055db7"
+ integrity sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-member-expression-literals@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz#63dff19763ea64a31f5e6c20957e6a25e41ed5de"
+ integrity sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-modules-amd@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz#49ba478f2295101544abd794486cd3088dddb6c5"
+ integrity sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==
+ dependencies:
+ "@babel/helper-module-transforms" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-modules-commonjs@^7.25.9":
+ version "7.26.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz#8f011d44b20d02c3de44d8850d971d8497f981fb"
+ integrity sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==
+ dependencies:
+ "@babel/helper-module-transforms" "^7.26.0"
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-modules-systemjs@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz#8bd1b43836269e3d33307151a114bcf3ba6793f8"
+ integrity sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==
+ dependencies:
+ "@babel/helper-module-transforms" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/helper-validator-identifier" "^7.25.9"
+ "@babel/traverse" "^7.25.9"
+
+"@babel/plugin-transform-modules-umd@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz#6710079cdd7c694db36529a1e8411e49fcbf14c9"
+ integrity sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==
+ dependencies:
+ "@babel/helper-module-transforms" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-named-capturing-groups-regex@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz#454990ae6cc22fd2a0fa60b3a2c6f63a38064e6a"
+ integrity sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-new-target@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz#42e61711294b105c248336dcb04b77054ea8becd"
+ integrity sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-nullish-coalescing-operator@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz#bcb1b0d9e948168102d5f7104375ca21c3266949"
+ integrity sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-numeric-separator@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz#bfed75866261a8b643468b0ccfd275f2033214a1"
+ integrity sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-object-rest-spread@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz#0203725025074164808bcf1a2cfa90c652c99f18"
+ integrity sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==
+ dependencies:
+ "@babel/helper-compilation-targets" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/plugin-transform-parameters" "^7.25.9"
+
+"@babel/plugin-transform-object-super@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz#385d5de135162933beb4a3d227a2b7e52bb4cf03"
+ integrity sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/helper-replace-supers" "^7.25.9"
+
+"@babel/plugin-transform-optional-catch-binding@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz#10e70d96d52bb1f10c5caaac59ac545ea2ba7ff3"
+ integrity sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-optional-chaining@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz#e142eb899d26ef715435f201ab6e139541eee7dd"
+ integrity sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9"
+
+"@babel/plugin-transform-parameters@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz#b856842205b3e77e18b7a7a1b94958069c7ba257"
+ integrity sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-private-methods@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz#847f4139263577526455d7d3223cd8bda51e3b57"
+ integrity sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==
+ dependencies:
+ "@babel/helper-create-class-features-plugin" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-private-property-in-object@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz#9c8b73e64e6cc3cbb2743633885a7dd2c385fe33"
+ integrity sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.25.9"
+ "@babel/helper-create-class-features-plugin" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-property-literals@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz#d72d588bd88b0dec8b62e36f6fda91cedfe28e3f"
+ integrity sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-react-constant-elements@^7.12.1":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.25.9.tgz#08a1de35a301929b60fdf2788a54b46cd8ecd0ef"
+ integrity sha512-Ncw2JFsJVuvfRsa2lSHiC55kETQVLSnsYGQ1JDDwkUeWGTL/8Tom8aLTnlqgoeuopWrbbGndrc9AlLYrIosrow==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-react-display-name@^7.16.0", "@babel/plugin-transform-react-display-name@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.9.tgz#4b79746b59efa1f38c8695065a92a9f5afb24f7d"
+ integrity sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-react-jsx-development@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.9.tgz#8fd220a77dd139c07e25225a903b8be8c829e0d7"
+ integrity sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw==
+ dependencies:
+ "@babel/plugin-transform-react-jsx" "^7.25.9"
+
+"@babel/plugin-transform-react-jsx@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz#06367940d8325b36edff5e2b9cbe782947ca4166"
+ integrity sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.25.9"
+ "@babel/helper-module-imports" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/plugin-syntax-jsx" "^7.25.9"
+ "@babel/types" "^7.25.9"
+
+"@babel/plugin-transform-react-pure-annotations@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.25.9.tgz#ea1c11b2f9dbb8e2d97025f43a3b5bc47e18ae62"
+ integrity sha512-KQ/Takk3T8Qzj5TppkS1be588lkbTp5uj7w6a0LeQaTMSckU/wK0oJ/pih+T690tkgI5jfmg2TqDJvd41Sj1Cg==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-regenerator@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz#03a8a4670d6cebae95305ac6defac81ece77740b"
+ integrity sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+ regenerator-transform "^0.15.2"
+
+"@babel/plugin-transform-regexp-modifiers@^7.26.0":
+ version "7.26.0"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.26.0.tgz#2f5837a5b5cd3842a919d8147e9903cc7455b850"
+ integrity sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-reserved-words@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz#0398aed2f1f10ba3f78a93db219b27ef417fb9ce"
+ integrity sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-runtime@^7.16.4":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.25.9.tgz#62723ea3f5b31ffbe676da9d6dae17138ae580ea"
+ integrity sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ==
+ dependencies:
+ "@babel/helper-module-imports" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+ babel-plugin-polyfill-corejs2 "^0.4.10"
+ babel-plugin-polyfill-corejs3 "^0.10.6"
+ babel-plugin-polyfill-regenerator "^0.6.1"
+ semver "^6.3.1"
+
+"@babel/plugin-transform-shorthand-properties@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz#bb785e6091f99f826a95f9894fc16fde61c163f2"
+ integrity sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-spread@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz#24a35153931b4ba3d13cec4a7748c21ab5514ef9"
+ integrity sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9"
+
+"@babel/plugin-transform-sticky-regex@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz#c7f02b944e986a417817b20ba2c504dfc1453d32"
+ integrity sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-template-literals@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz#6dbd4a24e8fad024df76d1fac6a03cf413f60fe1"
+ integrity sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-typeof-symbol@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz#224ba48a92869ddbf81f9b4a5f1204bbf5a2bc4b"
+ integrity sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-typescript@^7.25.9":
+ version "7.26.3"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.26.3.tgz#3d6add9c78735623317387ee26d5ada540eee3fd"
+ integrity sha512-6+5hpdr6mETwSKjmJUdYw0EIkATiQhnELWlE3kJFBwSg/BGIVwVaVbX+gOXBCdc7Ln1RXZxyWGecIXhUfnl7oA==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.25.9"
+ "@babel/helper-create-class-features-plugin" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/helper-skip-transparent-expression-wrappers" "^7.25.9"
+ "@babel/plugin-syntax-typescript" "^7.25.9"
+
+"@babel/plugin-transform-unicode-escapes@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz#a75ef3947ce15363fccaa38e2dd9bc70b2788b82"
+ integrity sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-unicode-property-regex@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz#a901e96f2c1d071b0d1bb5dc0d3c880ce8f53dd3"
+ integrity sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-unicode-regex@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz#5eae747fe39eacf13a8bd006a4fb0b5d1fa5e9b1"
+ integrity sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/plugin-transform-unicode-sets-regex@^7.25.9":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz#65114c17b4ffc20fa5b163c63c70c0d25621fabe"
+ integrity sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+
+"@babel/preset-env@^7.11.0", "@babel/preset-env@^7.12.1", "@babel/preset-env@^7.16.4":
+ version "7.26.0"
+ resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.26.0.tgz#30e5c6bc1bcc54865bff0c5a30f6d4ccdc7fa8b1"
+ integrity sha512-H84Fxq0CQJNdPFT2DrfnylZ3cf5K43rGfWK4LJGPpjKHiZlk0/RzwEus3PDDZZg+/Er7lCA03MVacueUuXdzfw==
+ dependencies:
+ "@babel/compat-data" "^7.26.0"
+ "@babel/helper-compilation-targets" "^7.25.9"
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/helper-validator-option" "^7.25.9"
+ "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.25.9"
+ "@babel/plugin-bugfix-safari-class-field-initializer-scope" "^7.25.9"
+ "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.25.9"
+ "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.25.9"
+ "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.25.9"
+ "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2"
+ "@babel/plugin-syntax-import-assertions" "^7.26.0"
+ "@babel/plugin-syntax-import-attributes" "^7.26.0"
+ "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6"
+ "@babel/plugin-transform-arrow-functions" "^7.25.9"
+ "@babel/plugin-transform-async-generator-functions" "^7.25.9"
+ "@babel/plugin-transform-async-to-generator" "^7.25.9"
+ "@babel/plugin-transform-block-scoped-functions" "^7.25.9"
+ "@babel/plugin-transform-block-scoping" "^7.25.9"
+ "@babel/plugin-transform-class-properties" "^7.25.9"
+ "@babel/plugin-transform-class-static-block" "^7.26.0"
+ "@babel/plugin-transform-classes" "^7.25.9"
+ "@babel/plugin-transform-computed-properties" "^7.25.9"
+ "@babel/plugin-transform-destructuring" "^7.25.9"
+ "@babel/plugin-transform-dotall-regex" "^7.25.9"
+ "@babel/plugin-transform-duplicate-keys" "^7.25.9"
+ "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.25.9"
+ "@babel/plugin-transform-dynamic-import" "^7.25.9"
+ "@babel/plugin-transform-exponentiation-operator" "^7.25.9"
+ "@babel/plugin-transform-export-namespace-from" "^7.25.9"
+ "@babel/plugin-transform-for-of" "^7.25.9"
+ "@babel/plugin-transform-function-name" "^7.25.9"
+ "@babel/plugin-transform-json-strings" "^7.25.9"
+ "@babel/plugin-transform-literals" "^7.25.9"
+ "@babel/plugin-transform-logical-assignment-operators" "^7.25.9"
+ "@babel/plugin-transform-member-expression-literals" "^7.25.9"
+ "@babel/plugin-transform-modules-amd" "^7.25.9"
+ "@babel/plugin-transform-modules-commonjs" "^7.25.9"
+ "@babel/plugin-transform-modules-systemjs" "^7.25.9"
+ "@babel/plugin-transform-modules-umd" "^7.25.9"
+ "@babel/plugin-transform-named-capturing-groups-regex" "^7.25.9"
+ "@babel/plugin-transform-new-target" "^7.25.9"
+ "@babel/plugin-transform-nullish-coalescing-operator" "^7.25.9"
+ "@babel/plugin-transform-numeric-separator" "^7.25.9"
+ "@babel/plugin-transform-object-rest-spread" "^7.25.9"
+ "@babel/plugin-transform-object-super" "^7.25.9"
+ "@babel/plugin-transform-optional-catch-binding" "^7.25.9"
+ "@babel/plugin-transform-optional-chaining" "^7.25.9"
+ "@babel/plugin-transform-parameters" "^7.25.9"
+ "@babel/plugin-transform-private-methods" "^7.25.9"
+ "@babel/plugin-transform-private-property-in-object" "^7.25.9"
+ "@babel/plugin-transform-property-literals" "^7.25.9"
+ "@babel/plugin-transform-regenerator" "^7.25.9"
+ "@babel/plugin-transform-regexp-modifiers" "^7.26.0"
+ "@babel/plugin-transform-reserved-words" "^7.25.9"
+ "@babel/plugin-transform-shorthand-properties" "^7.25.9"
+ "@babel/plugin-transform-spread" "^7.25.9"
+ "@babel/plugin-transform-sticky-regex" "^7.25.9"
+ "@babel/plugin-transform-template-literals" "^7.25.9"
+ "@babel/plugin-transform-typeof-symbol" "^7.25.9"
+ "@babel/plugin-transform-unicode-escapes" "^7.25.9"
+ "@babel/plugin-transform-unicode-property-regex" "^7.25.9"
+ "@babel/plugin-transform-unicode-regex" "^7.25.9"
+ "@babel/plugin-transform-unicode-sets-regex" "^7.25.9"
+ "@babel/preset-modules" "0.1.6-no-external-plugins"
+ babel-plugin-polyfill-corejs2 "^0.4.10"
+ babel-plugin-polyfill-corejs3 "^0.10.6"
+ babel-plugin-polyfill-regenerator "^0.6.1"
+ core-js-compat "^3.38.1"
+ semver "^6.3.1"
+
+"@babel/preset-modules@0.1.6-no-external-plugins":
+ version "0.1.6-no-external-plugins"
+ resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz#ccb88a2c49c817236861fee7826080573b8a923a"
+ integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/types" "^7.4.4"
+ esutils "^2.0.2"
+
+"@babel/preset-react@^7.12.5", "@babel/preset-react@^7.16.0":
+ version "7.26.3"
+ resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.26.3.tgz#7c5e028d623b4683c1f83a0bd4713b9100560caa"
+ integrity sha512-Nl03d6T9ky516DGK2YMxrTqvnpUW63TnJMOMonj+Zae0JiPC5BC9xPMSL6L8fiSpA5vP88qfygavVQvnLp+6Cw==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/helper-validator-option" "^7.25.9"
+ "@babel/plugin-transform-react-display-name" "^7.25.9"
+ "@babel/plugin-transform-react-jsx" "^7.25.9"
+ "@babel/plugin-transform-react-jsx-development" "^7.25.9"
+ "@babel/plugin-transform-react-pure-annotations" "^7.25.9"
+
+"@babel/preset-typescript@^7.16.0":
+ version "7.26.0"
+ resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.26.0.tgz#4a570f1b8d104a242d923957ffa1eaff142a106d"
+ integrity sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.25.9"
+ "@babel/helper-validator-option" "^7.25.9"
+ "@babel/plugin-syntax-jsx" "^7.25.9"
+ "@babel/plugin-transform-modules-commonjs" "^7.25.9"
+ "@babel/plugin-transform-typescript" "^7.25.9"
+
+"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.8.4":
+ version "7.26.0"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1"
+ integrity sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==
+ dependencies:
+ regenerator-runtime "^0.14.0"
+
+"@babel/template@^7.25.9", "@babel/template@^7.3.3":
+ version "7.25.9"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.9.tgz#ecb62d81a8a6f5dc5fe8abfc3901fc52ddf15016"
+ integrity sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==
+ dependencies:
+ "@babel/code-frame" "^7.25.9"
+ "@babel/parser" "^7.25.9"
+ "@babel/types" "^7.25.9"
+
+"@babel/traverse@^7.25.9", "@babel/traverse@^7.7.2":
+ version "7.26.4"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.26.4.tgz#ac3a2a84b908dde6d463c3bfa2c5fdc1653574bd"
+ integrity sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==
+ dependencies:
+ "@babel/code-frame" "^7.26.2"
+ "@babel/generator" "^7.26.3"
+ "@babel/parser" "^7.26.3"
+ "@babel/template" "^7.25.9"
+ "@babel/types" "^7.26.3"
+ debug "^4.3.1"
+ globals "^11.1.0"
+
+"@babel/types@^7.0.0", "@babel/types@^7.12.6", "@babel/types@^7.20.7", "@babel/types@^7.25.9", "@babel/types@^7.26.0", "@babel/types@^7.26.3", "@babel/types@^7.3.3", "@babel/types@^7.4.4":
+ version "7.26.3"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.26.3.tgz#37e79830f04c2b5687acc77db97fbc75fb81f3c0"
+ integrity sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==
+ dependencies:
+ "@babel/helper-string-parser" "^7.25.9"
+ "@babel/helper-validator-identifier" "^7.25.9"
+
+"@bcoe/v8-coverage@^0.2.3":
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
+ integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
+
+"@csstools/normalize.css@*":
+ version "12.1.1"
+ resolved "https://registry.yarnpkg.com/@csstools/normalize.css/-/normalize.css-12.1.1.tgz#f0ad221b7280f3fc814689786fd9ee092776ef8f"
+ integrity sha512-YAYeJ+Xqh7fUou1d1j9XHl44BmsuThiTr4iNrgCQ3J27IbhXsxXDGZ1cXv8Qvs99d4rBbLiSKy3+WZiet32PcQ==
+
+"@csstools/postcss-cascade-layers@^1.1.1":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz#8a997edf97d34071dd2e37ea6022447dd9e795ad"
+ integrity sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==
+ dependencies:
+ "@csstools/selector-specificity" "^2.0.2"
+ postcss-selector-parser "^6.0.10"
+
+"@csstools/postcss-color-function@^1.1.1":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz#2bd36ab34f82d0497cfacdc9b18d34b5e6f64b6b"
+ integrity sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==
+ dependencies:
+ "@csstools/postcss-progressive-custom-properties" "^1.1.0"
+ postcss-value-parser "^4.2.0"
+
+"@csstools/postcss-font-format-keywords@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz#677b34e9e88ae997a67283311657973150e8b16a"
+ integrity sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+"@csstools/postcss-hwb-function@^1.0.2":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz#ab54a9fce0ac102c754854769962f2422ae8aa8b"
+ integrity sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+"@csstools/postcss-ic-unit@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz#28237d812a124d1a16a5acc5c3832b040b303e58"
+ integrity sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==
+ dependencies:
+ "@csstools/postcss-progressive-custom-properties" "^1.1.0"
+ postcss-value-parser "^4.2.0"
+
+"@csstools/postcss-is-pseudo-class@^2.0.7":
+ version "2.0.7"
+ resolved "https://registry.yarnpkg.com/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz#846ae6c0d5a1eaa878fce352c544f9c295509cd1"
+ integrity sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==
+ dependencies:
+ "@csstools/selector-specificity" "^2.0.0"
+ postcss-selector-parser "^6.0.10"
+
+"@csstools/postcss-nested-calc@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@csstools/postcss-nested-calc/-/postcss-nested-calc-1.0.0.tgz#d7e9d1d0d3d15cf5ac891b16028af2a1044d0c26"
+ integrity sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+"@csstools/postcss-normalize-display-values@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz#15da54a36e867b3ac5163ee12c1d7f82d4d612c3"
+ integrity sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+"@csstools/postcss-oklab-function@^1.1.1":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz#88cee0fbc8d6df27079ebd2fa016ee261eecf844"
+ integrity sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==
+ dependencies:
+ "@csstools/postcss-progressive-custom-properties" "^1.1.0"
+ postcss-value-parser "^4.2.0"
+
+"@csstools/postcss-progressive-custom-properties@^1.1.0", "@csstools/postcss-progressive-custom-properties@^1.3.0":
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz#542292558384361776b45c85226b9a3a34f276fa"
+ integrity sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+"@csstools/postcss-stepped-value-functions@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz#f8772c3681cc2befed695e2b0b1d68e22f08c4f4"
+ integrity sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+"@csstools/postcss-text-decoration-shorthand@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-1.0.0.tgz#ea96cfbc87d921eca914d3ad29340d9bcc4c953f"
+ integrity sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+"@csstools/postcss-trigonometric-functions@^1.0.2":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz#94d3e4774c36d35dcdc88ce091336cb770d32756"
+ integrity sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+"@csstools/postcss-unset-value@^1.0.2":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz#c99bb70e2cdc7312948d1eb41df2412330b81f77"
+ integrity sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==
+
+"@csstools/selector-specificity@^2.0.0", "@csstools/selector-specificity@^2.0.2":
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz#2cbcf822bf3764c9658c4d2e568bd0c0cb748016"
+ integrity sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==
+
+"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0":
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz#d1145bf2c20132d6400495d6df4bf59362fd9d56"
+ integrity sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==
+ dependencies:
+ eslint-visitor-keys "^3.4.3"
+
+"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.12.1", "@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.6.1":
+ version "4.12.1"
+ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0"
+ integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==
+
+"@eslint/config-array@^0.19.0":
+ version "0.19.1"
+ resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.1.tgz#734aaea2c40be22bbb1f2a9dac687c57a6a4c984"
+ integrity sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA==
+ dependencies:
+ "@eslint/object-schema" "^2.1.5"
+ debug "^4.3.1"
+ minimatch "^3.1.2"
+
+"@eslint/core@^0.9.0":
+ version "0.9.1"
+ resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.9.1.tgz#31763847308ef6b7084a4505573ac9402c51f9d1"
+ integrity sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q==
+ dependencies:
+ "@types/json-schema" "^7.0.15"
+
+"@eslint/eslintrc@^2.1.4":
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad"
+ integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==
+ dependencies:
+ ajv "^6.12.4"
+ debug "^4.3.2"
+ espree "^9.6.0"
+ globals "^13.19.0"
+ ignore "^5.2.0"
+ import-fresh "^3.2.1"
+ js-yaml "^4.1.0"
+ minimatch "^3.1.2"
+ strip-json-comments "^3.1.1"
+
+"@eslint/eslintrc@^3.2.0":
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.2.0.tgz#57470ac4e2e283a6bf76044d63281196e370542c"
+ integrity sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==
+ dependencies:
+ ajv "^6.12.4"
+ debug "^4.3.2"
+ espree "^10.0.1"
+ globals "^14.0.0"
+ ignore "^5.2.0"
+ import-fresh "^3.2.1"
+ js-yaml "^4.1.0"
+ minimatch "^3.1.2"
+ strip-json-comments "^3.1.1"
+
+"@eslint/js@8.57.1":
+ version "8.57.1"
+ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2"
+ integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==
+
+"@eslint/js@9.17.0":
+ version "9.17.0"
+ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.17.0.tgz#1523e586791f80376a6f8398a3964455ecc651ec"
+ integrity sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w==
+
+"@eslint/object-schema@^2.1.5":
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.5.tgz#8670a8f6258a2be5b2c620ff314a1d984c23eb2e"
+ integrity sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ==
+
+"@eslint/plugin-kit@^0.2.3":
+ version "0.2.4"
+ resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz#2b78e7bb3755784bb13faa8932a1d994d6537792"
+ integrity sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg==
+ dependencies:
+ levn "^0.4.1"
+
+"@humanfs/core@^0.19.1":
+ version "0.19.1"
+ resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77"
+ integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==
+
+"@humanfs/node@^0.16.6":
+ version "0.16.6"
+ resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e"
+ integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==
+ dependencies:
+ "@humanfs/core" "^0.19.1"
+ "@humanwhocodes/retry" "^0.3.0"
+
+"@humanwhocodes/config-array@^0.13.0":
+ version "0.13.0"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748"
+ integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==
+ dependencies:
+ "@humanwhocodes/object-schema" "^2.0.3"
+ debug "^4.3.1"
+ minimatch "^3.0.5"
+
+"@humanwhocodes/module-importer@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
+ integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
+
+"@humanwhocodes/object-schema@^2.0.3":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3"
+ integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==
+
+"@humanwhocodes/retry@^0.3.0":
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a"
+ integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==
+
+"@humanwhocodes/retry@^0.4.1":
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.1.tgz#9a96ce501bc62df46c4031fbd970e3cc6b10f07b"
+ integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==
+
+"@isaacs/cliui@^8.0.2":
+ version "8.0.2"
+ resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
+ integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==
+ dependencies:
+ string-width "^5.1.2"
+ string-width-cjs "npm:string-width@^4.2.0"
+ strip-ansi "^7.0.1"
+ strip-ansi-cjs "npm:strip-ansi@^6.0.1"
+ wrap-ansi "^8.1.0"
+ wrap-ansi-cjs "npm:wrap-ansi@^7.0.0"
+
+"@istanbuljs/load-nyc-config@^1.0.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced"
+ integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==
+ dependencies:
+ camelcase "^5.3.1"
+ find-up "^4.1.0"
+ get-package-type "^0.1.0"
+ js-yaml "^3.13.1"
+ resolve-from "^5.0.0"
+
+"@istanbuljs/schema@^0.1.2":
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98"
+ integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==
+
+"@jest/console@^27.5.1":
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.5.1.tgz#260fe7239602fe5130a94f1aa386eff54b014bba"
+ integrity sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==
+ dependencies:
+ "@jest/types" "^27.5.1"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ jest-message-util "^27.5.1"
+ jest-util "^27.5.1"
+ slash "^3.0.0"
+
+"@jest/console@^28.1.3":
+ version "28.1.3"
+ resolved "https://registry.yarnpkg.com/@jest/console/-/console-28.1.3.tgz#2030606ec03a18c31803b8a36382762e447655df"
+ integrity sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==
+ dependencies:
+ "@jest/types" "^28.1.3"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ jest-message-util "^28.1.3"
+ jest-util "^28.1.3"
+ slash "^3.0.0"
+
+"@jest/core@^27.5.1":
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.5.1.tgz#267ac5f704e09dc52de2922cbf3af9edcd64b626"
+ integrity sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==
+ dependencies:
+ "@jest/console" "^27.5.1"
+ "@jest/reporters" "^27.5.1"
+ "@jest/test-result" "^27.5.1"
+ "@jest/transform" "^27.5.1"
+ "@jest/types" "^27.5.1"
+ "@types/node" "*"
+ ansi-escapes "^4.2.1"
+ chalk "^4.0.0"
+ emittery "^0.8.1"
+ exit "^0.1.2"
+ graceful-fs "^4.2.9"
+ jest-changed-files "^27.5.1"
+ jest-config "^27.5.1"
+ jest-haste-map "^27.5.1"
+ jest-message-util "^27.5.1"
+ jest-regex-util "^27.5.1"
+ jest-resolve "^27.5.1"
+ jest-resolve-dependencies "^27.5.1"
+ jest-runner "^27.5.1"
+ jest-runtime "^27.5.1"
+ jest-snapshot "^27.5.1"
+ jest-util "^27.5.1"
+ jest-validate "^27.5.1"
+ jest-watcher "^27.5.1"
+ micromatch "^4.0.4"
+ rimraf "^3.0.0"
+ slash "^3.0.0"
+ strip-ansi "^6.0.0"
+
+"@jest/environment@^27.5.1":
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.5.1.tgz#d7425820511fe7158abbecc010140c3fd3be9c74"
+ integrity sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==
+ dependencies:
+ "@jest/fake-timers" "^27.5.1"
+ "@jest/types" "^27.5.1"
+ "@types/node" "*"
+ jest-mock "^27.5.1"
+
+"@jest/expect-utils@^29.7.0":
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6"
+ integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==
+ dependencies:
+ jest-get-type "^29.6.3"
+
+"@jest/fake-timers@^27.5.1":
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74"
+ integrity sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==
+ dependencies:
+ "@jest/types" "^27.5.1"
+ "@sinonjs/fake-timers" "^8.0.1"
+ "@types/node" "*"
+ jest-message-util "^27.5.1"
+ jest-mock "^27.5.1"
+ jest-util "^27.5.1"
+
+"@jest/globals@^27.5.1":
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.5.1.tgz#7ac06ce57ab966566c7963431cef458434601b2b"
+ integrity sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==
+ dependencies:
+ "@jest/environment" "^27.5.1"
+ "@jest/types" "^27.5.1"
+ expect "^27.5.1"
+
+"@jest/reporters@^27.5.1":
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.5.1.tgz#ceda7be96170b03c923c37987b64015812ffec04"
+ integrity sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==
+ dependencies:
+ "@bcoe/v8-coverage" "^0.2.3"
+ "@jest/console" "^27.5.1"
+ "@jest/test-result" "^27.5.1"
+ "@jest/transform" "^27.5.1"
+ "@jest/types" "^27.5.1"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ collect-v8-coverage "^1.0.0"
+ exit "^0.1.2"
+ glob "^7.1.2"
+ graceful-fs "^4.2.9"
+ istanbul-lib-coverage "^3.0.0"
+ istanbul-lib-instrument "^5.1.0"
+ istanbul-lib-report "^3.0.0"
+ istanbul-lib-source-maps "^4.0.0"
+ istanbul-reports "^3.1.3"
+ jest-haste-map "^27.5.1"
+ jest-resolve "^27.5.1"
+ jest-util "^27.5.1"
+ jest-worker "^27.5.1"
+ slash "^3.0.0"
+ source-map "^0.6.0"
+ string-length "^4.0.1"
+ terminal-link "^2.0.0"
+ v8-to-istanbul "^8.1.0"
+
+"@jest/schemas@^28.1.3":
+ version "28.1.3"
+ resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-28.1.3.tgz#ad8b86a66f11f33619e3d7e1dcddd7f2d40ff905"
+ integrity sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==
+ dependencies:
+ "@sinclair/typebox" "^0.24.1"
+
+"@jest/schemas@^29.6.3":
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03"
+ integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==
+ dependencies:
+ "@sinclair/typebox" "^0.27.8"
+
+"@jest/source-map@^27.5.1":
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.5.1.tgz#6608391e465add4205eae073b55e7f279e04e8cf"
+ integrity sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==
+ dependencies:
+ callsites "^3.0.0"
+ graceful-fs "^4.2.9"
+ source-map "^0.6.0"
+
+"@jest/test-result@^27.5.1":
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.5.1.tgz#56a6585fa80f7cdab72b8c5fc2e871d03832f5bb"
+ integrity sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==
+ dependencies:
+ "@jest/console" "^27.5.1"
+ "@jest/types" "^27.5.1"
+ "@types/istanbul-lib-coverage" "^2.0.0"
+ collect-v8-coverage "^1.0.0"
+
+"@jest/test-result@^28.1.3":
+ version "28.1.3"
+ resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-28.1.3.tgz#5eae945fd9f4b8fcfce74d239e6f725b6bf076c5"
+ integrity sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==
+ dependencies:
+ "@jest/console" "^28.1.3"
+ "@jest/types" "^28.1.3"
+ "@types/istanbul-lib-coverage" "^2.0.0"
+ collect-v8-coverage "^1.0.0"
+
+"@jest/test-sequencer@^27.5.1":
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz#4057e0e9cea4439e544c6353c6affe58d095745b"
+ integrity sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==
+ dependencies:
+ "@jest/test-result" "^27.5.1"
+ graceful-fs "^4.2.9"
+ jest-haste-map "^27.5.1"
+ jest-runtime "^27.5.1"
+
+"@jest/transform@^27.5.1":
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.5.1.tgz#6c3501dcc00c4c08915f292a600ece5ecfe1f409"
+ integrity sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==
+ dependencies:
+ "@babel/core" "^7.1.0"
+ "@jest/types" "^27.5.1"
+ babel-plugin-istanbul "^6.1.1"
+ chalk "^4.0.0"
+ convert-source-map "^1.4.0"
+ fast-json-stable-stringify "^2.0.0"
+ graceful-fs "^4.2.9"
+ jest-haste-map "^27.5.1"
+ jest-regex-util "^27.5.1"
+ jest-util "^27.5.1"
+ micromatch "^4.0.4"
+ pirates "^4.0.4"
+ slash "^3.0.0"
+ source-map "^0.6.1"
+ write-file-atomic "^3.0.0"
+
+"@jest/types@^27.5.1":
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80"
+ integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==
+ dependencies:
+ "@types/istanbul-lib-coverage" "^2.0.0"
+ "@types/istanbul-reports" "^3.0.0"
+ "@types/node" "*"
+ "@types/yargs" "^16.0.0"
+ chalk "^4.0.0"
+
+"@jest/types@^28.1.3":
+ version "28.1.3"
+ resolved "https://registry.yarnpkg.com/@jest/types/-/types-28.1.3.tgz#b05de80996ff12512bc5ceb1d208285a7d11748b"
+ integrity sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==
+ dependencies:
+ "@jest/schemas" "^28.1.3"
+ "@types/istanbul-lib-coverage" "^2.0.0"
+ "@types/istanbul-reports" "^3.0.0"
+ "@types/node" "*"
+ "@types/yargs" "^17.0.8"
+ chalk "^4.0.0"
+
+"@jest/types@^29.6.3":
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59"
+ integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==
+ dependencies:
+ "@jest/schemas" "^29.6.3"
+ "@types/istanbul-lib-coverage" "^2.0.0"
+ "@types/istanbul-reports" "^3.0.0"
+ "@types/node" "*"
+ "@types/yargs" "^17.0.8"
+ chalk "^4.0.0"
+
+"@jridgewell/gen-mapping@^0.3.2", "@jridgewell/gen-mapping@^0.3.5":
+ version "0.3.8"
+ resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142"
+ integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==
+ dependencies:
+ "@jridgewell/set-array" "^1.2.1"
+ "@jridgewell/sourcemap-codec" "^1.4.10"
+ "@jridgewell/trace-mapping" "^0.3.24"
+
+"@jridgewell/resolve-uri@^3.1.0":
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
+ integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==
+
+"@jridgewell/set-array@^1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280"
+ integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==
+
+"@jridgewell/source-map@^0.3.3":
+ version "0.3.6"
+ resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a"
+ integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==
+ dependencies:
+ "@jridgewell/gen-mapping" "^0.3.5"
+ "@jridgewell/trace-mapping" "^0.3.25"
+
+"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14":
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a"
+ integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==
+
+"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25":
+ version "0.3.25"
+ resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0"
+ integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==
+ dependencies:
+ "@jridgewell/resolve-uri" "^3.1.0"
+ "@jridgewell/sourcemap-codec" "^1.4.14"
+
+"@leichtgewicht/ip-codec@^2.0.1":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz#4fc56c15c580b9adb7dc3c333a134e540b44bfb1"
+ integrity sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==
+
+"@microsoft/fetch-event-source@^2.0.1":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz#9ceecc94b49fbaa15666e38ae8587f64acce007d"
+ integrity sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA==
+
+"@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1":
+ version "5.1.1-v1"
+ resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129"
+ integrity sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==
+ dependencies:
+ eslint-scope "5.1.1"
+
+"@nodelib/fs.scandir@2.1.5":
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
+ integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
+ dependencies:
+ "@nodelib/fs.stat" "2.0.5"
+ run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
+ integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
+
+"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8":
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
+ integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
+ dependencies:
+ "@nodelib/fs.scandir" "2.1.5"
+ fastq "^1.6.0"
+
+"@parcel/watcher-android-arm64@2.5.0":
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz#e32d3dda6647791ee930556aee206fcd5ea0fb7a"
+ integrity sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==
+
+"@parcel/watcher-darwin-arm64@2.5.0":
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz#0d9e680b7e9ec1c8f54944f1b945aa8755afb12f"
+ integrity sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==
+
+"@parcel/watcher-darwin-x64@2.5.0":
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz#f9f1d5ce9d5878d344f14ef1856b7a830c59d1bb"
+ integrity sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==
+
+"@parcel/watcher-freebsd-x64@2.5.0":
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz#2b77f0c82d19e84ff4c21de6da7f7d096b1a7e82"
+ integrity sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==
+
+"@parcel/watcher-linux-arm-glibc@2.5.0":
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz#92ed322c56dbafa3d2545dcf2803334aee131e42"
+ integrity sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==
+
+"@parcel/watcher-linux-arm-musl@2.5.0":
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz#cd48e9bfde0cdbbd2ecd9accfc52967e22f849a4"
+ integrity sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==
+
+"@parcel/watcher-linux-arm64-glibc@2.5.0":
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz#7b81f6d5a442bb89fbabaf6c13573e94a46feb03"
+ integrity sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==
+
+"@parcel/watcher-linux-arm64-musl@2.5.0":
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz#dcb8ff01077cdf59a18d9e0a4dff7a0cfe5fd732"
+ integrity sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==
+
+"@parcel/watcher-linux-x64-glibc@2.5.0":
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.0.tgz#2e254600fda4e32d83942384d1106e1eed84494d"
+ integrity sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==
+
+"@parcel/watcher-linux-x64-musl@2.5.0":
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.0.tgz#01fcea60fedbb3225af808d3f0a7b11229792eef"
+ integrity sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==
+
+"@parcel/watcher-win32-arm64@2.5.0":
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz#87cdb16e0783e770197e52fb1dc027bb0c847154"
+ integrity sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==
+
+"@parcel/watcher-win32-ia32@2.5.0":
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz#778c39b56da33e045ba21c678c31a9f9d7c6b220"
+ integrity sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==
+
+"@parcel/watcher-win32-x64@2.5.0":
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz#33873876d0bbc588aacce38e90d1d7480ce81cb7"
+ integrity sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==
+
+"@parcel/watcher@^2.4.1":
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.5.0.tgz#5c88818b12b8de4307a9d3e6dc3e28eba0dfbd10"
+ integrity sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==
+ dependencies:
+ detect-libc "^1.0.3"
+ is-glob "^4.0.3"
+ micromatch "^4.0.5"
+ node-addon-api "^7.0.0"
+ optionalDependencies:
+ "@parcel/watcher-android-arm64" "2.5.0"
+ "@parcel/watcher-darwin-arm64" "2.5.0"
+ "@parcel/watcher-darwin-x64" "2.5.0"
+ "@parcel/watcher-freebsd-x64" "2.5.0"
+ "@parcel/watcher-linux-arm-glibc" "2.5.0"
+ "@parcel/watcher-linux-arm-musl" "2.5.0"
+ "@parcel/watcher-linux-arm64-glibc" "2.5.0"
+ "@parcel/watcher-linux-arm64-musl" "2.5.0"
+ "@parcel/watcher-linux-x64-glibc" "2.5.0"
+ "@parcel/watcher-linux-x64-musl" "2.5.0"
+ "@parcel/watcher-win32-arm64" "2.5.0"
+ "@parcel/watcher-win32-ia32" "2.5.0"
+ "@parcel/watcher-win32-x64" "2.5.0"
+
+"@pkgjs/parseargs@^0.11.0":
+ version "0.11.0"
+ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
+ integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
+
+"@pkgr/core@^0.1.0":
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31"
+ integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==
+
+"@pmmmwh/react-refresh-webpack-plugin@^0.5.3":
+ version "0.5.15"
+ resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.15.tgz#f126be97c30b83ed777e2aeabd518bc592e6e7c4"
+ integrity sha512-LFWllMA55pzB9D34w/wXUCf8+c+IYKuJDgxiZ3qMhl64KRMBHYM1I3VdGaD2BV5FNPV2/S2596bppxHbv2ZydQ==
+ dependencies:
+ ansi-html "^0.0.9"
+ core-js-pure "^3.23.3"
+ error-stack-parser "^2.0.6"
+ html-entities "^2.1.0"
+ loader-utils "^2.0.4"
+ schema-utils "^4.2.0"
+ source-map "^0.7.3"
+
+"@radix-ui/react-compose-refs@1.1.1":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz#6f766faa975f8738269ebb8a23bad4f5a8d2faec"
+ integrity sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==
+
+"@radix-ui/react-slot@^1.1.1":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.1.1.tgz#ab9a0ffae4027db7dc2af503c223c978706affc3"
+ integrity sha512-RApLLOcINYJA+dMVbOju7MYv1Mb2EBp2nH4HdDzXTSyaR5optlm6Otrz1euW3HbdOR8UmmFK06TD+A9frYWv+g==
+ dependencies:
+ "@radix-ui/react-compose-refs" "1.1.1"
+
+"@reduxjs/toolkit@^2.5.0":
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-2.5.0.tgz#4679b09b4da211cb9a821803aabf86a13c96fbfa"
+ integrity sha512-awNe2oTodsZ6LmRqmkFhtb/KH03hUhxOamEQy411m3Njj3BbFvoBovxo4Q1cBWnV1ErprVj9MlF0UPXkng0eyg==
+ dependencies:
+ immer "^10.0.3"
+ redux "^5.0.1"
+ redux-thunk "^3.1.0"
+ reselect "^5.1.0"
+
+"@rollup/plugin-babel@^5.2.0":
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz#04bc0608f4aa4b2e4b1aebf284344d0f68fda283"
+ integrity sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==
+ dependencies:
+ "@babel/helper-module-imports" "^7.10.4"
+ "@rollup/pluginutils" "^3.1.0"
+
+"@rollup/plugin-node-resolve@^11.2.1":
+ version "11.2.1"
+ resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz#82aa59397a29cd4e13248b106e6a4a1880362a60"
+ integrity sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg==
+ dependencies:
+ "@rollup/pluginutils" "^3.1.0"
+ "@types/resolve" "1.17.1"
+ builtin-modules "^3.1.0"
+ deepmerge "^4.2.2"
+ is-module "^1.0.0"
+ resolve "^1.19.0"
+
+"@rollup/plugin-replace@^2.4.1":
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz#a2d539314fbc77c244858faa523012825068510a"
+ integrity sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==
+ dependencies:
+ "@rollup/pluginutils" "^3.1.0"
+ magic-string "^0.25.7"
+
+"@rollup/pluginutils@^3.1.0":
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b"
+ integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==
+ dependencies:
+ "@types/estree" "0.0.39"
+ estree-walker "^1.0.1"
+ picomatch "^2.2.2"
+
+"@rtsao/scc@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8"
+ integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==
+
+"@rushstack/eslint-patch@^1.1.0":
+ version "1.10.4"
+ resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.10.4.tgz#427d5549943a9c6fce808e39ea64dbe60d4047f1"
+ integrity sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==
+
+"@sinclair/typebox@^0.24.1":
+ version "0.24.51"
+ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.51.tgz#645f33fe4e02defe26f2f5c0410e1c094eac7f5f"
+ integrity sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==
+
+"@sinclair/typebox@^0.27.8":
+ version "0.27.8"
+ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e"
+ integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==
+
+"@sinonjs/commons@^1.7.0":
+ version "1.8.6"
+ resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.6.tgz#80c516a4dc264c2a69115e7578d62581ff455ed9"
+ integrity sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==
+ dependencies:
+ type-detect "4.0.8"
+
+"@sinonjs/fake-timers@^8.0.1":
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7"
+ integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==
+ dependencies:
+ "@sinonjs/commons" "^1.7.0"
+
+"@surma/rollup-plugin-off-main-thread@^2.2.3":
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz#ee34985952ca21558ab0d952f00298ad2190c053"
+ integrity sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==
+ dependencies:
+ ejs "^3.1.6"
+ json5 "^2.2.0"
+ magic-string "^0.25.0"
+ string.prototype.matchall "^4.0.6"
+
+"@svgr/babel-plugin-add-jsx-attribute@^5.4.0":
+ version "5.4.0"
+ resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-5.4.0.tgz#81ef61947bb268eb9d50523446f9c638fb355906"
+ integrity sha512-ZFf2gs/8/6B8PnSofI0inYXr2SDNTDScPXhN7k5EqD4aZ3gi6u+rbmZHVB8IM3wDyx8ntKACZbtXSm7oZGRqVg==
+
+"@svgr/babel-plugin-remove-jsx-attribute@^5.4.0":
+ version "5.4.0"
+ resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-5.4.0.tgz#6b2c770c95c874654fd5e1d5ef475b78a0a962ef"
+ integrity sha512-yaS4o2PgUtwLFGTKbsiAy6D0o3ugcUhWK0Z45umJ66EPWunAz9fuFw2gJuje6wqQvQWOTJvIahUwndOXb7QCPg==
+
+"@svgr/babel-plugin-remove-jsx-empty-expression@^5.0.1":
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-5.0.1.tgz#25621a8915ed7ad70da6cea3d0a6dbc2ea933efd"
+ integrity sha512-LA72+88A11ND/yFIMzyuLRSMJ+tRKeYKeQ+mR3DcAZ5I4h5CPWN9AHyUzJbWSYp/u2u0xhmgOe0+E41+GjEueA==
+
+"@svgr/babel-plugin-replace-jsx-attribute-value@^5.0.1":
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-5.0.1.tgz#0b221fc57f9fcd10e91fe219e2cd0dd03145a897"
+ integrity sha512-PoiE6ZD2Eiy5mK+fjHqwGOS+IXX0wq/YDtNyIgOrc6ejFnxN4b13pRpiIPbtPwHEc+NT2KCjteAcq33/F1Y9KQ==
+
+"@svgr/babel-plugin-svg-dynamic-title@^5.4.0":
+ version "5.4.0"
+ resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-5.4.0.tgz#139b546dd0c3186b6e5db4fefc26cb0baea729d7"
+ integrity sha512-zSOZH8PdZOpuG1ZVx/cLVePB2ibo3WPpqo7gFIjLV9a0QsuQAzJiwwqmuEdTaW2pegyBE17Uu15mOgOcgabQZg==
+
+"@svgr/babel-plugin-svg-em-dimensions@^5.4.0":
+ version "5.4.0"
+ resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-5.4.0.tgz#6543f69526632a133ce5cabab965deeaea2234a0"
+ integrity sha512-cPzDbDA5oT/sPXDCUYoVXEmm3VIoAWAPT6mSPTJNbQaBNUuEKVKyGH93oDY4e42PYHRW67N5alJx/eEol20abw==
+
+"@svgr/babel-plugin-transform-react-native-svg@^5.4.0":
+ version "5.4.0"
+ resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-5.4.0.tgz#00bf9a7a73f1cad3948cdab1f8dfb774750f8c80"
+ integrity sha512-3eYP/SaopZ41GHwXma7Rmxcv9uRslRDTY1estspeB1w1ueZWd/tPlMfEOoccYpEMZU3jD4OU7YitnXcF5hLW2Q==
+
+"@svgr/babel-plugin-transform-svg-component@^5.5.0":
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-5.5.0.tgz#583a5e2a193e214da2f3afeb0b9e8d3250126b4a"
+ integrity sha512-q4jSH1UUvbrsOtlo/tKcgSeiCHRSBdXoIoqX1pgcKK/aU3JD27wmMKwGtpB8qRYUYoyXvfGxUVKchLuR5pB3rQ==
+
+"@svgr/babel-preset@^5.5.0":
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/@svgr/babel-preset/-/babel-preset-5.5.0.tgz#8af54f3e0a8add7b1e2b0fcd5a882c55393df327"
+ integrity sha512-4FiXBjvQ+z2j7yASeGPEi8VD/5rrGQk4Xrq3EdJmoZgz/tpqChpo5hgXDvmEauwtvOc52q8ghhZK4Oy7qph4ig==
+ dependencies:
+ "@svgr/babel-plugin-add-jsx-attribute" "^5.4.0"
+ "@svgr/babel-plugin-remove-jsx-attribute" "^5.4.0"
+ "@svgr/babel-plugin-remove-jsx-empty-expression" "^5.0.1"
+ "@svgr/babel-plugin-replace-jsx-attribute-value" "^5.0.1"
+ "@svgr/babel-plugin-svg-dynamic-title" "^5.4.0"
+ "@svgr/babel-plugin-svg-em-dimensions" "^5.4.0"
+ "@svgr/babel-plugin-transform-react-native-svg" "^5.4.0"
+ "@svgr/babel-plugin-transform-svg-component" "^5.5.0"
+
+"@svgr/core@^5.5.0":
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/@svgr/core/-/core-5.5.0.tgz#82e826b8715d71083120fe8f2492ec7d7874a579"
+ integrity sha512-q52VOcsJPvV3jO1wkPtzTuKlvX7Y3xIcWRpCMtBF3MrteZJtBfQw/+u0B1BHy5ColpQc1/YVTrPEtSYIMNZlrQ==
+ dependencies:
+ "@svgr/plugin-jsx" "^5.5.0"
+ camelcase "^6.2.0"
+ cosmiconfig "^7.0.0"
+
+"@svgr/hast-util-to-babel-ast@^5.5.0":
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-5.5.0.tgz#5ee52a9c2533f73e63f8f22b779f93cd432a5461"
+ integrity sha512-cAaR/CAiZRB8GP32N+1jocovUtvlj0+e65TB50/6Lcime+EA49m/8l+P2ko+XPJ4dw3xaPS3jOL4F2X4KWxoeQ==
+ dependencies:
+ "@babel/types" "^7.12.6"
+
+"@svgr/plugin-jsx@^5.5.0":
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/@svgr/plugin-jsx/-/plugin-jsx-5.5.0.tgz#1aa8cd798a1db7173ac043466d7b52236b369000"
+ integrity sha512-V/wVh33j12hGh05IDg8GpIUXbjAPnTdPTKuP4VNLggnwaHMPNQNae2pRnyTAILWCQdz5GyMqtO488g7CKM8CBA==
+ dependencies:
+ "@babel/core" "^7.12.3"
+ "@svgr/babel-preset" "^5.5.0"
+ "@svgr/hast-util-to-babel-ast" "^5.5.0"
+ svg-parser "^2.0.2"
+
+"@svgr/plugin-svgo@^5.5.0":
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/@svgr/plugin-svgo/-/plugin-svgo-5.5.0.tgz#02da55d85320549324e201c7b2e53bf431fcc246"
+ integrity sha512-r5swKk46GuQl4RrVejVwpeeJaydoxkdwkM1mBKOgJLBUJPGaLci6ylg/IjhrRsREKDkr4kbMWdgOtbXEh0fyLQ==
+ dependencies:
+ cosmiconfig "^7.0.0"
+ deepmerge "^4.2.2"
+ svgo "^1.2.2"
+
+"@svgr/webpack@^5.5.0":
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/@svgr/webpack/-/webpack-5.5.0.tgz#aae858ee579f5fa8ce6c3166ef56c6a1b381b640"
+ integrity sha512-DOBOK255wfQxguUta2INKkzPj6AIS6iafZYiYmHn6W3pHlycSRRlvWKCfLDG10fXfLWqE3DJHgRUOyJYmARa7g==
+ dependencies:
+ "@babel/core" "^7.12.3"
+ "@babel/plugin-transform-react-constant-elements" "^7.12.1"
+ "@babel/preset-env" "^7.12.1"
+ "@babel/preset-react" "^7.12.5"
+ "@svgr/core" "^5.5.0"
+ "@svgr/plugin-jsx" "^5.5.0"
+ "@svgr/plugin-svgo" "^5.5.0"
+ loader-utils "^2.0.0"
+
+"@testing-library/dom@^10.4.0":
+ version "10.4.0"
+ resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-10.4.0.tgz#82a9d9462f11d240ecadbf406607c6ceeeff43a8"
+ integrity sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==
+ dependencies:
+ "@babel/code-frame" "^7.10.4"
+ "@babel/runtime" "^7.12.5"
+ "@types/aria-query" "^5.0.1"
+ aria-query "5.3.0"
+ chalk "^4.1.0"
+ dom-accessibility-api "^0.5.9"
+ lz-string "^1.5.0"
+ pretty-format "^27.0.2"
+
+"@testing-library/jest-dom@^6.6.3":
+ version "6.6.3"
+ resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-6.6.3.tgz#26ba906cf928c0f8172e182c6fe214eb4f9f2bd2"
+ integrity sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==
+ dependencies:
+ "@adobe/css-tools" "^4.4.0"
+ aria-query "^5.0.0"
+ chalk "^3.0.0"
+ css.escape "^1.5.1"
+ dom-accessibility-api "^0.6.3"
+ lodash "^4.17.21"
+ redent "^3.0.0"
+
+"@testing-library/react@^16.1.0":
+ version "16.1.0"
+ resolved "https://registry.yarnpkg.com/@testing-library/react/-/react-16.1.0.tgz#aa0c61398bac82eaf89776967e97de41ac742d71"
+ integrity sha512-Q2ToPvg0KsVL0ohND9A3zLJWcOXXcO8IDu3fj11KhNt0UlCWyFyvnCIBkd12tidB2lkiVRG8VFqdhcqhqnAQtg==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+
+"@testing-library/user-event@^14.5.2":
+ version "14.5.2"
+ resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.5.2.tgz#db7257d727c891905947bd1c1a99da20e03c2ebd"
+ integrity sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==
+
+"@tootallnate/once@1":
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
+ integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==
+
+"@trysound/sax@0.2.0":
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
+ integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
+
+"@types/aria-query@^5.0.1":
+ version "5.0.4"
+ resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-5.0.4.tgz#1a31c3d378850d2778dabb6374d036dcba4ba708"
+ integrity sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==
+
+"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14":
+ version "7.20.5"
+ resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017"
+ integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==
+ dependencies:
+ "@babel/parser" "^7.20.7"
+ "@babel/types" "^7.20.7"
+ "@types/babel__generator" "*"
+ "@types/babel__template" "*"
+ "@types/babel__traverse" "*"
+
+"@types/babel__generator@*":
+ version "7.6.8"
+ resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab"
+ integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==
+ dependencies:
+ "@babel/types" "^7.0.0"
+
+"@types/babel__template@*":
+ version "7.4.4"
+ resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f"
+ integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==
+ dependencies:
+ "@babel/parser" "^7.1.0"
+ "@babel/types" "^7.0.0"
+
+"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6":
+ version "7.20.6"
+ resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7"
+ integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==
+ dependencies:
+ "@babel/types" "^7.20.7"
+
+"@types/body-parser@*":
+ version "1.19.5"
+ resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.5.tgz#04ce9a3b677dc8bd681a17da1ab9835dc9d3ede4"
+ integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==
+ dependencies:
+ "@types/connect" "*"
+ "@types/node" "*"
+
+"@types/bonjour@^3.5.9":
+ version "3.5.13"
+ resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.13.tgz#adf90ce1a105e81dd1f9c61fdc5afda1bfb92956"
+ integrity sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==
+ dependencies:
+ "@types/node" "*"
+
+"@types/connect-history-api-fallback@^1.3.5":
+ version "1.5.4"
+ resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz#7de71645a103056b48ac3ce07b3520b819c1d5b3"
+ integrity sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==
+ dependencies:
+ "@types/express-serve-static-core" "*"
+ "@types/node" "*"
+
+"@types/connect@*":
+ version "3.4.38"
+ resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858"
+ integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==
+ dependencies:
+ "@types/node" "*"
+
+"@types/eslint-scope@^3.7.7":
+ version "3.7.7"
+ resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5"
+ integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==
+ dependencies:
+ "@types/eslint" "*"
+ "@types/estree" "*"
+
+"@types/eslint@*":
+ version "9.6.1"
+ resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-9.6.1.tgz#d5795ad732ce81715f27f75da913004a56751584"
+ integrity sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==
+ dependencies:
+ "@types/estree" "*"
+ "@types/json-schema" "*"
+
+"@types/eslint@^7.29.0 || ^8.4.1":
+ version "8.56.12"
+ resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.56.12.tgz#1657c814ffeba4d2f84c0d4ba0f44ca7ea1ca53a"
+ integrity sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g==
+ dependencies:
+ "@types/estree" "*"
+ "@types/json-schema" "*"
+
+"@types/estree@*", "@types/estree@^1.0.6":
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50"
+ integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==
+
+"@types/estree@0.0.39":
+ version "0.0.39"
+ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f"
+ integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==
+
+"@types/express-serve-static-core@*", "@types/express-serve-static-core@^5.0.0":
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-5.0.2.tgz#812d2871e5eea17fb0bd5214dda7a7b748c0e12a"
+ integrity sha512-vluaspfvWEtE4vcSDlKRNer52DvOGrB2xv6diXy6UKyKW0lqZiWHGNApSyxOv+8DE5Z27IzVvE7hNkxg7EXIcg==
+ dependencies:
+ "@types/node" "*"
+ "@types/qs" "*"
+ "@types/range-parser" "*"
+ "@types/send" "*"
+
+"@types/express-serve-static-core@^4.17.33":
+ version "4.19.6"
+ resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz#e01324c2a024ff367d92c66f48553ced0ab50267"
+ integrity sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==
+ dependencies:
+ "@types/node" "*"
+ "@types/qs" "*"
+ "@types/range-parser" "*"
+ "@types/send" "*"
+
+"@types/express@*":
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/@types/express/-/express-5.0.0.tgz#13a7d1f75295e90d19ed6e74cab3678488eaa96c"
+ integrity sha512-DvZriSMehGHL1ZNLzi6MidnsDhUZM/x2pRdDIKdwbUNqqwHxMlRdkxtn6/EPKyqKpHqTl/4nRZsRNLpZxZRpPQ==
+ dependencies:
+ "@types/body-parser" "*"
+ "@types/express-serve-static-core" "^5.0.0"
+ "@types/qs" "*"
+ "@types/serve-static" "*"
+
+"@types/express@^4.17.13":
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d"
+ integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==
+ dependencies:
+ "@types/body-parser" "*"
+ "@types/express-serve-static-core" "^4.17.33"
+ "@types/qs" "*"
+ "@types/serve-static" "*"
+
+"@types/graceful-fs@^4.1.2":
+ version "4.1.9"
+ resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4"
+ integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==
+ dependencies:
+ "@types/node" "*"
+
+"@types/html-minifier-terser@^6.0.0":
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35"
+ integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==
+
+"@types/http-errors@*":
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f"
+ integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==
+
+"@types/http-proxy@^1.17.8":
+ version "1.17.15"
+ resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.15.tgz#12118141ce9775a6499ecb4c01d02f90fc839d36"
+ integrity sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==
+ dependencies:
+ "@types/node" "*"
+
+"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7"
+ integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==
+
+"@types/istanbul-lib-report@*":
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf"
+ integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==
+ dependencies:
+ "@types/istanbul-lib-coverage" "*"
+
+"@types/istanbul-reports@^3.0.0":
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54"
+ integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==
+ dependencies:
+ "@types/istanbul-lib-report" "*"
+
+"@types/jest@^29.5.14":
+ version "29.5.14"
+ resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.14.tgz#2b910912fa1d6856cadcd0c1f95af7df1d6049e5"
+ integrity sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==
+ dependencies:
+ expect "^29.0.0"
+ pretty-format "^29.0.0"
+
+"@types/json-schema@*", "@types/json-schema@^7.0.15", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
+ version "7.0.15"
+ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
+ integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
+
+"@types/json5@^0.0.29":
+ version "0.0.29"
+ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
+ integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
+
+"@types/mime@^1":
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690"
+ integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==
+
+"@types/node-forge@^1.3.0":
+ version "1.3.11"
+ resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-1.3.11.tgz#0972ea538ddb0f4d9c2fa0ec5db5724773a604da"
+ integrity sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==
+ dependencies:
+ "@types/node" "*"
+
+"@types/node@*", "@types/node@^22.10.2":
+ version "22.10.2"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.2.tgz#a485426e6d1fdafc7b0d4c7b24e2c78182ddabb9"
+ integrity sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==
+ dependencies:
+ undici-types "~6.20.0"
+
+"@types/parse-json@^4.0.0":
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239"
+ integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==
+
+"@types/prettier@^2.1.5":
+ version "2.7.3"
+ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f"
+ integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==
+
+"@types/q@^1.5.1":
+ version "1.5.8"
+ resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.8.tgz#95f6c6a08f2ad868ba230ead1d2d7f7be3db3837"
+ integrity sha512-hroOstUScF6zhIi+5+x0dzqrHA1EJi+Irri6b1fxolMTqqHIV/Cg77EtnQcZqZCu8hR3mX2BzIxN4/GzI68Kfw==
+
+"@types/qs@*":
+ version "6.9.17"
+ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.17.tgz#fc560f60946d0aeff2f914eb41679659d3310e1a"
+ integrity sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==
+
+"@types/range-parser@*":
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb"
+ integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==
+
+"@types/react-dom@^19.0.2":
+ version "19.0.2"
+ resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.0.2.tgz#ad21f9a1ee881817995fd3f7fd33659c87e7b1b7"
+ integrity sha512-c1s+7TKFaDRRxr1TxccIX2u7sfCnc3RxkVyBIUA2lCpyqCF+QoAwQ/CBg7bsMdVwP120HEH143VQezKtef5nCg==
+
+"@types/react@^19.0.2":
+ version "19.0.2"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-19.0.2.tgz#9363e6b3ef898c471cb182dd269decc4afc1b4f6"
+ integrity sha512-USU8ZI/xyKJwFTpjSVIrSeHBVAGagkHQKPNbxeWwql/vDmnTIBgx+TJnhFnj1NXgz8XfprU0egV2dROLGpsBEg==
+ dependencies:
+ csstype "^3.0.2"
+
+"@types/resolve@1.17.1":
+ version "1.17.1"
+ resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
+ integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==
+ dependencies:
+ "@types/node" "*"
+
+"@types/retry@0.12.0":
+ version "0.12.0"
+ resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d"
+ integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==
+
+"@types/semver@^7.3.12":
+ version "7.5.8"
+ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e"
+ integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==
+
+"@types/send@*":
+ version "0.17.4"
+ resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a"
+ integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==
+ dependencies:
+ "@types/mime" "^1"
+ "@types/node" "*"
+
+"@types/serve-index@^1.9.1":
+ version "1.9.4"
+ resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.4.tgz#e6ae13d5053cb06ed36392110b4f9a49ac4ec898"
+ integrity sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==
+ dependencies:
+ "@types/express" "*"
+
+"@types/serve-static@*", "@types/serve-static@^1.13.10":
+ version "1.15.7"
+ resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714"
+ integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==
+ dependencies:
+ "@types/http-errors" "*"
+ "@types/node" "*"
+ "@types/send" "*"
+
+"@types/sockjs@^0.3.33":
+ version "0.3.36"
+ resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.36.tgz#ce322cf07bcc119d4cbf7f88954f3a3bd0f67535"
+ integrity sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==
+ dependencies:
+ "@types/node" "*"
+
+"@types/stack-utils@^2.0.0":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8"
+ integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==
+
+"@types/trusted-types@^2.0.2":
+ version "2.0.7"
+ resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11"
+ integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==
+
+"@types/use-sync-external-store@^0.0.6":
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz#60be8d21baab8c305132eb9cb912ed497852aadc"
+ integrity sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==
+
+"@types/ws@^8.5.5":
+ version "8.5.13"
+ resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.13.tgz#6414c280875e2691d0d1e080b05addbf5cb91e20"
+ integrity sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==
+ dependencies:
+ "@types/node" "*"
+
+"@types/yargs-parser@*":
+ version "21.0.3"
+ resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15"
+ integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==
+
+"@types/yargs@^16.0.0":
+ version "16.0.9"
+ resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.9.tgz#ba506215e45f7707e6cbcaf386981155b7ab956e"
+ integrity sha512-tHhzvkFXZQeTECenFoRljLBYPZJ7jAVxqqtEI0qTLOmuultnFp4I9yKE17vTuhf7BkhCu7I4XuemPgikDVuYqA==
+ dependencies:
+ "@types/yargs-parser" "*"
+
+"@types/yargs@^17.0.8":
+ version "17.0.33"
+ resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d"
+ integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==
+ dependencies:
+ "@types/yargs-parser" "*"
+
+"@typescript-eslint/eslint-plugin@^5.5.0":
+ version "5.62.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz#aeef0328d172b9e37d9bab6dbc13b87ed88977db"
+ integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==
+ dependencies:
+ "@eslint-community/regexpp" "^4.4.0"
+ "@typescript-eslint/scope-manager" "5.62.0"
+ "@typescript-eslint/type-utils" "5.62.0"
+ "@typescript-eslint/utils" "5.62.0"
+ debug "^4.3.4"
+ graphemer "^1.4.0"
+ ignore "^5.2.0"
+ natural-compare-lite "^1.4.0"
+ semver "^7.3.7"
+ tsutils "^3.21.0"
+
+"@typescript-eslint/eslint-plugin@^8.18.1":
+ version "8.18.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.1.tgz#992e5ac1553ce20d0d46aa6eccd79dc36dedc805"
+ integrity sha512-Ncvsq5CT3Gvh+uJG0Lwlho6suwDfUXH0HztslDf5I+F2wAFAZMRwYLEorumpKLzmO2suAXZ/td1tBg4NZIi9CQ==
+ dependencies:
+ "@eslint-community/regexpp" "^4.10.0"
+ "@typescript-eslint/scope-manager" "8.18.1"
+ "@typescript-eslint/type-utils" "8.18.1"
+ "@typescript-eslint/utils" "8.18.1"
+ "@typescript-eslint/visitor-keys" "8.18.1"
+ graphemer "^1.4.0"
+ ignore "^5.3.1"
+ natural-compare "^1.4.0"
+ ts-api-utils "^1.3.0"
+
+"@typescript-eslint/experimental-utils@^5.0.0":
+ version "5.62.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-5.62.0.tgz#14559bf73383a308026b427a4a6129bae2146741"
+ integrity sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==
+ dependencies:
+ "@typescript-eslint/utils" "5.62.0"
+
+"@typescript-eslint/parser@^5.5.0":
+ version "5.62.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.62.0.tgz#1b63d082d849a2fcae8a569248fbe2ee1b8a56c7"
+ integrity sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==
+ dependencies:
+ "@typescript-eslint/scope-manager" "5.62.0"
+ "@typescript-eslint/types" "5.62.0"
+ "@typescript-eslint/typescript-estree" "5.62.0"
+ debug "^4.3.4"
+
+"@typescript-eslint/parser@^8.18.1":
+ version "8.18.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.18.1.tgz#c258bae062778b7696793bc492249027a39dfb95"
+ integrity sha512-rBnTWHCdbYM2lh7hjyXqxk70wvon3p2FyaniZuey5TrcGBpfhVp0OxOa6gxr9Q9YhZFKyfbEnxc24ZnVbbUkCA==
+ dependencies:
+ "@typescript-eslint/scope-manager" "8.18.1"
+ "@typescript-eslint/types" "8.18.1"
+ "@typescript-eslint/typescript-estree" "8.18.1"
+ "@typescript-eslint/visitor-keys" "8.18.1"
+ debug "^4.3.4"
+
+"@typescript-eslint/scope-manager@5.62.0":
+ version "5.62.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c"
+ integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==
+ dependencies:
+ "@typescript-eslint/types" "5.62.0"
+ "@typescript-eslint/visitor-keys" "5.62.0"
+
+"@typescript-eslint/scope-manager@8.18.1":
+ version "8.18.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.18.1.tgz#52cedc3a8178d7464a70beffed3203678648e55b"
+ integrity sha512-HxfHo2b090M5s2+/9Z3gkBhI6xBH8OJCFjH9MhQ+nnoZqxU3wNxkLT+VWXWSFWc3UF3Z+CfPAyqdCTdoXtDPCQ==
+ dependencies:
+ "@typescript-eslint/types" "8.18.1"
+ "@typescript-eslint/visitor-keys" "8.18.1"
+
+"@typescript-eslint/type-utils@5.62.0":
+ version "5.62.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz#286f0389c41681376cdad96b309cedd17d70346a"
+ integrity sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==
+ dependencies:
+ "@typescript-eslint/typescript-estree" "5.62.0"
+ "@typescript-eslint/utils" "5.62.0"
+ debug "^4.3.4"
+ tsutils "^3.21.0"
+
+"@typescript-eslint/type-utils@8.18.1":
+ version "8.18.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.18.1.tgz#10f41285475c0bdee452b79ff7223f0e43a7781e"
+ integrity sha512-jAhTdK/Qx2NJPNOTxXpMwlOiSymtR2j283TtPqXkKBdH8OAMmhiUfP0kJjc/qSE51Xrq02Gj9NY7MwK+UxVwHQ==
+ dependencies:
+ "@typescript-eslint/typescript-estree" "8.18.1"
+ "@typescript-eslint/utils" "8.18.1"
+ debug "^4.3.4"
+ ts-api-utils "^1.3.0"
+
+"@typescript-eslint/types@5.62.0":
+ version "5.62.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f"
+ integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==
+
+"@typescript-eslint/types@8.18.1":
+ version "8.18.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.18.1.tgz#d7f4f94d0bba9ebd088de840266fcd45408a8fff"
+ integrity sha512-7uoAUsCj66qdNQNpH2G8MyTFlgerum8ubf21s3TSM3XmKXuIn+H2Sifh/ES2nPOPiYSRJWAk0fDkW0APBWcpfw==
+
+"@typescript-eslint/typescript-estree@5.62.0":
+ version "5.62.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b"
+ integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==
+ dependencies:
+ "@typescript-eslint/types" "5.62.0"
+ "@typescript-eslint/visitor-keys" "5.62.0"
+ debug "^4.3.4"
+ globby "^11.1.0"
+ is-glob "^4.0.3"
+ semver "^7.3.7"
+ tsutils "^3.21.0"
+
+"@typescript-eslint/typescript-estree@8.18.1":
+ version "8.18.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.1.tgz#2a86cd64b211a742f78dfa7e6f4860413475367e"
+ integrity sha512-z8U21WI5txzl2XYOW7i9hJhxoKKNG1kcU4RzyNvKrdZDmbjkmLBo8bgeiOJmA06kizLI76/CCBAAGlTlEeUfyg==
+ dependencies:
+ "@typescript-eslint/types" "8.18.1"
+ "@typescript-eslint/visitor-keys" "8.18.1"
+ debug "^4.3.4"
+ fast-glob "^3.3.2"
+ is-glob "^4.0.3"
+ minimatch "^9.0.4"
+ semver "^7.6.0"
+ ts-api-utils "^1.3.0"
+
+"@typescript-eslint/utils@5.62.0", "@typescript-eslint/utils@^5.58.0":
+ version "5.62.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86"
+ integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==
+ dependencies:
+ "@eslint-community/eslint-utils" "^4.2.0"
+ "@types/json-schema" "^7.0.9"
+ "@types/semver" "^7.3.12"
+ "@typescript-eslint/scope-manager" "5.62.0"
+ "@typescript-eslint/types" "5.62.0"
+ "@typescript-eslint/typescript-estree" "5.62.0"
+ eslint-scope "^5.1.1"
+ semver "^7.3.7"
+
+"@typescript-eslint/utils@8.18.1", "@typescript-eslint/utils@^6.0.0 || ^7.0.0 || ^8.0.0":
+ version "8.18.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.18.1.tgz#c4199ea23fc823c736e2c96fd07b1f7235fa92d5"
+ integrity sha512-8vikiIj2ebrC4WRdcAdDcmnu9Q/MXXwg+STf40BVfT8exDqBCUPdypvzcUPxEqRGKg9ALagZ0UWcYCtn+4W2iQ==
+ dependencies:
+ "@eslint-community/eslint-utils" "^4.4.0"
+ "@typescript-eslint/scope-manager" "8.18.1"
+ "@typescript-eslint/types" "8.18.1"
+ "@typescript-eslint/typescript-estree" "8.18.1"
+
+"@typescript-eslint/visitor-keys@5.62.0":
+ version "5.62.0"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e"
+ integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==
+ dependencies:
+ "@typescript-eslint/types" "5.62.0"
+ eslint-visitor-keys "^3.3.0"
+
+"@typescript-eslint/visitor-keys@8.18.1":
+ version "8.18.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.1.tgz#344b4f6bc83f104f514676facf3129260df7610a"
+ integrity sha512-Vj0WLm5/ZsD013YeUKn+K0y8p1M0jPpxOkKdbD1wB0ns53a5piVY02zjf072TblEweAbcYiFiPoSMF3kp+VhhQ==
+ dependencies:
+ "@typescript-eslint/types" "8.18.1"
+ eslint-visitor-keys "^4.2.0"
+
+"@ungap/structured-clone@^1.2.0":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.1.tgz#28fa185f67daaf7b7a1a8c1d445132c5d979f8bd"
+ integrity sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==
+
+"@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.14.1.tgz#a9f6a07f2b03c95c8d38c4536a1fdfb521ff55b6"
+ integrity sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==
+ dependencies:
+ "@webassemblyjs/helper-numbers" "1.13.2"
+ "@webassemblyjs/helper-wasm-bytecode" "1.13.2"
+
+"@webassemblyjs/floating-point-hex-parser@1.13.2":
+ version "1.13.2"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz#fcca1eeddb1cc4e7b6eed4fc7956d6813b21b9fb"
+ integrity sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==
+
+"@webassemblyjs/helper-api-error@1.13.2":
+ version "1.13.2"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz#e0a16152248bc38daee76dd7e21f15c5ef3ab1e7"
+ integrity sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==
+
+"@webassemblyjs/helper-buffer@1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz#822a9bc603166531f7d5df84e67b5bf99b72b96b"
+ integrity sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==
+
+"@webassemblyjs/helper-numbers@1.13.2":
+ version "1.13.2"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz#dbd932548e7119f4b8a7877fd5a8d20e63490b2d"
+ integrity sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==
+ dependencies:
+ "@webassemblyjs/floating-point-hex-parser" "1.13.2"
+ "@webassemblyjs/helper-api-error" "1.13.2"
+ "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/helper-wasm-bytecode@1.13.2":
+ version "1.13.2"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz#e556108758f448aae84c850e593ce18a0eb31e0b"
+ integrity sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==
+
+"@webassemblyjs/helper-wasm-section@1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz#9629dda9c4430eab54b591053d6dc6f3ba050348"
+ integrity sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==
+ dependencies:
+ "@webassemblyjs/ast" "1.14.1"
+ "@webassemblyjs/helper-buffer" "1.14.1"
+ "@webassemblyjs/helper-wasm-bytecode" "1.13.2"
+ "@webassemblyjs/wasm-gen" "1.14.1"
+
+"@webassemblyjs/ieee754@1.13.2":
+ version "1.13.2"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz#1c5eaace1d606ada2c7fd7045ea9356c59ee0dba"
+ integrity sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==
+ dependencies:
+ "@xtuc/ieee754" "^1.2.0"
+
+"@webassemblyjs/leb128@1.13.2":
+ version "1.13.2"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.13.2.tgz#57c5c3deb0105d02ce25fa3fd74f4ebc9fd0bbb0"
+ integrity sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==
+ dependencies:
+ "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/utf8@1.13.2":
+ version "1.13.2"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.13.2.tgz#917a20e93f71ad5602966c2d685ae0c6c21f60f1"
+ integrity sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==
+
+"@webassemblyjs/wasm-edit@^1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz#ac6689f502219b59198ddec42dcd496b1004d597"
+ integrity sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==
+ dependencies:
+ "@webassemblyjs/ast" "1.14.1"
+ "@webassemblyjs/helper-buffer" "1.14.1"
+ "@webassemblyjs/helper-wasm-bytecode" "1.13.2"
+ "@webassemblyjs/helper-wasm-section" "1.14.1"
+ "@webassemblyjs/wasm-gen" "1.14.1"
+ "@webassemblyjs/wasm-opt" "1.14.1"
+ "@webassemblyjs/wasm-parser" "1.14.1"
+ "@webassemblyjs/wast-printer" "1.14.1"
+
+"@webassemblyjs/wasm-gen@1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz#991e7f0c090cb0bb62bbac882076e3d219da9570"
+ integrity sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==
+ dependencies:
+ "@webassemblyjs/ast" "1.14.1"
+ "@webassemblyjs/helper-wasm-bytecode" "1.13.2"
+ "@webassemblyjs/ieee754" "1.13.2"
+ "@webassemblyjs/leb128" "1.13.2"
+ "@webassemblyjs/utf8" "1.13.2"
+
+"@webassemblyjs/wasm-opt@1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz#e6f71ed7ccae46781c206017d3c14c50efa8106b"
+ integrity sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==
+ dependencies:
+ "@webassemblyjs/ast" "1.14.1"
+ "@webassemblyjs/helper-buffer" "1.14.1"
+ "@webassemblyjs/wasm-gen" "1.14.1"
+ "@webassemblyjs/wasm-parser" "1.14.1"
+
+"@webassemblyjs/wasm-parser@1.14.1", "@webassemblyjs/wasm-parser@^1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz#b3e13f1893605ca78b52c68e54cf6a865f90b9fb"
+ integrity sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==
+ dependencies:
+ "@webassemblyjs/ast" "1.14.1"
+ "@webassemblyjs/helper-api-error" "1.13.2"
+ "@webassemblyjs/helper-wasm-bytecode" "1.13.2"
+ "@webassemblyjs/ieee754" "1.13.2"
+ "@webassemblyjs/leb128" "1.13.2"
+ "@webassemblyjs/utf8" "1.13.2"
+
+"@webassemblyjs/wast-printer@1.14.1":
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz#3bb3e9638a8ae5fdaf9610e7a06b4d9f9aa6fe07"
+ integrity sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==
+ dependencies:
+ "@webassemblyjs/ast" "1.14.1"
+ "@xtuc/long" "4.2.2"
+
+"@xtuc/ieee754@^1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
+ integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==
+
+"@xtuc/long@4.2.2":
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
+ integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
+
+abab@^2.0.3, abab@^2.0.5:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291"
+ integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==
+
+accepts@~1.3.4, accepts@~1.3.8:
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
+ integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
+ dependencies:
+ mime-types "~2.1.34"
+ negotiator "0.6.3"
+
+acorn-globals@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45"
+ integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==
+ dependencies:
+ acorn "^7.1.1"
+ acorn-walk "^7.1.1"
+
+acorn-jsx@^5.3.2:
+ version "5.3.2"
+ resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
+ integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
+
+acorn-walk@^7.1.1:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
+ integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
+
+acorn@^7.1.1:
+ version "7.4.1"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
+ integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
+
+acorn@^8.14.0, acorn@^8.2.4, acorn@^8.8.2, acorn@^8.9.0:
+ version "8.14.0"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0"
+ integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==
+
+address@^1.0.1, address@^1.1.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/address/-/address-1.2.2.tgz#2b5248dac5485a6390532c6a517fda2e3faac89e"
+ integrity sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==
+
+adjust-sourcemap-loader@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz#fc4a0fd080f7d10471f30a7320f25560ade28c99"
+ integrity sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==
+ dependencies:
+ loader-utils "^2.0.0"
+ regex-parser "^2.2.11"
+
+agent-base@6:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
+ integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
+ dependencies:
+ debug "4"
+
+ajv-formats@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520"
+ integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==
+ dependencies:
+ ajv "^8.0.0"
+
+ajv-keywords@^3.4.1, ajv-keywords@^3.5.2:
+ version "3.5.2"
+ resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
+ integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
+
+ajv-keywords@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16"
+ integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==
+ dependencies:
+ fast-deep-equal "^3.1.3"
+
+ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5:
+ version "6.12.6"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+ integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
+ dependencies:
+ fast-deep-equal "^3.1.1"
+ fast-json-stable-stringify "^2.0.0"
+ json-schema-traverse "^0.4.1"
+ uri-js "^4.2.2"
+
+ajv@^8.0.0, ajv@^8.6.0, ajv@^8.9.0:
+ version "8.17.1"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6"
+ integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==
+ dependencies:
+ fast-deep-equal "^3.1.3"
+ fast-uri "^3.0.1"
+ json-schema-traverse "^1.0.0"
+ require-from-string "^2.0.2"
+
+ansi-escapes@^4.2.1, ansi-escapes@^4.3.1:
+ version "4.3.2"
+ resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
+ integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
+ dependencies:
+ type-fest "^0.21.3"
+
+ansi-html-community@^0.0.8:
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41"
+ integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==
+
+ansi-html@^0.0.9:
+ version "0.0.9"
+ resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.9.tgz#6512d02342ae2cc68131952644a129cb734cd3f0"
+ integrity sha512-ozbS3LuenHVxNRh/wdnN16QapUHzauqSomAl1jwwJRRsGwFwtj644lIhxfWu0Fy0acCij2+AEgHvjscq3dlVXg==
+
+ansi-regex@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
+ integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
+
+ansi-regex@^6.0.1:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654"
+ integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==
+
+ansi-styles@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+ integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+ dependencies:
+ color-convert "^1.9.0"
+
+ansi-styles@^4.0.0, ansi-styles@^4.1.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+ integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
+ dependencies:
+ color-convert "^2.0.1"
+
+ansi-styles@^5.0.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
+ integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
+
+ansi-styles@^6.1.0:
+ version "6.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
+ integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
+
+any-promise@^1.0.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
+ integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==
+
+anymatch@^3.0.3, anymatch@~3.1.2:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
+ integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
+ dependencies:
+ normalize-path "^3.0.0"
+ picomatch "^2.0.4"
+
+arg@^5.0.2:
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
+ integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==
+
+argparse@^1.0.7:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+ integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
+ dependencies:
+ sprintf-js "~1.0.2"
+
+argparse@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
+ integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
+
+aria-query@5.3.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e"
+ integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==
+ dependencies:
+ dequal "^2.0.3"
+
+aria-query@^5.0.0, aria-query@^5.3.2:
+ version "5.3.2"
+ resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.2.tgz#93f81a43480e33a338f19163a3d10a50c01dcd59"
+ integrity sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==
+
+array-buffer-byte-length@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f"
+ integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==
+ dependencies:
+ call-bind "^1.0.5"
+ is-array-buffer "^3.0.4"
+
+array-flatten@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
+ integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==
+
+array-includes@^3.1.6, array-includes@^3.1.8:
+ version "3.1.8"
+ resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d"
+ integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==
+ dependencies:
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.2"
+ es-object-atoms "^1.0.0"
+ get-intrinsic "^1.2.4"
+ is-string "^1.0.7"
+
+array-union@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
+ integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
+
+array.prototype.findlast@^1.2.5:
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904"
+ integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==
+ dependencies:
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.2"
+ es-errors "^1.3.0"
+ es-object-atoms "^1.0.0"
+ es-shim-unscopables "^1.0.2"
+
+array.prototype.findlastindex@^1.2.5:
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d"
+ integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==
+ dependencies:
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.2"
+ es-errors "^1.3.0"
+ es-object-atoms "^1.0.0"
+ es-shim-unscopables "^1.0.2"
+
+array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.2:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz#534aaf9e6e8dd79fb6b9a9917f839ef1ec63afe5"
+ integrity sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==
+ dependencies:
+ call-bind "^1.0.8"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.5"
+ es-shim-unscopables "^1.0.2"
+
+array.prototype.flatmap@^1.3.2:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz#712cc792ae70370ae40586264629e33aab5dd38b"
+ integrity sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==
+ dependencies:
+ call-bind "^1.0.8"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.5"
+ es-shim-unscopables "^1.0.2"
+
+array.prototype.reduce@^1.0.6:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/array.prototype.reduce/-/array.prototype.reduce-1.0.7.tgz#6aadc2f995af29cb887eb866d981dc85ab6f7dc7"
+ integrity sha512-mzmiUCVwtiD4lgxYP8g7IYy8El8p2CSMePvIbTS7gchKir/L1fgJrk0yDKmAX6mnRQFKNADYIk8nNlTris5H1Q==
+ dependencies:
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.2"
+ es-array-method-boxes-properly "^1.0.0"
+ es-errors "^1.3.0"
+ es-object-atoms "^1.0.0"
+ is-string "^1.0.7"
+
+array.prototype.tosorted@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz#fe954678ff53034e717ea3352a03f0b0b86f7ffc"
+ integrity sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==
+ dependencies:
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.3"
+ es-errors "^1.3.0"
+ es-shim-unscopables "^1.0.2"
+
+arraybuffer.prototype.slice@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz#9d760d84dbdd06d0cbf92c8849615a1a7ab3183c"
+ integrity sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==
+ dependencies:
+ array-buffer-byte-length "^1.0.1"
+ call-bind "^1.0.8"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.5"
+ es-errors "^1.3.0"
+ get-intrinsic "^1.2.6"
+ is-array-buffer "^3.0.4"
+
+asap@~2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
+ integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==
+
+ast-types-flow@^0.0.8:
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.8.tgz#0a85e1c92695769ac13a428bb653e7538bea27d6"
+ integrity sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==
+
+async@^3.2.3:
+ version "3.2.6"
+ resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce"
+ integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==
+
+asynckit@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+ integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
+
+at-least-node@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
+ integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
+
+autoprefixer@^10.4.13:
+ version "10.4.20"
+ resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.20.tgz#5caec14d43976ef42e32dcb4bd62878e96be5b3b"
+ integrity sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==
+ dependencies:
+ browserslist "^4.23.3"
+ caniuse-lite "^1.0.30001646"
+ fraction.js "^4.3.7"
+ normalize-range "^0.1.2"
+ picocolors "^1.0.1"
+ postcss-value-parser "^4.2.0"
+
+autosize@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/autosize/-/autosize-6.0.1.tgz#64ee78dd7029be959eddd3afbbd33235b957e10f"
+ integrity sha512-f86EjiUKE6Xvczc4ioP1JBlWG7FKrE13qe/DxBCpe8GCipCq2nFw73aO8QEBKHfSbYGDN5eB9jXWKen7tspDqQ==
+
+available-typed-arrays@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846"
+ integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==
+ dependencies:
+ possible-typed-array-names "^1.0.0"
+
+axe-core@^4.10.0:
+ version "4.10.2"
+ resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.10.2.tgz#85228e3e1d8b8532a27659b332e39b7fa0e022df"
+ integrity sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w==
+
+axobject-query@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee"
+ integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==
+
+babel-jest@^27.4.2, babel-jest@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444"
+ integrity sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==
+ dependencies:
+ "@jest/transform" "^27.5.1"
+ "@jest/types" "^27.5.1"
+ "@types/babel__core" "^7.1.14"
+ babel-plugin-istanbul "^6.1.1"
+ babel-preset-jest "^27.5.1"
+ chalk "^4.0.0"
+ graceful-fs "^4.2.9"
+ slash "^3.0.0"
+
+babel-loader@^8.2.3:
+ version "8.4.1"
+ resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.4.1.tgz#6ccb75c66e62c3b144e1c5f2eaec5b8f6c08c675"
+ integrity sha512-nXzRChX+Z1GoE6yWavBQg6jDslyFF3SDjl2paADuoQtQW10JqShJt62R6eJQ5m/pjJFDT8xgKIWSP85OY8eXeA==
+ dependencies:
+ find-cache-dir "^3.3.1"
+ loader-utils "^2.0.4"
+ make-dir "^3.1.0"
+ schema-utils "^2.6.5"
+
+babel-plugin-istanbul@^6.1.1:
+ version "6.1.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73"
+ integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.0.0"
+ "@istanbuljs/load-nyc-config" "^1.0.0"
+ "@istanbuljs/schema" "^0.1.2"
+ istanbul-lib-instrument "^5.0.4"
+ test-exclude "^6.0.0"
+
+babel-plugin-jest-hoist@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz#9be98ecf28c331eb9f5df9c72d6f89deb8181c2e"
+ integrity sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==
+ dependencies:
+ "@babel/template" "^7.3.3"
+ "@babel/types" "^7.3.3"
+ "@types/babel__core" "^7.0.0"
+ "@types/babel__traverse" "^7.0.6"
+
+babel-plugin-macros@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1"
+ integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+ cosmiconfig "^7.0.0"
+ resolve "^1.19.0"
+
+babel-plugin-named-asset-import@^0.3.8:
+ version "0.3.8"
+ resolved "https://registry.yarnpkg.com/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz#6b7fa43c59229685368683c28bc9734f24524cc2"
+ integrity sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==
+
+babel-plugin-polyfill-corejs2@^0.4.10:
+ version "0.4.12"
+ resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.12.tgz#ca55bbec8ab0edeeef3d7b8ffd75322e210879a9"
+ integrity sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==
+ dependencies:
+ "@babel/compat-data" "^7.22.6"
+ "@babel/helper-define-polyfill-provider" "^0.6.3"
+ semver "^6.3.1"
+
+babel-plugin-polyfill-corejs3@^0.10.6:
+ version "0.10.6"
+ resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz#2deda57caef50f59c525aeb4964d3b2f867710c7"
+ integrity sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA==
+ dependencies:
+ "@babel/helper-define-polyfill-provider" "^0.6.2"
+ core-js-compat "^3.38.0"
+
+babel-plugin-polyfill-regenerator@^0.6.1:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.3.tgz#abeb1f3f1c762eace37587f42548b08b57789bc8"
+ integrity sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==
+ dependencies:
+ "@babel/helper-define-polyfill-provider" "^0.6.3"
+
+babel-plugin-transform-react-remove-prop-types@^0.4.24:
+ version "0.4.24"
+ resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz#f2edaf9b4c6a5fbe5c1d678bfb531078c1555f3a"
+ integrity sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA==
+
+babel-preset-current-node-syntax@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz#9a929eafece419612ef4ae4f60b1862ebad8ef30"
+ integrity sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==
+ dependencies:
+ "@babel/plugin-syntax-async-generators" "^7.8.4"
+ "@babel/plugin-syntax-bigint" "^7.8.3"
+ "@babel/plugin-syntax-class-properties" "^7.12.13"
+ "@babel/plugin-syntax-class-static-block" "^7.14.5"
+ "@babel/plugin-syntax-import-attributes" "^7.24.7"
+ "@babel/plugin-syntax-import-meta" "^7.10.4"
+ "@babel/plugin-syntax-json-strings" "^7.8.3"
+ "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
+ "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
+ "@babel/plugin-syntax-numeric-separator" "^7.10.4"
+ "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
+ "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
+ "@babel/plugin-syntax-optional-chaining" "^7.8.3"
+ "@babel/plugin-syntax-private-property-in-object" "^7.14.5"
+ "@babel/plugin-syntax-top-level-await" "^7.14.5"
+
+babel-preset-jest@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz#91f10f58034cb7989cb4f962b69fa6eef6a6bc81"
+ integrity sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==
+ dependencies:
+ babel-plugin-jest-hoist "^27.5.1"
+ babel-preset-current-node-syntax "^1.0.0"
+
+babel-preset-react-app@^10.0.1:
+ version "10.0.1"
+ resolved "https://registry.yarnpkg.com/babel-preset-react-app/-/babel-preset-react-app-10.0.1.tgz#ed6005a20a24f2c88521809fa9aea99903751584"
+ integrity sha512-b0D9IZ1WhhCWkrTXyFuIIgqGzSkRIH5D5AmB0bXbzYAB1OBAwHcUeyWW2LorutLWF5btNo/N7r/cIdmvvKJlYg==
+ dependencies:
+ "@babel/core" "^7.16.0"
+ "@babel/plugin-proposal-class-properties" "^7.16.0"
+ "@babel/plugin-proposal-decorators" "^7.16.4"
+ "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.0"
+ "@babel/plugin-proposal-numeric-separator" "^7.16.0"
+ "@babel/plugin-proposal-optional-chaining" "^7.16.0"
+ "@babel/plugin-proposal-private-methods" "^7.16.0"
+ "@babel/plugin-transform-flow-strip-types" "^7.16.0"
+ "@babel/plugin-transform-react-display-name" "^7.16.0"
+ "@babel/plugin-transform-runtime" "^7.16.4"
+ "@babel/preset-env" "^7.16.4"
+ "@babel/preset-react" "^7.16.0"
+ "@babel/preset-typescript" "^7.16.0"
+ "@babel/runtime" "^7.16.3"
+ babel-plugin-macros "^3.1.0"
+ babel-plugin-transform-react-remove-prop-types "^0.4.24"
+
+balanced-match@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
+batch@0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16"
+ integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==
+
+bfj@^7.0.2:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/bfj/-/bfj-7.1.0.tgz#c5177d522103f9040e1b12980fe8c38cf41d3f8b"
+ integrity sha512-I6MMLkn+anzNdCUp9hMRyui1HaNEUCco50lxbvNS4+EyXg8lN3nJ48PjPWtbH8UVS9CuMoaKE9U2V3l29DaRQw==
+ dependencies:
+ bluebird "^3.7.2"
+ check-types "^11.2.3"
+ hoopy "^0.1.4"
+ jsonpath "^1.1.1"
+ tryer "^1.0.1"
+
+big.js@^5.2.2:
+ version "5.2.2"
+ resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
+ integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
+
+binary-extensions@^2.0.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522"
+ integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
+
+bluebird@^3.7.2:
+ version "3.7.2"
+ resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f"
+ integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==
+
+body-parser@1.20.3:
+ version "1.20.3"
+ resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6"
+ integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==
+ dependencies:
+ bytes "3.1.2"
+ content-type "~1.0.5"
+ debug "2.6.9"
+ depd "2.0.0"
+ destroy "1.2.0"
+ http-errors "2.0.0"
+ iconv-lite "0.4.24"
+ on-finished "2.4.1"
+ qs "6.13.0"
+ raw-body "2.5.2"
+ type-is "~1.6.18"
+ unpipe "1.0.0"
+
+bonjour-service@^1.0.11:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.3.0.tgz#80d867430b5a0da64e82a8047fc1e355bdb71722"
+ integrity sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==
+ dependencies:
+ fast-deep-equal "^3.1.3"
+ multicast-dns "^7.2.5"
+
+boolbase@^1.0.0, boolbase@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
+ integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+brace-expansion@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
+ integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
+ dependencies:
+ balanced-match "^1.0.0"
+
+braces@^3.0.3, braces@~3.0.2:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
+ integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
+ dependencies:
+ fill-range "^7.1.1"
+
+browser-process-hrtime@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626"
+ integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==
+
+browserslist@^4.0.0, browserslist@^4.18.1, browserslist@^4.21.4, browserslist@^4.23.3, browserslist@^4.24.0, browserslist@^4.24.2:
+ version "4.24.3"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.3.tgz#5fc2725ca8fb3c1432e13dac278c7cc103e026d2"
+ integrity sha512-1CPmv8iobE2fyRMV97dAcMVegvvWKxmq94hkLiAkUGwKVTyDLw33K+ZxiFrREKmmps4rIw6grcCFCnTMSZ/YiA==
+ dependencies:
+ caniuse-lite "^1.0.30001688"
+ electron-to-chromium "^1.5.73"
+ node-releases "^2.0.19"
+ update-browserslist-db "^1.1.1"
+
+bser@2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05"
+ integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==
+ dependencies:
+ node-int64 "^0.4.0"
+
+buffer-from@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
+ integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
+
+builtin-modules@^3.1.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
+ integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
+
+bytes@3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
+ integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
+
+call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz#32e5892e6361b29b0b545ba6f7763378daca2840"
+ integrity sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==
+ dependencies:
+ es-errors "^1.3.0"
+ function-bind "^1.1.2"
+
+call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7, call-bind@^1.0.8:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c"
+ integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==
+ dependencies:
+ call-bind-apply-helpers "^1.0.0"
+ es-define-property "^1.0.0"
+ get-intrinsic "^1.2.4"
+ set-function-length "^1.2.2"
+
+call-bound@^1.0.2, call-bound@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.3.tgz#41cfd032b593e39176a71533ab4f384aa04fd681"
+ integrity sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==
+ dependencies:
+ call-bind-apply-helpers "^1.0.1"
+ get-intrinsic "^1.2.6"
+
+callsites@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
+ integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
+
+camel-case@^4.1.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a"
+ integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==
+ dependencies:
+ pascal-case "^3.1.2"
+ tslib "^2.0.3"
+
+camelcase-css@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5"
+ integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
+
+camelcase@^5.3.1:
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
+ integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
+
+camelcase@^6.2.0, camelcase@^6.2.1:
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
+ integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
+
+caniuse-api@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
+ integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==
+ dependencies:
+ browserslist "^4.0.0"
+ caniuse-lite "^1.0.0"
+ lodash.memoize "^4.1.2"
+ lodash.uniq "^4.5.0"
+
+caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001646, caniuse-lite@^1.0.30001688:
+ version "1.0.30001690"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001690.tgz#f2d15e3aaf8e18f76b2b8c1481abde063b8104c8"
+ integrity sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==
+
+case-sensitive-paths-webpack-plugin@^2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/case-sensitive-paths-webpack-plugin/-/case-sensitive-paths-webpack-plugin-2.4.0.tgz#db64066c6422eed2e08cc14b986ca43796dbc6d4"
+ integrity sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==
+
+chalk@^2.4.1:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+ integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+ dependencies:
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
+
+chalk@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
+ integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
+ dependencies:
+ ansi-styles "^4.1.0"
+ supports-color "^7.1.0"
+
+chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
+ integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
+ dependencies:
+ ansi-styles "^4.1.0"
+ supports-color "^7.1.0"
+
+char-regex@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
+ integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==
+
+char-regex@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-2.0.2.tgz#81385bb071af4df774bff8721d0ca15ef29ea0bb"
+ integrity sha512-cbGOjAptfM2LVmWhwRFHEKTPkLwNddVmuqYZQt895yXwAsWsXObCG+YN4DGQ/JBtT4GP1a1lPPdio2z413LmTg==
+
+check-types@^11.2.3:
+ version "11.2.3"
+ resolved "https://registry.yarnpkg.com/check-types/-/check-types-11.2.3.tgz#1ffdf68faae4e941fce252840b1787b8edc93b71"
+ integrity sha512-+67P1GkJRaxQD6PKK0Et9DhwQB+vGg3PM5+aavopCpZT1lj9jeqfvpgTLAWErNj8qApkkmXlu/Ug74kmhagkXg==
+
+chokidar@^3.4.2, chokidar@^3.5.3, chokidar@^3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
+ integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
+ dependencies:
+ anymatch "~3.1.2"
+ braces "~3.0.2"
+ glob-parent "~5.1.2"
+ is-binary-path "~2.1.0"
+ is-glob "~4.0.1"
+ normalize-path "~3.0.0"
+ readdirp "~3.6.0"
+ optionalDependencies:
+ fsevents "~2.3.2"
+
+chokidar@^4.0.0:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30"
+ integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==
+ dependencies:
+ readdirp "^4.0.1"
+
+chrome-trace-event@^1.0.2:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz#05bffd7ff928465093314708c93bdfa9bd1f0f5b"
+ integrity sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==
+
+ci-info@^3.2.0:
+ version "3.9.0"
+ resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4"
+ integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==
+
+cjs-module-lexer@^1.0.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz#707413784dbb3a72aa11c2f2b042a0bef4004170"
+ integrity sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==
+
+class-variance-authority@^0.7.1:
+ version "0.7.1"
+ resolved "https://registry.yarnpkg.com/class-variance-authority/-/class-variance-authority-0.7.1.tgz#4008a798a0e4553a781a57ac5177c9fb5d043787"
+ integrity sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==
+ dependencies:
+ clsx "^2.1.1"
+
+clean-css@^5.2.2:
+ version "5.3.3"
+ resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.3.tgz#b330653cd3bd6b75009cc25c714cae7b93351ccd"
+ integrity sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==
+ dependencies:
+ source-map "~0.6.0"
+
+cliui@^7.0.2:
+ version "7.0.4"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
+ integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.0"
+ wrap-ansi "^7.0.0"
+
+clsx@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999"
+ integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==
+
+co@^4.6.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+ integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==
+
+coa@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/coa/-/coa-2.0.2.tgz#43f6c21151b4ef2bf57187db0d73de229e3e7ec3"
+ integrity sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==
+ dependencies:
+ "@types/q" "^1.5.1"
+ chalk "^2.4.1"
+ q "^1.1.2"
+
+collect-v8-coverage@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9"
+ integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==
+
+color-convert@^1.9.0:
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+ integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+ dependencies:
+ color-name "1.1.3"
+
+color-convert@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+ integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+ dependencies:
+ color-name "~1.1.4"
+
+color-name@1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+ integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
+
+color-name@~1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+ integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+colord@^2.9.1:
+ version "2.9.3"
+ resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43"
+ integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==
+
+colorette@^2.0.10:
+ version "2.0.20"
+ resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a"
+ integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==
+
+combined-stream@^1.0.8:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+ integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
+ dependencies:
+ delayed-stream "~1.0.0"
+
+commander@^2.20.0:
+ version "2.20.3"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
+ integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
+
+commander@^4.0.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
+ integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
+
+commander@^7.2.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
+ integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
+
+commander@^8.3.0:
+ version "8.3.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
+ integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==
+
+common-tags@^1.8.0:
+ version "1.8.2"
+ resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6"
+ integrity sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==
+
+commondir@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
+ integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==
+
+compressible@~2.0.18:
+ version "2.0.18"
+ resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
+ integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==
+ dependencies:
+ mime-db ">= 1.43.0 < 2"
+
+compression@^1.7.4:
+ version "1.7.5"
+ resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.5.tgz#fdd256c0a642e39e314c478f6c2cd654edd74c93"
+ integrity sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==
+ dependencies:
+ bytes "3.1.2"
+ compressible "~2.0.18"
+ debug "2.6.9"
+ negotiator "~0.6.4"
+ on-headers "~1.0.2"
+ safe-buffer "5.2.1"
+ vary "~1.1.2"
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+
+confusing-browser-globals@^1.0.10, confusing-browser-globals@^1.0.11:
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81"
+ integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==
+
+connect-history-api-fallback@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8"
+ integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==
+
+content-disposition@0.5.4:
+ version "0.5.4"
+ resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
+ integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
+ dependencies:
+ safe-buffer "5.2.1"
+
+content-type@~1.0.4, content-type@~1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
+ integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
+
+convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f"
+ integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==
+
+convert-source-map@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a"
+ integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
+
+cookie-signature@1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
+ integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==
+
+cookie@0.7.1:
+ version "0.7.1"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9"
+ integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==
+
+core-js-compat@^3.38.0, core-js-compat@^3.38.1:
+ version "3.39.0"
+ resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.39.0.tgz#b12dccb495f2601dc860bdbe7b4e3ffa8ba63f61"
+ integrity sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==
+ dependencies:
+ browserslist "^4.24.2"
+
+core-js-pure@^3.23.3:
+ version "3.39.0"
+ resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.39.0.tgz#aa0d54d70a15bdc13e7c853db87c10abc30d68f3"
+ integrity sha512-7fEcWwKI4rJinnK+wLTezeg2smbFFdSBP6E2kQZNbnzM2s1rpKQ6aaRteZSSg7FLU3P0HGGVo/gbpfanU36urg==
+
+core-js@^3.19.2:
+ version "3.39.0"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.39.0.tgz#57f7647f4d2d030c32a72ea23a0555b2eaa30f83"
+ integrity sha512-raM0ew0/jJUqkJ0E6e8UDtl+y/7ktFivgWvqw8dNSQeNWoSDLvQ1H/RN3aPXB9tBd4/FhyR4RDPGhsNIMsAn7g==
+
+core-util-is@~1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
+ integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
+
+cosmiconfig@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982"
+ integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==
+ dependencies:
+ "@types/parse-json" "^4.0.0"
+ import-fresh "^3.1.0"
+ parse-json "^5.0.0"
+ path-type "^4.0.0"
+ yaml "^1.7.2"
+
+cosmiconfig@^7.0.0:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6"
+ integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==
+ dependencies:
+ "@types/parse-json" "^4.0.0"
+ import-fresh "^3.2.1"
+ parse-json "^5.0.0"
+ path-type "^4.0.0"
+ yaml "^1.10.0"
+
+cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3, cross-spawn@^7.0.6:
+ version "7.0.6"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f"
+ integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==
+ dependencies:
+ path-key "^3.1.0"
+ shebang-command "^2.0.0"
+ which "^2.0.1"
+
+crypto-random-string@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
+ integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
+
+css-blank-pseudo@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz#36523b01c12a25d812df343a32c322d2a2324561"
+ integrity sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==
+ dependencies:
+ postcss-selector-parser "^6.0.9"
+
+css-declaration-sorter@^6.3.1:
+ version "6.4.1"
+ resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.4.1.tgz#28beac7c20bad7f1775be3a7129d7eae409a3a71"
+ integrity sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==
+
+css-has-pseudo@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz#57f6be91ca242d5c9020ee3e51bbb5b89fc7af73"
+ integrity sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==
+ dependencies:
+ postcss-selector-parser "^6.0.9"
+
+css-loader@^6.5.1:
+ version "6.11.0"
+ resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.11.0.tgz#33bae3bf6363d0a7c2cf9031c96c744ff54d85ba"
+ integrity sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==
+ dependencies:
+ icss-utils "^5.1.0"
+ postcss "^8.4.33"
+ postcss-modules-extract-imports "^3.1.0"
+ postcss-modules-local-by-default "^4.0.5"
+ postcss-modules-scope "^3.2.0"
+ postcss-modules-values "^4.0.0"
+ postcss-value-parser "^4.2.0"
+ semver "^7.5.4"
+
+css-minimizer-webpack-plugin@^3.2.0:
+ version "3.4.1"
+ resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.4.1.tgz#ab78f781ced9181992fe7b6e4f3422e76429878f"
+ integrity sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==
+ dependencies:
+ cssnano "^5.0.6"
+ jest-worker "^27.0.2"
+ postcss "^8.3.5"
+ schema-utils "^4.0.0"
+ serialize-javascript "^6.0.0"
+ source-map "^0.6.1"
+
+css-prefers-color-scheme@^6.0.3:
+ version "6.0.3"
+ resolved "https://registry.yarnpkg.com/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz#ca8a22e5992c10a5b9d315155e7caee625903349"
+ integrity sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==
+
+css-select-base-adapter@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz#3b2ff4972cc362ab88561507a95408a1432135d7"
+ integrity sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==
+
+css-select@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/css-select/-/css-select-2.1.0.tgz#6a34653356635934a81baca68d0255432105dbef"
+ integrity sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==
+ dependencies:
+ boolbase "^1.0.0"
+ css-what "^3.2.1"
+ domutils "^1.7.0"
+ nth-check "^1.0.2"
+
+css-select@^4.1.3:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b"
+ integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==
+ dependencies:
+ boolbase "^1.0.0"
+ css-what "^6.0.1"
+ domhandler "^4.3.1"
+ domutils "^2.8.0"
+ nth-check "^2.0.1"
+
+css-tree@1.0.0-alpha.37:
+ version "1.0.0-alpha.37"
+ resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.37.tgz#98bebd62c4c1d9f960ec340cf9f7522e30709a22"
+ integrity sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==
+ dependencies:
+ mdn-data "2.0.4"
+ source-map "^0.6.1"
+
+css-tree@^1.1.2, css-tree@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d"
+ integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==
+ dependencies:
+ mdn-data "2.0.14"
+ source-map "^0.6.1"
+
+css-what@^3.2.1:
+ version "3.4.2"
+ resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4"
+ integrity sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==
+
+css-what@^6.0.1:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
+ integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
+
+css.escape@^1.5.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb"
+ integrity sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==
+
+cssdb@^7.1.0:
+ version "7.11.2"
+ resolved "https://registry.yarnpkg.com/cssdb/-/cssdb-7.11.2.tgz#127a2f5b946ee653361a5af5333ea85a39df5ae5"
+ integrity sha512-lhQ32TFkc1X4eTefGfYPvgovRSzIMofHkigfH8nWtyRL4XJLsRhJFreRvEgKzept7x1rjBuy3J/MurXLaFxW/A==
+
+cssesc@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
+ integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
+
+cssnano-preset-default@^5.2.14:
+ version "5.2.14"
+ resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.14.tgz#309def4f7b7e16d71ab2438052093330d9ab45d8"
+ integrity sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==
+ dependencies:
+ css-declaration-sorter "^6.3.1"
+ cssnano-utils "^3.1.0"
+ postcss-calc "^8.2.3"
+ postcss-colormin "^5.3.1"
+ postcss-convert-values "^5.1.3"
+ postcss-discard-comments "^5.1.2"
+ postcss-discard-duplicates "^5.1.0"
+ postcss-discard-empty "^5.1.1"
+ postcss-discard-overridden "^5.1.0"
+ postcss-merge-longhand "^5.1.7"
+ postcss-merge-rules "^5.1.4"
+ postcss-minify-font-values "^5.1.0"
+ postcss-minify-gradients "^5.1.1"
+ postcss-minify-params "^5.1.4"
+ postcss-minify-selectors "^5.2.1"
+ postcss-normalize-charset "^5.1.0"
+ postcss-normalize-display-values "^5.1.0"
+ postcss-normalize-positions "^5.1.1"
+ postcss-normalize-repeat-style "^5.1.1"
+ postcss-normalize-string "^5.1.0"
+ postcss-normalize-timing-functions "^5.1.0"
+ postcss-normalize-unicode "^5.1.1"
+ postcss-normalize-url "^5.1.0"
+ postcss-normalize-whitespace "^5.1.1"
+ postcss-ordered-values "^5.1.3"
+ postcss-reduce-initial "^5.1.2"
+ postcss-reduce-transforms "^5.1.0"
+ postcss-svgo "^5.1.0"
+ postcss-unique-selectors "^5.1.1"
+
+cssnano-utils@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-3.1.0.tgz#95684d08c91511edfc70d2636338ca37ef3a6861"
+ integrity sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==
+
+cssnano@^5.0.6:
+ version "5.1.15"
+ resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.15.tgz#ded66b5480d5127fcb44dac12ea5a983755136bf"
+ integrity sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==
+ dependencies:
+ cssnano-preset-default "^5.2.14"
+ lilconfig "^2.0.3"
+ yaml "^1.10.2"
+
+csso@^4.0.2, csso@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529"
+ integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==
+ dependencies:
+ css-tree "^1.1.2"
+
+cssom@^0.4.4:
+ version "0.4.4"
+ resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10"
+ integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==
+
+cssom@~0.3.6:
+ version "0.3.8"
+ resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a"
+ integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==
+
+cssstyle@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852"
+ integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==
+ dependencies:
+ cssom "~0.3.6"
+
+csstype@^3.0.2:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
+ integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
+
+damerau-levenshtein@^1.0.8:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
+ integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==
+
+data-urls@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b"
+ integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==
+ dependencies:
+ abab "^2.0.3"
+ whatwg-mimetype "^2.3.0"
+ whatwg-url "^8.0.0"
+
+data-view-buffer@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2"
+ integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==
+ dependencies:
+ call-bind "^1.0.6"
+ es-errors "^1.3.0"
+ is-data-view "^1.0.1"
+
+data-view-byte-length@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2"
+ integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==
+ dependencies:
+ call-bind "^1.0.7"
+ es-errors "^1.3.0"
+ is-data-view "^1.0.1"
+
+data-view-byte-offset@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a"
+ integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==
+ dependencies:
+ call-bind "^1.0.6"
+ es-errors "^1.3.0"
+ is-data-view "^1.0.1"
+
+debug@2.6.9, debug@^2.6.0:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+ dependencies:
+ ms "2.0.0"
+
+debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4:
+ version "4.4.0"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a"
+ integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==
+ dependencies:
+ ms "^2.1.3"
+
+debug@^3.2.7:
+ version "3.2.7"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
+ integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
+ dependencies:
+ ms "^2.1.1"
+
+decimal.js@^10.2.1:
+ version "10.4.3"
+ resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23"
+ integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==
+
+dedent@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c"
+ integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==
+
+deep-is@^0.1.3, deep-is@~0.1.3:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831"
+ integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
+
+deepmerge@^4.2.2:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
+ integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
+
+default-gateway@^6.0.3:
+ version "6.0.3"
+ resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71"
+ integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==
+ dependencies:
+ execa "^5.0.0"
+
+define-data-property@^1.0.1, define-data-property@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
+ integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
+ dependencies:
+ es-define-property "^1.0.0"
+ es-errors "^1.3.0"
+ gopd "^1.0.1"
+
+define-lazy-prop@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f"
+ integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==
+
+define-properties@^1.1.3, define-properties@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c"
+ integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==
+ dependencies:
+ define-data-property "^1.0.1"
+ has-property-descriptors "^1.0.0"
+ object-keys "^1.1.1"
+
+delayed-stream@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+ integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
+
+depd@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
+ integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
+
+depd@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
+ integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==
+
+dequal@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be"
+ integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==
+
+destroy@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
+ integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
+
+detect-libc@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
+ integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==
+
+detect-newline@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
+ integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==
+
+detect-node@^2.0.4:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
+ integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
+
+detect-port-alt@^1.1.6:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/detect-port-alt/-/detect-port-alt-1.1.6.tgz#24707deabe932d4a3cf621302027c2b266568275"
+ integrity sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==
+ dependencies:
+ address "^1.0.1"
+ debug "^2.6.0"
+
+didyoumean@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
+ integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==
+
+diff-sequences@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327"
+ integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==
+
+diff-sequences@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921"
+ integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==
+
+dir-glob@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
+ integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
+ dependencies:
+ path-type "^4.0.0"
+
+dlv@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79"
+ integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
+
+dns-packet@^5.2.2:
+ version "5.6.1"
+ resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.6.1.tgz#ae888ad425a9d1478a0674256ab866de1012cf2f"
+ integrity sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==
+ dependencies:
+ "@leichtgewicht/ip-codec" "^2.0.1"
+
+doctrine@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
+ integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==
+ dependencies:
+ esutils "^2.0.2"
+
+doctrine@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
+ integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
+ dependencies:
+ esutils "^2.0.2"
+
+dom-accessibility-api@^0.5.9:
+ version "0.5.16"
+ resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz#5a7429e6066eb3664d911e33fb0e45de8eb08453"
+ integrity sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==
+
+dom-accessibility-api@^0.6.3:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz#993e925cc1d73f2c662e7d75dd5a5445259a8fd8"
+ integrity sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==
+
+dom-converter@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768"
+ integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==
+ dependencies:
+ utila "~0.4"
+
+dom-serializer@0:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51"
+ integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==
+ dependencies:
+ domelementtype "^2.0.1"
+ entities "^2.0.0"
+
+dom-serializer@^1.0.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30"
+ integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==
+ dependencies:
+ domelementtype "^2.0.1"
+ domhandler "^4.2.0"
+ entities "^2.0.0"
+
+domelementtype@1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f"
+ integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==
+
+domelementtype@^2.0.1, domelementtype@^2.2.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
+ integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
+
+domexception@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304"
+ integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==
+ dependencies:
+ webidl-conversions "^5.0.0"
+
+domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c"
+ integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==
+ dependencies:
+ domelementtype "^2.2.0"
+
+domutils@^1.7.0:
+ version "1.7.0"
+ resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
+ integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==
+ dependencies:
+ dom-serializer "0"
+ domelementtype "1"
+
+domutils@^2.5.2, domutils@^2.8.0:
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
+ integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
+ dependencies:
+ dom-serializer "^1.0.1"
+ domelementtype "^2.2.0"
+ domhandler "^4.2.0"
+
+dot-case@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751"
+ integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==
+ dependencies:
+ no-case "^3.0.4"
+ tslib "^2.0.3"
+
+dotenv-expand@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-5.1.0.tgz#3fbaf020bfd794884072ea26b1e9791d45a629f0"
+ integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==
+
+dotenv@^10.0.0:
+ version "10.0.0"
+ resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81"
+ integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==
+
+dunder-proto@^1.0.0, dunder-proto@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a"
+ integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==
+ dependencies:
+ call-bind-apply-helpers "^1.0.1"
+ es-errors "^1.3.0"
+ gopd "^1.2.0"
+
+duplexer@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
+ integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==
+
+eastasianwidth@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
+ integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
+
+ee-first@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
+ integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
+
+ejs@^3.1.6:
+ version "3.1.10"
+ resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b"
+ integrity sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==
+ dependencies:
+ jake "^10.8.5"
+
+electron-to-chromium@^1.5.73:
+ version "1.5.74"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.74.tgz#cb886b504a6467e4c00bea3317edb38393c53413"
+ integrity sha512-ck3//9RC+6oss/1Bh9tiAVFy5vfSKbRHAFh7Z3/eTRkEqJeWgymloShB17Vg3Z4nmDNp35vAd1BZ6CMW4Wt6Iw==
+
+emittery@^0.10.2:
+ version "0.10.2"
+ resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.2.tgz#902eec8aedb8c41938c46e9385e9db7e03182933"
+ integrity sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==
+
+emittery@^0.8.1:
+ version "0.8.1"
+ resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860"
+ integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==
+
+emoji-regex@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+ integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+
+emoji-regex@^9.2.2:
+ version "9.2.2"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
+ integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
+
+emojis-list@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
+ integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
+
+encodeurl@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
+ integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
+
+encodeurl@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58"
+ integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==
+
+enhanced-resolve@^5.17.1:
+ version "5.17.1"
+ resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15"
+ integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==
+ dependencies:
+ graceful-fs "^4.2.4"
+ tapable "^2.2.0"
+
+entities@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
+ integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
+
+error-ex@^1.3.1:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
+ integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
+ dependencies:
+ is-arrayish "^0.2.1"
+
+error-stack-parser@^2.0.6:
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz#229cb01cdbfa84440bfa91876285b94680188286"
+ integrity sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==
+ dependencies:
+ stackframe "^1.3.4"
+
+es-abstract@^1.17.2, es-abstract@^1.17.5, es-abstract@^1.23.2, es-abstract@^1.23.3, es-abstract@^1.23.5, es-abstract@^1.23.6:
+ version "1.23.6"
+ resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.6.tgz#55f0e1ce7128995cc04ace0a57d7dca348345108"
+ integrity sha512-Ifco6n3yj2tMZDWNLyloZrytt9lqqlwvS83P3HtaETR0NUOYnIULGGHpktqYGObGy+8wc1okO25p8TjemhImvA==
+ dependencies:
+ array-buffer-byte-length "^1.0.1"
+ arraybuffer.prototype.slice "^1.0.4"
+ available-typed-arrays "^1.0.7"
+ call-bind "^1.0.8"
+ call-bound "^1.0.3"
+ data-view-buffer "^1.0.1"
+ data-view-byte-length "^1.0.1"
+ data-view-byte-offset "^1.0.0"
+ es-define-property "^1.0.1"
+ es-errors "^1.3.0"
+ es-object-atoms "^1.0.0"
+ es-set-tostringtag "^2.0.3"
+ es-to-primitive "^1.3.0"
+ function.prototype.name "^1.1.7"
+ get-intrinsic "^1.2.6"
+ get-symbol-description "^1.0.2"
+ globalthis "^1.0.4"
+ gopd "^1.2.0"
+ has-property-descriptors "^1.0.2"
+ has-proto "^1.2.0"
+ has-symbols "^1.1.0"
+ hasown "^2.0.2"
+ internal-slot "^1.1.0"
+ is-array-buffer "^3.0.4"
+ is-callable "^1.2.7"
+ is-data-view "^1.0.2"
+ is-negative-zero "^2.0.3"
+ is-regex "^1.2.1"
+ is-shared-array-buffer "^1.0.3"
+ is-string "^1.1.1"
+ is-typed-array "^1.1.13"
+ is-weakref "^1.1.0"
+ math-intrinsics "^1.0.0"
+ object-inspect "^1.13.3"
+ object-keys "^1.1.1"
+ object.assign "^4.1.5"
+ regexp.prototype.flags "^1.5.3"
+ safe-array-concat "^1.1.3"
+ safe-regex-test "^1.1.0"
+ string.prototype.trim "^1.2.10"
+ string.prototype.trimend "^1.0.9"
+ string.prototype.trimstart "^1.0.8"
+ typed-array-buffer "^1.0.2"
+ typed-array-byte-length "^1.0.1"
+ typed-array-byte-offset "^1.0.3"
+ typed-array-length "^1.0.7"
+ unbox-primitive "^1.0.2"
+ which-typed-array "^1.1.16"
+
+es-array-method-boxes-properly@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e"
+ integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==
+
+es-define-property@^1.0.0, es-define-property@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa"
+ integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==
+
+es-errors@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
+ integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
+
+es-iterator-helpers@^1.1.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.2.0.tgz#2f1a3ab998b30cb2d10b195b587c6d9ebdebf152"
+ integrity sha512-tpxqxncxnpw3c93u8n3VOzACmRFoVmWJqbWXvX/JfKbkhBw1oslgPrUfeSt2psuqyEJFD6N/9lg5i7bsKpoq+Q==
+ dependencies:
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.3"
+ es-errors "^1.3.0"
+ es-set-tostringtag "^2.0.3"
+ function-bind "^1.1.2"
+ get-intrinsic "^1.2.4"
+ globalthis "^1.0.4"
+ gopd "^1.0.1"
+ has-property-descriptors "^1.0.2"
+ has-proto "^1.0.3"
+ has-symbols "^1.0.3"
+ internal-slot "^1.0.7"
+ iterator.prototype "^1.1.3"
+ safe-array-concat "^1.1.2"
+
+es-module-lexer@^1.2.1:
+ version "1.5.4"
+ resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.4.tgz#a8efec3a3da991e60efa6b633a7cad6ab8d26b78"
+ integrity sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==
+
+es-object-atoms@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941"
+ integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==
+ dependencies:
+ es-errors "^1.3.0"
+
+es-set-tostringtag@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777"
+ integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==
+ dependencies:
+ get-intrinsic "^1.2.4"
+ has-tostringtag "^1.0.2"
+ hasown "^2.0.1"
+
+es-shim-unscopables@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763"
+ integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==
+ dependencies:
+ hasown "^2.0.0"
+
+es-to-primitive@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.3.0.tgz#96c89c82cc49fd8794a24835ba3e1ff87f214e18"
+ integrity sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==
+ dependencies:
+ is-callable "^1.2.7"
+ is-date-object "^1.0.5"
+ is-symbol "^1.0.4"
+
+escalade@^3.1.1, escalade@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5"
+ integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==
+
+escape-html@~1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+ integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
+
+escape-string-regexp@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+ integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
+
+escape-string-regexp@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344"
+ integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
+
+escape-string-regexp@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
+ integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
+
+escodegen@^1.8.1:
+ version "1.14.3"
+ resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503"
+ integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==
+ dependencies:
+ esprima "^4.0.1"
+ estraverse "^4.2.0"
+ esutils "^2.0.2"
+ optionator "^0.8.1"
+ optionalDependencies:
+ source-map "~0.6.1"
+
+escodegen@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17"
+ integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==
+ dependencies:
+ esprima "^4.0.1"
+ estraverse "^5.2.0"
+ esutils "^2.0.2"
+ optionalDependencies:
+ source-map "~0.6.1"
+
+eslint-config-airbnb-base@^15.0.0:
+ version "15.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-15.0.0.tgz#6b09add90ac79c2f8d723a2580e07f3925afd236"
+ integrity sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==
+ dependencies:
+ confusing-browser-globals "^1.0.10"
+ object.assign "^4.1.2"
+ object.entries "^1.1.5"
+ semver "^6.3.0"
+
+eslint-config-airbnb-typescript@^18.0.0:
+ version "18.0.0"
+ resolved "https://registry.yarnpkg.com/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-18.0.0.tgz#b1646db4134858d704b1d2bee47e1d72c180315f"
+ integrity sha512-oc+Lxzgzsu8FQyFVa4QFaVKiitTYiiW3frB9KYW5OWdPrqFc7FzxgB20hP4cHMlr+MBzGcLl3jnCOVOydL9mIg==
+ dependencies:
+ eslint-config-airbnb-base "^15.0.0"
+
+eslint-config-airbnb@^19.0.4:
+ version "19.0.4"
+ resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz#84d4c3490ad70a0ffa571138ebcdea6ab085fdc3"
+ integrity sha512-T75QYQVQX57jiNgpF9r1KegMICE94VYwoFQyMGhrvc+lB8YF2E/M/PYDaQe1AJcWaEgqLE+ErXV1Og/+6Vyzew==
+ dependencies:
+ eslint-config-airbnb-base "^15.0.0"
+ object.assign "^4.1.2"
+ object.entries "^1.1.5"
+
+eslint-config-prettier@^9.1.0:
+ version "9.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f"
+ integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==
+
+eslint-config-react-app@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz#73ba3929978001c5c86274c017ea57eb5fa644b4"
+ integrity sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==
+ dependencies:
+ "@babel/core" "^7.16.0"
+ "@babel/eslint-parser" "^7.16.3"
+ "@rushstack/eslint-patch" "^1.1.0"
+ "@typescript-eslint/eslint-plugin" "^5.5.0"
+ "@typescript-eslint/parser" "^5.5.0"
+ babel-preset-react-app "^10.0.1"
+ confusing-browser-globals "^1.0.11"
+ eslint-plugin-flowtype "^8.0.3"
+ eslint-plugin-import "^2.25.3"
+ eslint-plugin-jest "^25.3.0"
+ eslint-plugin-jsx-a11y "^6.5.1"
+ eslint-plugin-react "^7.27.1"
+ eslint-plugin-react-hooks "^4.3.0"
+ eslint-plugin-testing-library "^5.0.1"
+
+eslint-import-resolver-node@^0.3.9:
+ version "0.3.9"
+ resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac"
+ integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==
+ dependencies:
+ debug "^3.2.7"
+ is-core-module "^2.13.0"
+ resolve "^1.22.4"
+
+eslint-module-utils@^2.12.0:
+ version "2.12.0"
+ resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz#fe4cfb948d61f49203d7b08871982b65b9af0b0b"
+ integrity sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==
+ dependencies:
+ debug "^3.2.7"
+
+eslint-plugin-flowtype@^8.0.3:
+ version "8.0.3"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-8.0.3.tgz#e1557e37118f24734aa3122e7536a038d34a4912"
+ integrity sha512-dX8l6qUL6O+fYPtpNRideCFSpmWOUVx5QcaGLVqe/vlDiBSe4vYljDWDETwnyFzpl7By/WVIu6rcrniCgH9BqQ==
+ dependencies:
+ lodash "^4.17.21"
+ string-natural-compare "^3.0.1"
+
+eslint-plugin-import@^2.25.3, eslint-plugin-import@^2.31.0:
+ version "2.31.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz#310ce7e720ca1d9c0bb3f69adfd1c6bdd7d9e0e7"
+ integrity sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==
+ dependencies:
+ "@rtsao/scc" "^1.1.0"
+ array-includes "^3.1.8"
+ array.prototype.findlastindex "^1.2.5"
+ array.prototype.flat "^1.3.2"
+ array.prototype.flatmap "^1.3.2"
+ debug "^3.2.7"
+ doctrine "^2.1.0"
+ eslint-import-resolver-node "^0.3.9"
+ eslint-module-utils "^2.12.0"
+ hasown "^2.0.2"
+ is-core-module "^2.15.1"
+ is-glob "^4.0.3"
+ minimatch "^3.1.2"
+ object.fromentries "^2.0.8"
+ object.groupby "^1.0.3"
+ object.values "^1.2.0"
+ semver "^6.3.1"
+ string.prototype.trimend "^1.0.8"
+ tsconfig-paths "^3.15.0"
+
+eslint-plugin-jest@^25.3.0:
+ version "25.7.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-25.7.0.tgz#ff4ac97520b53a96187bad9c9814e7d00de09a6a"
+ integrity sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==
+ dependencies:
+ "@typescript-eslint/experimental-utils" "^5.0.0"
+
+eslint-plugin-jest@^28.9.0:
+ version "28.9.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-28.9.0.tgz#19168dfaed124339cd2252c4c4d1ac3688aeb243"
+ integrity sha512-rLu1s1Wf96TgUUxSw6loVIkNtUjq1Re7A9QdCCHSohnvXEBAjuL420h0T/fMmkQlNsQP2GhQzEUpYHPfxBkvYQ==
+ dependencies:
+ "@typescript-eslint/utils" "^6.0.0 || ^7.0.0 || ^8.0.0"
+
+eslint-plugin-jsx-a11y@^6.10.2, eslint-plugin-jsx-a11y@^6.5.1:
+ version "6.10.2"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz#d2812bb23bf1ab4665f1718ea442e8372e638483"
+ integrity sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==
+ dependencies:
+ aria-query "^5.3.2"
+ array-includes "^3.1.8"
+ array.prototype.flatmap "^1.3.2"
+ ast-types-flow "^0.0.8"
+ axe-core "^4.10.0"
+ axobject-query "^4.1.0"
+ damerau-levenshtein "^1.0.8"
+ emoji-regex "^9.2.2"
+ hasown "^2.0.2"
+ jsx-ast-utils "^3.3.5"
+ language-tags "^1.0.9"
+ minimatch "^3.1.2"
+ object.fromentries "^2.0.8"
+ safe-regex-test "^1.0.3"
+ string.prototype.includes "^2.0.1"
+
+eslint-plugin-prettier@^5.2.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz#d1c8f972d8f60e414c25465c163d16f209411f95"
+ integrity sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==
+ dependencies:
+ prettier-linter-helpers "^1.0.0"
+ synckit "^0.9.1"
+
+eslint-plugin-react-hooks@^4.3.0:
+ version "4.6.2"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.2.tgz#c829eb06c0e6f484b3fbb85a97e57784f328c596"
+ integrity sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==
+
+eslint-plugin-react-hooks@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.1.0.tgz#3d34e37d5770866c34b87d5b499f5f0b53bf0854"
+ integrity sha512-mpJRtPgHN2tNAvZ35AMfqeB3Xqeo273QxrHJsbBEPWODRM4r0yB6jfoROqKEYrOn27UtRPpcpHc2UqyBSuUNTw==
+
+eslint-plugin-react@^7.27.1, eslint-plugin-react@^7.37.2:
+ version "7.37.2"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.2.tgz#cd0935987876ba2900df2f58339f6d92305acc7a"
+ integrity sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==
+ dependencies:
+ array-includes "^3.1.8"
+ array.prototype.findlast "^1.2.5"
+ array.prototype.flatmap "^1.3.2"
+ array.prototype.tosorted "^1.1.4"
+ doctrine "^2.1.0"
+ es-iterator-helpers "^1.1.0"
+ estraverse "^5.3.0"
+ hasown "^2.0.2"
+ jsx-ast-utils "^2.4.1 || ^3.0.0"
+ minimatch "^3.1.2"
+ object.entries "^1.1.8"
+ object.fromentries "^2.0.8"
+ object.values "^1.2.0"
+ prop-types "^15.8.1"
+ resolve "^2.0.0-next.5"
+ semver "^6.3.1"
+ string.prototype.matchall "^4.0.11"
+ string.prototype.repeat "^1.0.0"
+
+eslint-plugin-testing-library@^5.0.1:
+ version "5.11.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.1.tgz#5b46cdae96d4a78918711c0b4792f90088e62d20"
+ integrity sha512-5eX9e1Kc2PqVRed3taaLnAAqPZGEX75C+M/rXzUAI3wIg/ZxzUm1OVAwfe/O+vE+6YXOLetSe9g5GKD2ecXipw==
+ dependencies:
+ "@typescript-eslint/utils" "^5.58.0"
+
+eslint-scope@5.1.1, eslint-scope@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
+ integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
+ dependencies:
+ esrecurse "^4.3.0"
+ estraverse "^4.1.1"
+
+eslint-scope@^7.2.2:
+ version "7.2.2"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f"
+ integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==
+ dependencies:
+ esrecurse "^4.3.0"
+ estraverse "^5.2.0"
+
+eslint-scope@^8.2.0:
+ version "8.2.0"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.2.0.tgz#377aa6f1cb5dc7592cfd0b7f892fd0cf352ce442"
+ integrity sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==
+ dependencies:
+ esrecurse "^4.3.0"
+ estraverse "^5.2.0"
+
+eslint-visitor-keys@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
+ integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==
+
+eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3:
+ version "3.4.3"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800"
+ integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==
+
+eslint-visitor-keys@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45"
+ integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==
+
+eslint-webpack-plugin@^3.1.1:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/eslint-webpack-plugin/-/eslint-webpack-plugin-3.2.0.tgz#1978cdb9edc461e4b0195a20da950cf57988347c"
+ integrity sha512-avrKcGncpPbPSUHX6B3stNGzkKFto3eL+DKM4+VyMrVnhPc3vRczVlCq3uhuFOdRvDHTVXuzwk1ZKUrqDQHQ9w==
+ dependencies:
+ "@types/eslint" "^7.29.0 || ^8.4.1"
+ jest-worker "^28.0.2"
+ micromatch "^4.0.5"
+ normalize-path "^3.0.0"
+ schema-utils "^4.0.0"
+
+eslint@^8.3.0:
+ version "8.57.1"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9"
+ integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==
+ dependencies:
+ "@eslint-community/eslint-utils" "^4.2.0"
+ "@eslint-community/regexpp" "^4.6.1"
+ "@eslint/eslintrc" "^2.1.4"
+ "@eslint/js" "8.57.1"
+ "@humanwhocodes/config-array" "^0.13.0"
+ "@humanwhocodes/module-importer" "^1.0.1"
+ "@nodelib/fs.walk" "^1.2.8"
+ "@ungap/structured-clone" "^1.2.0"
+ ajv "^6.12.4"
+ chalk "^4.0.0"
+ cross-spawn "^7.0.2"
+ debug "^4.3.2"
+ doctrine "^3.0.0"
+ escape-string-regexp "^4.0.0"
+ eslint-scope "^7.2.2"
+ eslint-visitor-keys "^3.4.3"
+ espree "^9.6.1"
+ esquery "^1.4.2"
+ esutils "^2.0.2"
+ fast-deep-equal "^3.1.3"
+ file-entry-cache "^6.0.1"
+ find-up "^5.0.0"
+ glob-parent "^6.0.2"
+ globals "^13.19.0"
+ graphemer "^1.4.0"
+ ignore "^5.2.0"
+ imurmurhash "^0.1.4"
+ is-glob "^4.0.0"
+ is-path-inside "^3.0.3"
+ js-yaml "^4.1.0"
+ json-stable-stringify-without-jsonify "^1.0.1"
+ levn "^0.4.1"
+ lodash.merge "^4.6.2"
+ minimatch "^3.1.2"
+ natural-compare "^1.4.0"
+ optionator "^0.9.3"
+ strip-ansi "^6.0.1"
+ text-table "^0.2.0"
+
+eslint@^9.17.0:
+ version "9.17.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.17.0.tgz#faa1facb5dd042172fdc520106984b5c2421bb0c"
+ integrity sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA==
+ dependencies:
+ "@eslint-community/eslint-utils" "^4.2.0"
+ "@eslint-community/regexpp" "^4.12.1"
+ "@eslint/config-array" "^0.19.0"
+ "@eslint/core" "^0.9.0"
+ "@eslint/eslintrc" "^3.2.0"
+ "@eslint/js" "9.17.0"
+ "@eslint/plugin-kit" "^0.2.3"
+ "@humanfs/node" "^0.16.6"
+ "@humanwhocodes/module-importer" "^1.0.1"
+ "@humanwhocodes/retry" "^0.4.1"
+ "@types/estree" "^1.0.6"
+ "@types/json-schema" "^7.0.15"
+ ajv "^6.12.4"
+ chalk "^4.0.0"
+ cross-spawn "^7.0.6"
+ debug "^4.3.2"
+ escape-string-regexp "^4.0.0"
+ eslint-scope "^8.2.0"
+ eslint-visitor-keys "^4.2.0"
+ espree "^10.3.0"
+ esquery "^1.5.0"
+ esutils "^2.0.2"
+ fast-deep-equal "^3.1.3"
+ file-entry-cache "^8.0.0"
+ find-up "^5.0.0"
+ glob-parent "^6.0.2"
+ ignore "^5.2.0"
+ imurmurhash "^0.1.4"
+ is-glob "^4.0.0"
+ json-stable-stringify-without-jsonify "^1.0.1"
+ lodash.merge "^4.6.2"
+ minimatch "^3.1.2"
+ natural-compare "^1.4.0"
+ optionator "^0.9.3"
+
+espree@^10.0.1, espree@^10.3.0:
+ version "10.3.0"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a"
+ integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==
+ dependencies:
+ acorn "^8.14.0"
+ acorn-jsx "^5.3.2"
+ eslint-visitor-keys "^4.2.0"
+
+espree@^9.6.0, espree@^9.6.1:
+ version "9.6.1"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f"
+ integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==
+ dependencies:
+ acorn "^8.9.0"
+ acorn-jsx "^5.3.2"
+ eslint-visitor-keys "^3.4.1"
+
+esprima@1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.2.tgz#76a0fd66fcfe154fd292667dc264019750b1657b"
+ integrity sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==
+
+esprima@^4.0.0, esprima@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
+ integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
+
+esquery@^1.4.2, esquery@^1.5.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7"
+ integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==
+ dependencies:
+ estraverse "^5.1.0"
+
+esrecurse@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
+ integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
+ dependencies:
+ estraverse "^5.2.0"
+
+estraverse@^4.1.1, estraverse@^4.2.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
+ integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
+
+estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
+ integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
+
+estree-walker@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700"
+ integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==
+
+esutils@^2.0.2:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64"
+ integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==
+
+etag@~1.8.1:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
+ integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
+
+eventemitter3@^4.0.0:
+ version "4.0.7"
+ resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
+ integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
+
+events@^3.2.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
+ integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
+
+execa@^5.0.0:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
+ integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
+ dependencies:
+ cross-spawn "^7.0.3"
+ get-stream "^6.0.0"
+ human-signals "^2.1.0"
+ is-stream "^2.0.0"
+ merge-stream "^2.0.0"
+ npm-run-path "^4.0.1"
+ onetime "^5.1.2"
+ signal-exit "^3.0.3"
+ strip-final-newline "^2.0.0"
+
+exit@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
+ integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==
+
+expect@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/expect/-/expect-27.5.1.tgz#83ce59f1e5bdf5f9d2b94b61d2050db48f3fef74"
+ integrity sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==
+ dependencies:
+ "@jest/types" "^27.5.1"
+ jest-get-type "^27.5.1"
+ jest-matcher-utils "^27.5.1"
+ jest-message-util "^27.5.1"
+
+expect@^29.0.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc"
+ integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==
+ dependencies:
+ "@jest/expect-utils" "^29.7.0"
+ jest-get-type "^29.6.3"
+ jest-matcher-utils "^29.7.0"
+ jest-message-util "^29.7.0"
+ jest-util "^29.7.0"
+
+express@^4.17.3:
+ version "4.21.2"
+ resolved "https://registry.yarnpkg.com/express/-/express-4.21.2.tgz#cf250e48362174ead6cea4a566abef0162c1ec32"
+ integrity sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==
+ dependencies:
+ accepts "~1.3.8"
+ array-flatten "1.1.1"
+ body-parser "1.20.3"
+ content-disposition "0.5.4"
+ content-type "~1.0.4"
+ cookie "0.7.1"
+ cookie-signature "1.0.6"
+ debug "2.6.9"
+ depd "2.0.0"
+ encodeurl "~2.0.0"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ finalhandler "1.3.1"
+ fresh "0.5.2"
+ http-errors "2.0.0"
+ merge-descriptors "1.0.3"
+ methods "~1.1.2"
+ on-finished "2.4.1"
+ parseurl "~1.3.3"
+ path-to-regexp "0.1.12"
+ proxy-addr "~2.0.7"
+ qs "6.13.0"
+ range-parser "~1.2.1"
+ safe-buffer "5.2.1"
+ send "0.19.0"
+ serve-static "1.16.2"
+ setprototypeof "1.2.0"
+ statuses "2.0.1"
+ type-is "~1.6.18"
+ utils-merge "1.0.1"
+ vary "~1.1.2"
+
+fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
+ integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
+
+fast-diff@^1.1.2:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0"
+ integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==
+
+fast-glob@^3.2.9, fast-glob@^3.3.2:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
+ integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
+ dependencies:
+ "@nodelib/fs.stat" "^2.0.2"
+ "@nodelib/fs.walk" "^1.2.3"
+ glob-parent "^5.1.2"
+ merge2 "^1.3.0"
+ micromatch "^4.0.4"
+
+fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+ integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
+
+fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+ integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==
+
+fast-uri@^3.0.1:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.3.tgz#892a1c91802d5d7860de728f18608a0573142241"
+ integrity sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==
+
+fastq@^1.6.0:
+ version "1.17.1"
+ resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47"
+ integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==
+ dependencies:
+ reusify "^1.0.4"
+
+faye-websocket@^0.11.3:
+ version "0.11.4"
+ resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da"
+ integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==
+ dependencies:
+ websocket-driver ">=0.5.1"
+
+fb-watchman@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c"
+ integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==
+ dependencies:
+ bser "2.1.1"
+
+file-entry-cache@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
+ integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==
+ dependencies:
+ flat-cache "^3.0.4"
+
+file-entry-cache@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f"
+ integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==
+ dependencies:
+ flat-cache "^4.0.0"
+
+file-loader@^6.2.0:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d"
+ integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==
+ dependencies:
+ loader-utils "^2.0.0"
+ schema-utils "^3.0.0"
+
+filelist@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5"
+ integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==
+ dependencies:
+ minimatch "^5.0.1"
+
+filesize@^8.0.6:
+ version "8.0.7"
+ resolved "https://registry.yarnpkg.com/filesize/-/filesize-8.0.7.tgz#695e70d80f4e47012c132d57a059e80c6b580bd8"
+ integrity sha512-pjmC+bkIF8XI7fWaH8KxHcZL3DPybs1roSKP4rKDvy20tAWwIObE4+JIseG2byfGKhud5ZnM4YSGKBz7Sh0ndQ==
+
+fill-range@^7.1.1:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
+ integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
+ dependencies:
+ to-regex-range "^5.0.1"
+
+finalhandler@1.3.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019"
+ integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==
+ dependencies:
+ debug "2.6.9"
+ encodeurl "~2.0.0"
+ escape-html "~1.0.3"
+ on-finished "2.4.1"
+ parseurl "~1.3.3"
+ statuses "2.0.1"
+ unpipe "~1.0.0"
+
+find-cache-dir@^3.3.1:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b"
+ integrity sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==
+ dependencies:
+ commondir "^1.0.1"
+ make-dir "^3.0.2"
+ pkg-dir "^4.1.0"
+
+find-up@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
+ integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
+ dependencies:
+ locate-path "^3.0.0"
+
+find-up@^4.0.0, find-up@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
+ integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
+ dependencies:
+ locate-path "^5.0.0"
+ path-exists "^4.0.0"
+
+find-up@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
+ integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
+ dependencies:
+ locate-path "^6.0.0"
+ path-exists "^4.0.0"
+
+flat-cache@^3.0.4:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee"
+ integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==
+ dependencies:
+ flatted "^3.2.9"
+ keyv "^4.5.3"
+ rimraf "^3.0.2"
+
+flat-cache@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c"
+ integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==
+ dependencies:
+ flatted "^3.2.9"
+ keyv "^4.5.4"
+
+flatted@^3.2.9:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27"
+ integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==
+
+follow-redirects@^1.0.0:
+ version "1.15.9"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1"
+ integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==
+
+for-each@^0.3.3:
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
+ integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==
+ dependencies:
+ is-callable "^1.1.3"
+
+foreground-child@^3.1.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77"
+ integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==
+ dependencies:
+ cross-spawn "^7.0.0"
+ signal-exit "^4.0.1"
+
+fork-ts-checker-webpack-plugin@^6.5.0:
+ version "6.5.3"
+ resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.3.tgz#eda2eff6e22476a2688d10661688c47f611b37f3"
+ integrity sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==
+ dependencies:
+ "@babel/code-frame" "^7.8.3"
+ "@types/json-schema" "^7.0.5"
+ chalk "^4.1.0"
+ chokidar "^3.4.2"
+ cosmiconfig "^6.0.0"
+ deepmerge "^4.2.2"
+ fs-extra "^9.0.0"
+ glob "^7.1.6"
+ memfs "^3.1.2"
+ minimatch "^3.0.4"
+ schema-utils "2.7.0"
+ semver "^7.3.2"
+ tapable "^1.0.0"
+
+form-data@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.2.tgz#83ad9ced7c03feaad97e293d6f6091011e1659c8"
+ integrity sha512-sJe+TQb2vIaIyO783qN6BlMYWMw3WBOHA1Ay2qxsnjuafEOQFJ2JakedOQirT6D5XPRxDvS7AHYyem9fTpb4LQ==
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.8"
+ mime-types "^2.1.12"
+
+forwarded@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811"
+ integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
+
+fraction.js@^4.3.7:
+ version "4.3.7"
+ resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7"
+ integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==
+
+fresh@0.5.2:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
+ integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
+
+fs-extra@^10.0.0:
+ version "10.1.0"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
+ integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==
+ dependencies:
+ graceful-fs "^4.2.0"
+ jsonfile "^6.0.1"
+ universalify "^2.0.0"
+
+fs-extra@^9.0.0, fs-extra@^9.0.1:
+ version "9.1.0"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d"
+ integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==
+ dependencies:
+ at-least-node "^1.0.0"
+ graceful-fs "^4.2.0"
+ jsonfile "^6.0.1"
+ universalify "^2.0.0"
+
+fs-monkey@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.6.tgz#8ead082953e88d992cf3ff844faa907b26756da2"
+ integrity sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+ integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
+
+fsevents@^2.3.2, fsevents@~2.3.2:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
+ integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
+
+function-bind@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
+ integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
+
+function.prototype.name@^1.1.6, function.prototype.name@^1.1.7:
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.7.tgz#9df48ea5f746bf577d7e15b5da89df8952a98e7b"
+ integrity sha512-2g4x+HqTJKM9zcJqBSpjoRmdcPFtJM60J3xJisTQSXBWka5XqyBN/2tNUgma1mztTXyDuUsEtYe5qcs7xYzYQA==
+ dependencies:
+ call-bind "^1.0.8"
+ define-properties "^1.2.1"
+ functions-have-names "^1.2.3"
+ hasown "^2.0.2"
+ is-callable "^1.2.7"
+
+functions-have-names@^1.2.3:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834"
+ integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==
+
+gensync@^1.0.0-beta.2:
+ version "1.0.0-beta.2"
+ resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
+ integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
+
+get-caller-file@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
+ integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+
+get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6:
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.6.tgz#43dd3dd0e7b49b82b2dfcad10dc824bf7fc265d5"
+ integrity sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA==
+ dependencies:
+ call-bind-apply-helpers "^1.0.1"
+ dunder-proto "^1.0.0"
+ es-define-property "^1.0.1"
+ es-errors "^1.3.0"
+ es-object-atoms "^1.0.0"
+ function-bind "^1.1.2"
+ gopd "^1.2.0"
+ has-symbols "^1.1.0"
+ hasown "^2.0.2"
+ math-intrinsics "^1.0.0"
+
+get-own-enumerable-property-symbols@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664"
+ integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==
+
+get-package-type@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a"
+ integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==
+
+get-stream@^6.0.0:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
+ integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
+
+get-symbol-description@^1.0.2:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz#7bdd54e0befe8ffc9f3b4e203220d9f1e881b6ee"
+ integrity sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==
+ dependencies:
+ call-bound "^1.0.3"
+ es-errors "^1.3.0"
+ get-intrinsic "^1.2.6"
+
+glob-parent@^5.1.2, glob-parent@~5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+ integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
+ dependencies:
+ is-glob "^4.0.1"
+
+glob-parent@^6.0.2:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
+ integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
+ dependencies:
+ is-glob "^4.0.3"
+
+glob-to-regexp@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
+ integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
+
+glob@^10.3.10:
+ version "10.4.5"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956"
+ integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==
+ dependencies:
+ foreground-child "^3.1.0"
+ jackspeak "^3.1.2"
+ minimatch "^9.0.4"
+ minipass "^7.1.2"
+ package-json-from-dist "^1.0.0"
+ path-scurry "^1.11.1"
+
+glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
+ version "7.2.3"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
+ integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.1.1"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+global-modules@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780"
+ integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==
+ dependencies:
+ global-prefix "^3.0.0"
+
+global-prefix@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97"
+ integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==
+ dependencies:
+ ini "^1.3.5"
+ kind-of "^6.0.2"
+ which "^1.3.1"
+
+globals@^11.1.0:
+ version "11.12.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
+ integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
+
+globals@^13.19.0:
+ version "13.24.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171"
+ integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==
+ dependencies:
+ type-fest "^0.20.2"
+
+globals@^14.0.0:
+ version "14.0.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e"
+ integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==
+
+globalthis@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236"
+ integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==
+ dependencies:
+ define-properties "^1.2.1"
+ gopd "^1.0.1"
+
+globby@^11.0.4, globby@^11.1.0:
+ version "11.1.0"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
+ integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
+ dependencies:
+ array-union "^2.1.0"
+ dir-glob "^3.0.1"
+ fast-glob "^3.2.9"
+ ignore "^5.2.0"
+ merge2 "^1.4.1"
+ slash "^3.0.0"
+
+gopd@^1.0.1, gopd@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1"
+ integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==
+
+graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9:
+ version "4.2.11"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
+ integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
+
+graphemer@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6"
+ integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==
+
+gzip-size@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462"
+ integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==
+ dependencies:
+ duplexer "^0.1.2"
+
+handle-thing@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e"
+ integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==
+
+harmony-reflect@^1.4.6:
+ version "1.6.2"
+ resolved "https://registry.yarnpkg.com/harmony-reflect/-/harmony-reflect-1.6.2.tgz#31ecbd32e648a34d030d86adb67d4d47547fe710"
+ integrity sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g==
+
+has-bigints@^1.0.2:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.1.0.tgz#28607e965ac967e03cd2a2c70a2636a1edad49fe"
+ integrity sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==
+
+has-flag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+ integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
+
+has-flag@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+ integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+
+has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
+ integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
+ dependencies:
+ es-define-property "^1.0.0"
+
+has-proto@^1.0.3, has-proto@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.2.0.tgz#5de5a6eabd95fdffd9818b43055e8065e39fe9d5"
+ integrity sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==
+ dependencies:
+ dunder-proto "^1.0.0"
+
+has-symbols@^1.0.1, has-symbols@^1.0.3, has-symbols@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338"
+ integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==
+
+has-tostringtag@^1.0.0, has-tostringtag@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
+ integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==
+ dependencies:
+ has-symbols "^1.0.3"
+
+hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
+ integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
+ dependencies:
+ function-bind "^1.1.2"
+
+he@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
+ integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+
+hoopy@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d"
+ integrity sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==
+
+hpack.js@^2.1.6:
+ version "2.1.6"
+ resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2"
+ integrity sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==
+ dependencies:
+ inherits "^2.0.1"
+ obuf "^1.0.0"
+ readable-stream "^2.0.1"
+ wbuf "^1.1.0"
+
+html-encoding-sniffer@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3"
+ integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==
+ dependencies:
+ whatwg-encoding "^1.0.5"
+
+html-entities@^2.1.0, html-entities@^2.3.2:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.5.2.tgz#201a3cf95d3a15be7099521620d19dfb4f65359f"
+ integrity sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==
+
+html-escaper@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
+ integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
+
+html-minifier-terser@^6.0.2:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#bfc818934cc07918f6b3669f5774ecdfd48f32ab"
+ integrity sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==
+ dependencies:
+ camel-case "^4.1.2"
+ clean-css "^5.2.2"
+ commander "^8.3.0"
+ he "^1.2.0"
+ param-case "^3.0.4"
+ relateurl "^0.2.7"
+ terser "^5.10.0"
+
+html-webpack-plugin@^5.5.0:
+ version "5.6.3"
+ resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.6.3.tgz#a31145f0fee4184d53a794f9513147df1e653685"
+ integrity sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg==
+ dependencies:
+ "@types/html-minifier-terser" "^6.0.0"
+ html-minifier-terser "^6.0.2"
+ lodash "^4.17.21"
+ pretty-error "^4.0.0"
+ tapable "^2.0.0"
+
+htmlparser2@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
+ integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==
+ dependencies:
+ domelementtype "^2.0.1"
+ domhandler "^4.0.0"
+ domutils "^2.5.2"
+ entities "^2.0.0"
+
+http-deceiver@^1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
+ integrity sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==
+
+http-errors@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
+ integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
+ dependencies:
+ depd "2.0.0"
+ inherits "2.0.4"
+ setprototypeof "1.2.0"
+ statuses "2.0.1"
+ toidentifier "1.0.1"
+
+http-errors@~1.6.2:
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
+ integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==
+ dependencies:
+ depd "~1.1.2"
+ inherits "2.0.3"
+ setprototypeof "1.1.0"
+ statuses ">= 1.4.0 < 2"
+
+http-parser-js@>=0.5.1:
+ version "0.5.8"
+ resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3"
+ integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==
+
+http-proxy-agent@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a"
+ integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==
+ dependencies:
+ "@tootallnate/once" "1"
+ agent-base "6"
+ debug "4"
+
+http-proxy-middleware@^2.0.3:
+ version "2.0.7"
+ resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz#915f236d92ae98ef48278a95dedf17e991936ec6"
+ integrity sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==
+ dependencies:
+ "@types/http-proxy" "^1.17.8"
+ http-proxy "^1.18.1"
+ is-glob "^4.0.1"
+ is-plain-obj "^3.0.0"
+ micromatch "^4.0.2"
+
+http-proxy@^1.18.1:
+ version "1.18.1"
+ resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549"
+ integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==
+ dependencies:
+ eventemitter3 "^4.0.0"
+ follow-redirects "^1.0.0"
+ requires-port "^1.0.0"
+
+https-proxy-agent@^5.0.0:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
+ integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==
+ dependencies:
+ agent-base "6"
+ debug "4"
+
+human-signals@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
+ integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
+
+iconv-lite@0.4.24:
+ version "0.4.24"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+ integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3"
+
+iconv-lite@^0.6.3:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
+ integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3.0.0"
+
+icss-utils@^5.0.0, icss-utils@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae"
+ integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==
+
+idb@^7.0.1:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b"
+ integrity sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==
+
+identity-obj-proxy@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz#94d2bda96084453ef36fbc5aaec37e0f79f1fc14"
+ integrity sha512-00n6YnVHKrinT9t0d9+5yZC6UBNJANpYEQvL2LlX6Ab9lnmxzIRcEmTPuyGScvl1+jKuCICX1Z0Ab1pPKKdikA==
+ dependencies:
+ harmony-reflect "^1.4.6"
+
+ignore@^5.2.0, ignore@^5.3.1:
+ version "5.3.2"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5"
+ integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==
+
+immer@^10.0.3:
+ version "10.1.1"
+ resolved "https://registry.yarnpkg.com/immer/-/immer-10.1.1.tgz#206f344ea372d8ea176891545ee53ccc062db7bc"
+ integrity sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==
+
+immer@^9.0.7:
+ version "9.0.21"
+ resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.21.tgz#1e025ea31a40f24fb064f1fef23e931496330176"
+ integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==
+
+immutable@^5.0.2:
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/immutable/-/immutable-5.0.3.tgz#aa037e2313ea7b5d400cd9298fa14e404c933db1"
+ integrity sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==
+
+import-fresh@^3.1.0, import-fresh@^3.2.1:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
+ integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
+ dependencies:
+ parent-module "^1.0.0"
+ resolve-from "^4.0.0"
+
+import-local@^3.0.2:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260"
+ integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==
+ dependencies:
+ pkg-dir "^4.2.0"
+ resolve-cwd "^3.0.0"
+
+imurmurhash@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+ integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
+
+indent-string@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
+ integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+ integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+inherits@2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+ integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==
+
+ini@^1.3.5:
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
+ integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
+
+internal-slot@^1.0.7, internal-slot@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.1.0.tgz#1eac91762947d2f7056bc838d93e13b2e9604961"
+ integrity sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==
+ dependencies:
+ es-errors "^1.3.0"
+ hasown "^2.0.2"
+ side-channel "^1.1.0"
+
+ipaddr.js@1.9.1:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
+ integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
+
+ipaddr.js@^2.0.1:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8"
+ integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==
+
+is-array-buffer@^3.0.4:
+ version "3.0.5"
+ resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz#65742e1e687bd2cc666253068fd8707fe4d44280"
+ integrity sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==
+ dependencies:
+ call-bind "^1.0.8"
+ call-bound "^1.0.3"
+ get-intrinsic "^1.2.6"
+
+is-arrayish@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+ integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
+
+is-async-function@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646"
+ integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==
+ dependencies:
+ has-tostringtag "^1.0.0"
+
+is-bigint@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.1.0.tgz#dda7a3445df57a42583db4228682eba7c4170672"
+ integrity sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==
+ dependencies:
+ has-bigints "^1.0.2"
+
+is-binary-path@~2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
+ integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
+ dependencies:
+ binary-extensions "^2.0.0"
+
+is-boolean-object@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.2.1.tgz#c20d0c654be05da4fbc23c562635c019e93daf89"
+ integrity sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng==
+ dependencies:
+ call-bound "^1.0.2"
+ has-tostringtag "^1.0.2"
+
+is-callable@^1.1.3, is-callable@^1.2.7:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
+ integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
+
+is-core-module@^2.13.0, is-core-module@^2.15.1, is-core-module@^2.16.0:
+ version "2.16.0"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.0.tgz#6c01ffdd5e33c49c1d2abfa93334a85cb56bd81c"
+ integrity sha512-urTSINYfAYgcbLb0yDQ6egFm6h3Mo1DcF9EkyXSRjjzdHbsulg01qhwWuXdOoUBuTkbQ80KDboXa0vFJ+BDH+g==
+ dependencies:
+ hasown "^2.0.2"
+
+is-data-view@^1.0.1, is-data-view@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.2.tgz#bae0a41b9688986c2188dda6657e56b8f9e63b8e"
+ integrity sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==
+ dependencies:
+ call-bound "^1.0.2"
+ get-intrinsic "^1.2.6"
+ is-typed-array "^1.1.13"
+
+is-date-object@^1.0.5, is-date-object@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.1.0.tgz#ad85541996fc7aa8b2729701d27b7319f95d82f7"
+ integrity sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==
+ dependencies:
+ call-bound "^1.0.2"
+ has-tostringtag "^1.0.2"
+
+is-docker@^2.0.0, is-docker@^2.1.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa"
+ integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==
+
+is-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+ integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+
+is-finalizationregistry@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz#eefdcdc6c94ddd0674d9c85887bf93f944a97c90"
+ integrity sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==
+ dependencies:
+ call-bound "^1.0.3"
+
+is-fullwidth-code-point@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+ integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
+is-generator-fn@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118"
+ integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==
+
+is-generator-function@^1.0.10:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72"
+ integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==
+ dependencies:
+ has-tostringtag "^1.0.0"
+
+is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
+ integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
+ dependencies:
+ is-extglob "^2.1.1"
+
+is-map@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e"
+ integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==
+
+is-module@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591"
+ integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==
+
+is-negative-zero@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747"
+ integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==
+
+is-number-object@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.1.1.tgz#144b21e95a1bc148205dcc2814a9134ec41b2541"
+ integrity sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==
+ dependencies:
+ call-bound "^1.0.3"
+ has-tostringtag "^1.0.2"
+
+is-number@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+ integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
+is-obj@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
+ integrity sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==
+
+is-path-inside@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
+ integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
+
+is-plain-obj@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7"
+ integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==
+
+is-potential-custom-element-name@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5"
+ integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==
+
+is-regex@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22"
+ integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==
+ dependencies:
+ call-bound "^1.0.2"
+ gopd "^1.2.0"
+ has-tostringtag "^1.0.2"
+ hasown "^2.0.2"
+
+is-regexp@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069"
+ integrity sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==
+
+is-root@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-root/-/is-root-2.1.0.tgz#809e18129cf1129644302a4f8544035d51984a9c"
+ integrity sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==
+
+is-set@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d"
+ integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==
+
+is-shared-array-buffer@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz#9b67844bd9b7f246ba0708c3a93e34269c774f6f"
+ integrity sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==
+ dependencies:
+ call-bound "^1.0.3"
+
+is-stream@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
+ integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
+
+is-string@^1.0.7, is-string@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.1.1.tgz#92ea3f3d5c5b6e039ca8677e5ac8d07ea773cbb9"
+ integrity sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==
+ dependencies:
+ call-bound "^1.0.3"
+ has-tostringtag "^1.0.2"
+
+is-symbol@^1.0.4, is-symbol@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.1.1.tgz#f47761279f532e2b05a7024a7506dbbedacd0634"
+ integrity sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==
+ dependencies:
+ call-bound "^1.0.2"
+ has-symbols "^1.1.0"
+ safe-regex-test "^1.1.0"
+
+is-typed-array@^1.1.13, is-typed-array@^1.1.14:
+ version "1.1.15"
+ resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b"
+ integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==
+ dependencies:
+ which-typed-array "^1.1.16"
+
+is-typedarray@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+ integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==
+
+is-weakmap@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd"
+ integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==
+
+is-weakref@^1.0.2, is-weakref@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.1.0.tgz#47e3472ae95a63fa9cf25660bcf0c181c39770ef"
+ integrity sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q==
+ dependencies:
+ call-bound "^1.0.2"
+
+is-weakset@^2.0.3:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.4.tgz#c9f5deb0bc1906c6d6f1027f284ddf459249daca"
+ integrity sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==
+ dependencies:
+ call-bound "^1.0.3"
+ get-intrinsic "^1.2.6"
+
+is-wsl@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
+ integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==
+ dependencies:
+ is-docker "^2.0.0"
+
+isarray@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723"
+ integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==
+
+isarray@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+ integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==
+
+isexe@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+ integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
+
+istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756"
+ integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==
+
+istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d"
+ integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==
+ dependencies:
+ "@babel/core" "^7.12.3"
+ "@babel/parser" "^7.14.7"
+ "@istanbuljs/schema" "^0.1.2"
+ istanbul-lib-coverage "^3.2.0"
+ semver "^6.3.0"
+
+istanbul-lib-report@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d"
+ integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==
+ dependencies:
+ istanbul-lib-coverage "^3.0.0"
+ make-dir "^4.0.0"
+ supports-color "^7.1.0"
+
+istanbul-lib-source-maps@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551"
+ integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==
+ dependencies:
+ debug "^4.1.1"
+ istanbul-lib-coverage "^3.0.0"
+ source-map "^0.6.1"
+
+istanbul-reports@^3.1.3:
+ version "3.1.7"
+ resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b"
+ integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==
+ dependencies:
+ html-escaper "^2.0.0"
+ istanbul-lib-report "^3.0.0"
+
+iterator.prototype@^1.1.3:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.4.tgz#4ae6cf98b97fdc717b7e159d79dc25f8fc9482f1"
+ integrity sha512-x4WH0BWmrMmg4oHHl+duwubhrvczGlyuGAZu3nvrf0UXOfPu8IhZObFEr7DE/iv01YgVZrsOiRcqw2srkKEDIA==
+ dependencies:
+ define-data-property "^1.1.4"
+ es-object-atoms "^1.0.0"
+ get-intrinsic "^1.2.6"
+ has-symbols "^1.1.0"
+ reflect.getprototypeof "^1.0.8"
+ set-function-name "^2.0.2"
+
+jackspeak@^3.1.2:
+ version "3.4.3"
+ resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a"
+ integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==
+ dependencies:
+ "@isaacs/cliui" "^8.0.2"
+ optionalDependencies:
+ "@pkgjs/parseargs" "^0.11.0"
+
+jake@^10.8.5:
+ version "10.9.2"
+ resolved "https://registry.yarnpkg.com/jake/-/jake-10.9.2.tgz#6ae487e6a69afec3a5e167628996b59f35ae2b7f"
+ integrity sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==
+ dependencies:
+ async "^3.2.3"
+ chalk "^4.0.2"
+ filelist "^1.0.4"
+ minimatch "^3.1.2"
+
+jest-changed-files@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.5.1.tgz#a348aed00ec9bf671cc58a66fcbe7c3dfd6a68f5"
+ integrity sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==
+ dependencies:
+ "@jest/types" "^27.5.1"
+ execa "^5.0.0"
+ throat "^6.0.1"
+
+jest-circus@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.5.1.tgz#37a5a4459b7bf4406e53d637b49d22c65d125ecc"
+ integrity sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==
+ dependencies:
+ "@jest/environment" "^27.5.1"
+ "@jest/test-result" "^27.5.1"
+ "@jest/types" "^27.5.1"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ co "^4.6.0"
+ dedent "^0.7.0"
+ expect "^27.5.1"
+ is-generator-fn "^2.0.0"
+ jest-each "^27.5.1"
+ jest-matcher-utils "^27.5.1"
+ jest-message-util "^27.5.1"
+ jest-runtime "^27.5.1"
+ jest-snapshot "^27.5.1"
+ jest-util "^27.5.1"
+ pretty-format "^27.5.1"
+ slash "^3.0.0"
+ stack-utils "^2.0.3"
+ throat "^6.0.1"
+
+jest-cli@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.5.1.tgz#278794a6e6458ea8029547e6c6cbf673bd30b145"
+ integrity sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==
+ dependencies:
+ "@jest/core" "^27.5.1"
+ "@jest/test-result" "^27.5.1"
+ "@jest/types" "^27.5.1"
+ chalk "^4.0.0"
+ exit "^0.1.2"
+ graceful-fs "^4.2.9"
+ import-local "^3.0.2"
+ jest-config "^27.5.1"
+ jest-util "^27.5.1"
+ jest-validate "^27.5.1"
+ prompts "^2.0.1"
+ yargs "^16.2.0"
+
+jest-config@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.5.1.tgz#5c387de33dca3f99ad6357ddeccd91bf3a0e4a41"
+ integrity sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==
+ dependencies:
+ "@babel/core" "^7.8.0"
+ "@jest/test-sequencer" "^27.5.1"
+ "@jest/types" "^27.5.1"
+ babel-jest "^27.5.1"
+ chalk "^4.0.0"
+ ci-info "^3.2.0"
+ deepmerge "^4.2.2"
+ glob "^7.1.1"
+ graceful-fs "^4.2.9"
+ jest-circus "^27.5.1"
+ jest-environment-jsdom "^27.5.1"
+ jest-environment-node "^27.5.1"
+ jest-get-type "^27.5.1"
+ jest-jasmine2 "^27.5.1"
+ jest-regex-util "^27.5.1"
+ jest-resolve "^27.5.1"
+ jest-runner "^27.5.1"
+ jest-util "^27.5.1"
+ jest-validate "^27.5.1"
+ micromatch "^4.0.4"
+ parse-json "^5.2.0"
+ pretty-format "^27.5.1"
+ slash "^3.0.0"
+ strip-json-comments "^3.1.1"
+
+jest-diff@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def"
+ integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==
+ dependencies:
+ chalk "^4.0.0"
+ diff-sequences "^27.5.1"
+ jest-get-type "^27.5.1"
+ pretty-format "^27.5.1"
+
+jest-diff@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a"
+ integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==
+ dependencies:
+ chalk "^4.0.0"
+ diff-sequences "^29.6.3"
+ jest-get-type "^29.6.3"
+ pretty-format "^29.7.0"
+
+jest-docblock@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0"
+ integrity sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==
+ dependencies:
+ detect-newline "^3.0.0"
+
+jest-each@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.5.1.tgz#5bc87016f45ed9507fed6e4702a5b468a5b2c44e"
+ integrity sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==
+ dependencies:
+ "@jest/types" "^27.5.1"
+ chalk "^4.0.0"
+ jest-get-type "^27.5.1"
+ jest-util "^27.5.1"
+ pretty-format "^27.5.1"
+
+jest-environment-jsdom@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz#ea9ccd1fc610209655a77898f86b2b559516a546"
+ integrity sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==
+ dependencies:
+ "@jest/environment" "^27.5.1"
+ "@jest/fake-timers" "^27.5.1"
+ "@jest/types" "^27.5.1"
+ "@types/node" "*"
+ jest-mock "^27.5.1"
+ jest-util "^27.5.1"
+ jsdom "^16.6.0"
+
+jest-environment-node@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.5.1.tgz#dedc2cfe52fab6b8f5714b4808aefa85357a365e"
+ integrity sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==
+ dependencies:
+ "@jest/environment" "^27.5.1"
+ "@jest/fake-timers" "^27.5.1"
+ "@jest/types" "^27.5.1"
+ "@types/node" "*"
+ jest-mock "^27.5.1"
+ jest-util "^27.5.1"
+
+jest-get-type@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1"
+ integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==
+
+jest-get-type@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1"
+ integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==
+
+jest-haste-map@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f"
+ integrity sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==
+ dependencies:
+ "@jest/types" "^27.5.1"
+ "@types/graceful-fs" "^4.1.2"
+ "@types/node" "*"
+ anymatch "^3.0.3"
+ fb-watchman "^2.0.0"
+ graceful-fs "^4.2.9"
+ jest-regex-util "^27.5.1"
+ jest-serializer "^27.5.1"
+ jest-util "^27.5.1"
+ jest-worker "^27.5.1"
+ micromatch "^4.0.4"
+ walker "^1.0.7"
+ optionalDependencies:
+ fsevents "^2.3.2"
+
+jest-jasmine2@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz#a037b0034ef49a9f3d71c4375a796f3b230d1ac4"
+ integrity sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==
+ dependencies:
+ "@jest/environment" "^27.5.1"
+ "@jest/source-map" "^27.5.1"
+ "@jest/test-result" "^27.5.1"
+ "@jest/types" "^27.5.1"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ co "^4.6.0"
+ expect "^27.5.1"
+ is-generator-fn "^2.0.0"
+ jest-each "^27.5.1"
+ jest-matcher-utils "^27.5.1"
+ jest-message-util "^27.5.1"
+ jest-runtime "^27.5.1"
+ jest-snapshot "^27.5.1"
+ jest-util "^27.5.1"
+ pretty-format "^27.5.1"
+ throat "^6.0.1"
+
+jest-leak-detector@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz#6ec9d54c3579dd6e3e66d70e3498adf80fde3fb8"
+ integrity sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==
+ dependencies:
+ jest-get-type "^27.5.1"
+ pretty-format "^27.5.1"
+
+jest-matcher-utils@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab"
+ integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==
+ dependencies:
+ chalk "^4.0.0"
+ jest-diff "^27.5.1"
+ jest-get-type "^27.5.1"
+ pretty-format "^27.5.1"
+
+jest-matcher-utils@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12"
+ integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==
+ dependencies:
+ chalk "^4.0.0"
+ jest-diff "^29.7.0"
+ jest-get-type "^29.6.3"
+ pretty-format "^29.7.0"
+
+jest-message-util@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf"
+ integrity sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==
+ dependencies:
+ "@babel/code-frame" "^7.12.13"
+ "@jest/types" "^27.5.1"
+ "@types/stack-utils" "^2.0.0"
+ chalk "^4.0.0"
+ graceful-fs "^4.2.9"
+ micromatch "^4.0.4"
+ pretty-format "^27.5.1"
+ slash "^3.0.0"
+ stack-utils "^2.0.3"
+
+jest-message-util@^28.1.3:
+ version "28.1.3"
+ resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-28.1.3.tgz#232def7f2e333f1eecc90649b5b94b0055e7c43d"
+ integrity sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==
+ dependencies:
+ "@babel/code-frame" "^7.12.13"
+ "@jest/types" "^28.1.3"
+ "@types/stack-utils" "^2.0.0"
+ chalk "^4.0.0"
+ graceful-fs "^4.2.9"
+ micromatch "^4.0.4"
+ pretty-format "^28.1.3"
+ slash "^3.0.0"
+ stack-utils "^2.0.3"
+
+jest-message-util@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3"
+ integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==
+ dependencies:
+ "@babel/code-frame" "^7.12.13"
+ "@jest/types" "^29.6.3"
+ "@types/stack-utils" "^2.0.0"
+ chalk "^4.0.0"
+ graceful-fs "^4.2.9"
+ micromatch "^4.0.4"
+ pretty-format "^29.7.0"
+ slash "^3.0.0"
+ stack-utils "^2.0.3"
+
+jest-mock@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6"
+ integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==
+ dependencies:
+ "@jest/types" "^27.5.1"
+ "@types/node" "*"
+
+jest-pnp-resolver@^1.2.2:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e"
+ integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==
+
+jest-regex-util@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95"
+ integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==
+
+jest-regex-util@^28.0.0:
+ version "28.0.2"
+ resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-28.0.2.tgz#afdc377a3b25fb6e80825adcf76c854e5bf47ead"
+ integrity sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==
+
+jest-resolve-dependencies@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz#d811ecc8305e731cc86dd79741ee98fed06f1da8"
+ integrity sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==
+ dependencies:
+ "@jest/types" "^27.5.1"
+ jest-regex-util "^27.5.1"
+ jest-snapshot "^27.5.1"
+
+jest-resolve@^27.4.2, jest-resolve@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.5.1.tgz#a2f1c5a0796ec18fe9eb1536ac3814c23617b384"
+ integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==
+ dependencies:
+ "@jest/types" "^27.5.1"
+ chalk "^4.0.0"
+ graceful-fs "^4.2.9"
+ jest-haste-map "^27.5.1"
+ jest-pnp-resolver "^1.2.2"
+ jest-util "^27.5.1"
+ jest-validate "^27.5.1"
+ resolve "^1.20.0"
+ resolve.exports "^1.1.0"
+ slash "^3.0.0"
+
+jest-runner@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.5.1.tgz#071b27c1fa30d90540805c5645a0ec167c7b62e5"
+ integrity sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==
+ dependencies:
+ "@jest/console" "^27.5.1"
+ "@jest/environment" "^27.5.1"
+ "@jest/test-result" "^27.5.1"
+ "@jest/transform" "^27.5.1"
+ "@jest/types" "^27.5.1"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ emittery "^0.8.1"
+ graceful-fs "^4.2.9"
+ jest-docblock "^27.5.1"
+ jest-environment-jsdom "^27.5.1"
+ jest-environment-node "^27.5.1"
+ jest-haste-map "^27.5.1"
+ jest-leak-detector "^27.5.1"
+ jest-message-util "^27.5.1"
+ jest-resolve "^27.5.1"
+ jest-runtime "^27.5.1"
+ jest-util "^27.5.1"
+ jest-worker "^27.5.1"
+ source-map-support "^0.5.6"
+ throat "^6.0.1"
+
+jest-runtime@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.5.1.tgz#4896003d7a334f7e8e4a53ba93fb9bcd3db0a1af"
+ integrity sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==
+ dependencies:
+ "@jest/environment" "^27.5.1"
+ "@jest/fake-timers" "^27.5.1"
+ "@jest/globals" "^27.5.1"
+ "@jest/source-map" "^27.5.1"
+ "@jest/test-result" "^27.5.1"
+ "@jest/transform" "^27.5.1"
+ "@jest/types" "^27.5.1"
+ chalk "^4.0.0"
+ cjs-module-lexer "^1.0.0"
+ collect-v8-coverage "^1.0.0"
+ execa "^5.0.0"
+ glob "^7.1.3"
+ graceful-fs "^4.2.9"
+ jest-haste-map "^27.5.1"
+ jest-message-util "^27.5.1"
+ jest-mock "^27.5.1"
+ jest-regex-util "^27.5.1"
+ jest-resolve "^27.5.1"
+ jest-snapshot "^27.5.1"
+ jest-util "^27.5.1"
+ slash "^3.0.0"
+ strip-bom "^4.0.0"
+
+jest-serializer@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64"
+ integrity sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==
+ dependencies:
+ "@types/node" "*"
+ graceful-fs "^4.2.9"
+
+jest-snapshot@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.5.1.tgz#b668d50d23d38054a51b42c4039cab59ae6eb6a1"
+ integrity sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==
+ dependencies:
+ "@babel/core" "^7.7.2"
+ "@babel/generator" "^7.7.2"
+ "@babel/plugin-syntax-typescript" "^7.7.2"
+ "@babel/traverse" "^7.7.2"
+ "@babel/types" "^7.0.0"
+ "@jest/transform" "^27.5.1"
+ "@jest/types" "^27.5.1"
+ "@types/babel__traverse" "^7.0.4"
+ "@types/prettier" "^2.1.5"
+ babel-preset-current-node-syntax "^1.0.0"
+ chalk "^4.0.0"
+ expect "^27.5.1"
+ graceful-fs "^4.2.9"
+ jest-diff "^27.5.1"
+ jest-get-type "^27.5.1"
+ jest-haste-map "^27.5.1"
+ jest-matcher-utils "^27.5.1"
+ jest-message-util "^27.5.1"
+ jest-util "^27.5.1"
+ natural-compare "^1.4.0"
+ pretty-format "^27.5.1"
+ semver "^7.3.2"
+
+jest-util@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9"
+ integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==
+ dependencies:
+ "@jest/types" "^27.5.1"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ ci-info "^3.2.0"
+ graceful-fs "^4.2.9"
+ picomatch "^2.2.3"
+
+jest-util@^28.1.3:
+ version "28.1.3"
+ resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-28.1.3.tgz#f4f932aa0074f0679943220ff9cbba7e497028b0"
+ integrity sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==
+ dependencies:
+ "@jest/types" "^28.1.3"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ ci-info "^3.2.0"
+ graceful-fs "^4.2.9"
+ picomatch "^2.2.3"
+
+jest-util@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc"
+ integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==
+ dependencies:
+ "@jest/types" "^29.6.3"
+ "@types/node" "*"
+ chalk "^4.0.0"
+ ci-info "^3.2.0"
+ graceful-fs "^4.2.9"
+ picomatch "^2.2.3"
+
+jest-validate@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.5.1.tgz#9197d54dc0bdb52260b8db40b46ae668e04df067"
+ integrity sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==
+ dependencies:
+ "@jest/types" "^27.5.1"
+ camelcase "^6.2.0"
+ chalk "^4.0.0"
+ jest-get-type "^27.5.1"
+ leven "^3.1.0"
+ pretty-format "^27.5.1"
+
+jest-watch-typeahead@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/jest-watch-typeahead/-/jest-watch-typeahead-1.1.0.tgz#b4a6826dfb9c9420da2f7bc900de59dad11266a9"
+ integrity sha512-Va5nLSJTN7YFtC2jd+7wsoe1pNe5K4ShLux/E5iHEwlB9AxaxmggY7to9KUqKojhaJw3aXqt5WAb4jGPOolpEw==
+ dependencies:
+ ansi-escapes "^4.3.1"
+ chalk "^4.0.0"
+ jest-regex-util "^28.0.0"
+ jest-watcher "^28.0.0"
+ slash "^4.0.0"
+ string-length "^5.0.1"
+ strip-ansi "^7.0.1"
+
+jest-watcher@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.5.1.tgz#71bd85fb9bde3a2c2ec4dc353437971c43c642a2"
+ integrity sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==
+ dependencies:
+ "@jest/test-result" "^27.5.1"
+ "@jest/types" "^27.5.1"
+ "@types/node" "*"
+ ansi-escapes "^4.2.1"
+ chalk "^4.0.0"
+ jest-util "^27.5.1"
+ string-length "^4.0.1"
+
+jest-watcher@^28.0.0:
+ version "28.1.3"
+ resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-28.1.3.tgz#c6023a59ba2255e3b4c57179fc94164b3e73abd4"
+ integrity sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==
+ dependencies:
+ "@jest/test-result" "^28.1.3"
+ "@jest/types" "^28.1.3"
+ "@types/node" "*"
+ ansi-escapes "^4.2.1"
+ chalk "^4.0.0"
+ emittery "^0.10.2"
+ jest-util "^28.1.3"
+ string-length "^4.0.1"
+
+jest-worker@^26.2.1:
+ version "26.6.2"
+ resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed"
+ integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==
+ dependencies:
+ "@types/node" "*"
+ merge-stream "^2.0.0"
+ supports-color "^7.0.0"
+
+jest-worker@^27.0.2, jest-worker@^27.4.5, jest-worker@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0"
+ integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==
+ dependencies:
+ "@types/node" "*"
+ merge-stream "^2.0.0"
+ supports-color "^8.0.0"
+
+jest-worker@^28.0.2:
+ version "28.1.3"
+ resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-28.1.3.tgz#7e3c4ce3fa23d1bb6accb169e7f396f98ed4bb98"
+ integrity sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==
+ dependencies:
+ "@types/node" "*"
+ merge-stream "^2.0.0"
+ supports-color "^8.0.0"
+
+jest@^27.4.3:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest/-/jest-27.5.1.tgz#dadf33ba70a779be7a6fc33015843b51494f63fc"
+ integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==
+ dependencies:
+ "@jest/core" "^27.5.1"
+ import-local "^3.0.2"
+ jest-cli "^27.5.1"
+
+jiti@^1.21.6:
+ version "1.21.7"
+ resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.7.tgz#9dd81043424a3d28458b193d965f0d18a2300ba9"
+ integrity sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==
+
+"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+ integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+js-yaml@^3.13.1:
+ version "3.14.1"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537"
+ integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==
+ dependencies:
+ argparse "^1.0.7"
+ esprima "^4.0.0"
+
+js-yaml@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
+ integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
+ dependencies:
+ argparse "^2.0.1"
+
+jsdom@^16.6.0:
+ version "16.7.0"
+ resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710"
+ integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==
+ dependencies:
+ abab "^2.0.5"
+ acorn "^8.2.4"
+ acorn-globals "^6.0.0"
+ cssom "^0.4.4"
+ cssstyle "^2.3.0"
+ data-urls "^2.0.0"
+ decimal.js "^10.2.1"
+ domexception "^2.0.1"
+ escodegen "^2.0.0"
+ form-data "^3.0.0"
+ html-encoding-sniffer "^2.0.1"
+ http-proxy-agent "^4.0.1"
+ https-proxy-agent "^5.0.0"
+ is-potential-custom-element-name "^1.0.1"
+ nwsapi "^2.2.0"
+ parse5 "6.0.1"
+ saxes "^5.0.1"
+ symbol-tree "^3.2.4"
+ tough-cookie "^4.0.0"
+ w3c-hr-time "^1.0.2"
+ w3c-xmlserializer "^2.0.0"
+ webidl-conversions "^6.1.0"
+ whatwg-encoding "^1.0.5"
+ whatwg-mimetype "^2.3.0"
+ whatwg-url "^8.5.0"
+ ws "^7.4.6"
+ xml-name-validator "^3.0.0"
+
+jsesc@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d"
+ integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==
+
+jsesc@~3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e"
+ integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==
+
+json-buffer@3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
+ integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
+
+json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
+ integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
+
+json-schema-traverse@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+ integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+json-schema-traverse@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
+ integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
+
+json-schema@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5"
+ integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==
+
+json-stable-stringify-without-jsonify@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
+ integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
+
+json5@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593"
+ integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==
+ dependencies:
+ minimist "^1.2.0"
+
+json5@^2.1.2, json5@^2.2.0, json5@^2.2.3:
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
+ integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
+
+jsonfile@^6.0.1:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
+ integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
+ dependencies:
+ universalify "^2.0.0"
+ optionalDependencies:
+ graceful-fs "^4.1.6"
+
+jsonpath@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/jsonpath/-/jsonpath-1.1.1.tgz#0ca1ed8fb65bb3309248cc9d5466d12d5b0b9901"
+ integrity sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==
+ dependencies:
+ esprima "1.2.2"
+ static-eval "2.0.2"
+ underscore "1.12.1"
+
+jsonpointer@^5.0.0:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-5.0.1.tgz#2110e0af0900fd37467b5907ecd13a7884a1b559"
+ integrity sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==
+
+"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.5:
+ version "3.3.5"
+ resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a"
+ integrity sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==
+ dependencies:
+ array-includes "^3.1.6"
+ array.prototype.flat "^1.3.1"
+ object.assign "^4.1.4"
+ object.values "^1.1.6"
+
+keyv@^4.5.3, keyv@^4.5.4:
+ version "4.5.4"
+ resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
+ integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
+ dependencies:
+ json-buffer "3.0.1"
+
+kind-of@^6.0.2:
+ version "6.0.3"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
+ integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
+
+kleur@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
+ integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
+
+klona@^2.0.4, klona@^2.0.5:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/klona/-/klona-2.0.6.tgz#85bffbf819c03b2f53270412420a4555ef882e22"
+ integrity sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==
+
+language-subtag-registry@^0.3.20:
+ version "0.3.23"
+ resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz#23529e04d9e3b74679d70142df3fd2eb6ec572e7"
+ integrity sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==
+
+language-tags@^1.0.9:
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.9.tgz#1ffdcd0ec0fafb4b1be7f8b11f306ad0f9c08777"
+ integrity sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==
+ dependencies:
+ language-subtag-registry "^0.3.20"
+
+launch-editor@^2.6.0:
+ version "2.9.1"
+ resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.9.1.tgz#253f173bd441e342d4344b4dae58291abb425047"
+ integrity sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==
+ dependencies:
+ picocolors "^1.0.0"
+ shell-quote "^1.8.1"
+
+leven@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
+ integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==
+
+levn@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
+ integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==
+ dependencies:
+ prelude-ls "^1.2.1"
+ type-check "~0.4.0"
+
+levn@~0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+ integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==
+ dependencies:
+ prelude-ls "~1.1.2"
+ type-check "~0.3.2"
+
+lilconfig@^2.0.3:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52"
+ integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==
+
+lilconfig@^3.0.0, lilconfig@^3.1.3:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-3.1.3.tgz#a1bcfd6257f9585bf5ae14ceeebb7b559025e4c4"
+ integrity sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==
+
+lines-and-columns@^1.1.6:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
+ integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
+
+loader-runner@^4.2.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1"
+ integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==
+
+loader-utils@^2.0.0, loader-utils@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c"
+ integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==
+ dependencies:
+ big.js "^5.2.2"
+ emojis-list "^3.0.0"
+ json5 "^2.1.2"
+
+loader-utils@^3.2.0:
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-3.3.1.tgz#735b9a19fd63648ca7adbd31c2327dfe281304e5"
+ integrity sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==
+
+locate-path@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
+ integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
+ dependencies:
+ p-locate "^3.0.0"
+ path-exists "^3.0.0"
+
+locate-path@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
+ integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
+ dependencies:
+ p-locate "^4.1.0"
+
+locate-path@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
+ integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
+ dependencies:
+ p-locate "^5.0.0"
+
+lodash.debounce@^4.0.8:
+ version "4.0.8"
+ resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
+ integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==
+
+lodash.memoize@^4.1.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
+ integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==
+
+lodash.merge@^4.6.2:
+ version "4.6.2"
+ resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
+ integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
+
+lodash.sortby@^4.7.0:
+ version "4.7.0"
+ resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
+ integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==
+
+lodash.uniq@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
+ integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==
+
+lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0:
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+ integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+
+loose-envify@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+ integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
+ dependencies:
+ js-tokens "^3.0.0 || ^4.0.0"
+
+lower-case@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28"
+ integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==
+ dependencies:
+ tslib "^2.0.3"
+
+lru-cache@^10.2.0:
+ version "10.4.3"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119"
+ integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==
+
+lru-cache@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
+ integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
+ dependencies:
+ yallist "^3.0.2"
+
+lucide-react@^0.468.0:
+ version "0.468.0"
+ resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.468.0.tgz#830c1bfd905575ddd23b832baa420c87db166910"
+ integrity sha512-6koYRhnM2N0GGZIdXzSeiNwguv1gt/FAjZOiPl76roBi3xKEXa4WmfpxgQwTTL4KipXjefrnf3oV4IsYhi4JFA==
+
+lz-string@^1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941"
+ integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==
+
+magic-string@^0.25.0, magic-string@^0.25.7:
+ version "0.25.9"
+ resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c"
+ integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==
+ dependencies:
+ sourcemap-codec "^1.4.8"
+
+make-dir@^3.0.2, make-dir@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
+ integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
+ dependencies:
+ semver "^6.0.0"
+
+make-dir@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e"
+ integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==
+ dependencies:
+ semver "^7.5.3"
+
+makeerror@1.0.12:
+ version "1.0.12"
+ resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a"
+ integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==
+ dependencies:
+ tmpl "1.0.5"
+
+math-intrinsics@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.0.0.tgz#4e04bf87c85aa51e90d078dac2252b4eb5260817"
+ integrity sha512-4MqMiKP90ybymYvsut0CH2g4XWbfLtmlCkXmtmdcDCxNB+mQcu1w/1+L/VD7vi/PSv7X2JYV7SCcR+jiPXnQtA==
+
+mdn-data@2.0.14:
+ version "2.0.14"
+ resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
+ integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==
+
+mdn-data@2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.4.tgz#699b3c38ac6f1d728091a64650b65d388502fd5b"
+ integrity sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==
+
+media-typer@0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
+ integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
+
+memfs@^3.1.2, memfs@^3.4.3:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.6.0.tgz#d7a2110f86f79dd950a8b6df6d57bc984aa185f6"
+ integrity sha512-EGowvkkgbMcIChjMTMkESFDbZeSh8xZ7kNSF0hAiAN4Jh6jgHCRS0Ga/+C8y6Au+oqpezRHCfPsmJ2+DwAgiwQ==
+ dependencies:
+ fs-monkey "^1.0.4"
+
+merge-descriptors@1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5"
+ integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==
+
+merge-stream@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
+ integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
+
+merge2@^1.3.0, merge2@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
+ integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+
+methods@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
+ integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
+
+micromatch@^4.0.2, micromatch@^4.0.4, micromatch@^4.0.5, micromatch@^4.0.8:
+ version "4.0.8"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
+ integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
+ dependencies:
+ braces "^3.0.3"
+ picomatch "^2.3.1"
+
+mime-db@1.52.0:
+ version "1.52.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+ integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+
+"mime-db@>= 1.43.0 < 2":
+ version "1.53.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.53.0.tgz#3cb63cd820fc29896d9d4e8c32ab4fcd74ccb447"
+ integrity sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg==
+
+mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34:
+ version "2.1.35"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+ integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
+ dependencies:
+ mime-db "1.52.0"
+
+mime@1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
+ integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
+
+mimic-fn@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
+ integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
+
+min-indent@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
+ integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
+
+mini-css-extract-plugin@^2.4.5:
+ version "2.9.2"
+ resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.9.2.tgz#966031b468917a5446f4c24a80854b2947503c5b"
+ integrity sha512-GJuACcS//jtq4kCtd5ii/M0SZf7OZRH+BxdqXZHaJfb8TJiVl+NgQRPwiYt2EuqeSkNydn/7vP+bcE27C5mb9w==
+ dependencies:
+ schema-utils "^4.0.0"
+ tapable "^2.2.1"
+
+minimalistic-assert@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
+ integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
+
+minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+ integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+ dependencies:
+ brace-expansion "^1.1.7"
+
+minimatch@^5.0.1:
+ version "5.1.6"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96"
+ integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==
+ dependencies:
+ brace-expansion "^2.0.1"
+
+minimatch@^9.0.4:
+ version "9.0.5"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5"
+ integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==
+ dependencies:
+ brace-expansion "^2.0.1"
+
+minimist@^1.2.0, minimist@^1.2.6:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
+ integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
+
+"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2:
+ version "7.1.2"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707"
+ integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==
+
+mkdirp@~0.5.1:
+ version "0.5.6"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
+ integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
+ dependencies:
+ minimist "^1.2.6"
+
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
+
+ms@2.1.3, ms@^2.1.1, ms@^2.1.3:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
+multicast-dns@^7.2.5:
+ version "7.2.5"
+ resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced"
+ integrity sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==
+ dependencies:
+ dns-packet "^5.2.2"
+ thunky "^1.0.2"
+
+mz@^2.7.0:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
+ integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==
+ dependencies:
+ any-promise "^1.0.0"
+ object-assign "^4.0.1"
+ thenify-all "^1.0.0"
+
+nanoid@^3.3.7:
+ version "3.3.8"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf"
+ integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==
+
+natural-compare-lite@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4"
+ integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==
+
+natural-compare@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+ integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
+
+negotiator@0.6.3:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
+ integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
+
+negotiator@~0.6.4:
+ version "0.6.4"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.4.tgz#777948e2452651c570b712dd01c23e262713fff7"
+ integrity sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==
+
+neo-async@^2.6.2:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
+ integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
+
+no-case@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d"
+ integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==
+ dependencies:
+ lower-case "^2.0.2"
+ tslib "^2.0.3"
+
+node-addon-api@^7.0.0:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558"
+ integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==
+
+node-forge@^1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3"
+ integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==
+
+node-int64@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
+ integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==
+
+node-releases@^2.0.19:
+ version "2.0.19"
+ resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314"
+ integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==
+
+normalize-path@^3.0.0, normalize-path@~3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+ integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
+normalize-range@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942"
+ integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==
+
+normalize-url@^6.0.1:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
+ integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
+
+npm-run-path@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
+ integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
+ dependencies:
+ path-key "^3.0.0"
+
+nth-check@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c"
+ integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==
+ dependencies:
+ boolbase "~1.0.0"
+
+nth-check@^2.0.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
+ integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==
+ dependencies:
+ boolbase "^1.0.0"
+
+nwsapi@^2.2.0:
+ version "2.2.16"
+ resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.16.tgz#177760bba02c351df1d2644e220c31dfec8cdb43"
+ integrity sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==
+
+object-assign@^4.0.1, object-assign@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+ integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
+
+object-hash@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9"
+ integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==
+
+object-inspect@^1.13.3:
+ version "1.13.3"
+ resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.3.tgz#f14c183de51130243d6d18ae149375ff50ea488a"
+ integrity sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==
+
+object-keys@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
+ integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
+
+object.assign@^4.1.2, object.assign@^4.1.4, object.assign@^4.1.5:
+ version "4.1.7"
+ resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.7.tgz#8c14ca1a424c6a561b0bb2a22f66f5049a945d3d"
+ integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==
+ dependencies:
+ call-bind "^1.0.8"
+ call-bound "^1.0.3"
+ define-properties "^1.2.1"
+ es-object-atoms "^1.0.0"
+ has-symbols "^1.1.0"
+ object-keys "^1.1.1"
+
+object.entries@^1.1.5, object.entries@^1.1.8:
+ version "1.1.8"
+ resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.8.tgz#bffe6f282e01f4d17807204a24f8edd823599c41"
+ integrity sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==
+ dependencies:
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-object-atoms "^1.0.0"
+
+object.fromentries@^2.0.8:
+ version "2.0.8"
+ resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65"
+ integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==
+ dependencies:
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.2"
+ es-object-atoms "^1.0.0"
+
+object.getownpropertydescriptors@^2.1.0:
+ version "2.1.8"
+ resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.8.tgz#2f1fe0606ec1a7658154ccd4f728504f69667923"
+ integrity sha512-qkHIGe4q0lSYMv0XI4SsBTJz3WaURhLvd0lKSgtVuOsJ2krg4SgMw3PIRQFMp07yi++UR3se2mkcLqsBNpBb/A==
+ dependencies:
+ array.prototype.reduce "^1.0.6"
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.2"
+ es-object-atoms "^1.0.0"
+ gopd "^1.0.1"
+ safe-array-concat "^1.1.2"
+
+object.groupby@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e"
+ integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==
+ dependencies:
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.2"
+
+object.values@^1.1.0, object.values@^1.1.6, object.values@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b"
+ integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==
+ dependencies:
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-object-atoms "^1.0.0"
+
+obuf@^1.0.0, obuf@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
+ integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==
+
+on-finished@2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
+ integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
+ dependencies:
+ ee-first "1.1.1"
+
+on-headers@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
+ integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
+
+once@^1.3.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
+ dependencies:
+ wrappy "1"
+
+onetime@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
+ integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
+ dependencies:
+ mimic-fn "^2.1.0"
+
+open@^8.0.9, open@^8.4.0:
+ version "8.4.2"
+ resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9"
+ integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==
+ dependencies:
+ define-lazy-prop "^2.0.0"
+ is-docker "^2.1.1"
+ is-wsl "^2.2.0"
+
+optionator@^0.8.1:
+ version "0.8.3"
+ resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
+ integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==
+ dependencies:
+ deep-is "~0.1.3"
+ fast-levenshtein "~2.0.6"
+ levn "~0.3.0"
+ prelude-ls "~1.1.2"
+ type-check "~0.3.2"
+ word-wrap "~1.2.3"
+
+optionator@^0.9.3:
+ version "0.9.4"
+ resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734"
+ integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==
+ dependencies:
+ deep-is "^0.1.3"
+ fast-levenshtein "^2.0.6"
+ levn "^0.4.1"
+ prelude-ls "^1.2.1"
+ type-check "^0.4.0"
+ word-wrap "^1.2.5"
+
+p-limit@^2.0.0, p-limit@^2.2.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
+ integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
+ dependencies:
+ p-try "^2.0.0"
+
+p-limit@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
+ integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
+ dependencies:
+ yocto-queue "^0.1.0"
+
+p-locate@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
+ integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
+ dependencies:
+ p-limit "^2.0.0"
+
+p-locate@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
+ integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
+ dependencies:
+ p-limit "^2.2.0"
+
+p-locate@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
+ integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
+ dependencies:
+ p-limit "^3.0.2"
+
+p-retry@^4.5.0:
+ version "4.6.2"
+ resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16"
+ integrity sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==
+ dependencies:
+ "@types/retry" "0.12.0"
+ retry "^0.13.1"
+
+p-try@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
+ integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+
+package-json-from-dist@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505"
+ integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==
+
+param-case@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5"
+ integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==
+ dependencies:
+ dot-case "^3.0.4"
+ tslib "^2.0.3"
+
+parent-module@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+ integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
+ dependencies:
+ callsites "^3.0.0"
+
+parse-json@^5.0.0, parse-json@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
+ integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ error-ex "^1.3.1"
+ json-parse-even-better-errors "^2.3.0"
+ lines-and-columns "^1.1.6"
+
+parse5@6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
+ integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
+
+parseurl@~1.3.2, parseurl@~1.3.3:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
+ integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
+
+pascal-case@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb"
+ integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==
+ dependencies:
+ no-case "^3.0.4"
+ tslib "^2.0.3"
+
+path-exists@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+ integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==
+
+path-exists@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
+ integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
+
+path-is-absolute@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+ integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
+
+path-key@^3.0.0, path-key@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
+ integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
+
+path-parse@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+
+path-scurry@^1.11.1:
+ version "1.11.1"
+ resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2"
+ integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==
+ dependencies:
+ lru-cache "^10.2.0"
+ minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
+
+path-to-regexp@0.1.12:
+ version "0.1.12"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.12.tgz#d5e1a12e478a976d432ef3c58d534b9923164bb7"
+ integrity sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==
+
+path-type@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
+ integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
+
+performance-now@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
+ integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==
+
+picocolors@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f"
+ integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==
+
+picocolors@^1.0.0, picocolors@^1.0.1, picocolors@^1.1.0, picocolors@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b"
+ integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==
+
+picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3, picomatch@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+ integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+pify@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+ integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==
+
+pirates@^4.0.1, pirates@^4.0.4:
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9"
+ integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==
+
+pkg-dir@^4.1.0, pkg-dir@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
+ integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
+ dependencies:
+ find-up "^4.0.0"
+
+pkg-up@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5"
+ integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==
+ dependencies:
+ find-up "^3.0.0"
+
+possible-typed-array-names@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f"
+ integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==
+
+postcss-attribute-case-insensitive@^5.0.2:
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz#03d761b24afc04c09e757e92ff53716ae8ea2741"
+ integrity sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==
+ dependencies:
+ postcss-selector-parser "^6.0.10"
+
+postcss-browser-comments@^4:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-browser-comments/-/postcss-browser-comments-4.0.0.tgz#bcfc86134df5807f5d3c0eefa191d42136b5e72a"
+ integrity sha512-X9X9/WN3KIvY9+hNERUqX9gncsgBA25XaeR+jshHz2j8+sYyHktHw1JdKuMjeLpGktXidqDhA7b/qm1mrBDmgg==
+
+postcss-calc@^8.2.3:
+ version "8.2.4"
+ resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.2.4.tgz#77b9c29bfcbe8a07ff6693dc87050828889739a5"
+ integrity sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==
+ dependencies:
+ postcss-selector-parser "^6.0.9"
+ postcss-value-parser "^4.2.0"
+
+postcss-clamp@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-clamp/-/postcss-clamp-4.1.0.tgz#7263e95abadd8c2ba1bd911b0b5a5c9c93e02363"
+ integrity sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+postcss-color-functional-notation@^4.2.4:
+ version "4.2.4"
+ resolved "https://registry.yarnpkg.com/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz#21a909e8d7454d3612d1659e471ce4696f28caec"
+ integrity sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+postcss-color-hex-alpha@^8.0.4:
+ version "8.0.4"
+ resolved "https://registry.yarnpkg.com/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz#c66e2980f2fbc1a63f5b079663340ce8b55f25a5"
+ integrity sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+postcss-color-rebeccapurple@^7.1.1:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz#63fdab91d878ebc4dd4b7c02619a0c3d6a56ced0"
+ integrity sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+postcss-colormin@^5.3.1:
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.3.1.tgz#86c27c26ed6ba00d96c79e08f3ffb418d1d1988f"
+ integrity sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==
+ dependencies:
+ browserslist "^4.21.4"
+ caniuse-api "^3.0.0"
+ colord "^2.9.1"
+ postcss-value-parser "^4.2.0"
+
+postcss-convert-values@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.1.3.tgz#04998bb9ba6b65aa31035d669a6af342c5f9d393"
+ integrity sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==
+ dependencies:
+ browserslist "^4.21.4"
+ postcss-value-parser "^4.2.0"
+
+postcss-custom-media@^8.0.2:
+ version "8.0.2"
+ resolved "https://registry.yarnpkg.com/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz#c8f9637edf45fef761b014c024cee013f80529ea"
+ integrity sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+postcss-custom-properties@^12.1.10:
+ version "12.1.11"
+ resolved "https://registry.yarnpkg.com/postcss-custom-properties/-/postcss-custom-properties-12.1.11.tgz#d14bb9b3989ac4d40aaa0e110b43be67ac7845cf"
+ integrity sha512-0IDJYhgU8xDv1KY6+VgUwuQkVtmYzRwu+dMjnmdMafXYv86SWqfxkc7qdDvWS38vsjaEtv8e0vGOUQrAiMBLpQ==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+postcss-custom-selectors@^6.0.3:
+ version "6.0.3"
+ resolved "https://registry.yarnpkg.com/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz#1ab4684d65f30fed175520f82d223db0337239d9"
+ integrity sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==
+ dependencies:
+ postcss-selector-parser "^6.0.4"
+
+postcss-dir-pseudo-class@^6.0.5:
+ version "6.0.5"
+ resolved "https://registry.yarnpkg.com/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz#2bf31de5de76added44e0a25ecf60ae9f7c7c26c"
+ integrity sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==
+ dependencies:
+ postcss-selector-parser "^6.0.10"
+
+postcss-discard-comments@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz#8df5e81d2925af2780075840c1526f0660e53696"
+ integrity sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==
+
+postcss-discard-duplicates@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz#9eb4fe8456706a4eebd6d3b7b777d07bad03e848"
+ integrity sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==
+
+postcss-discard-empty@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz#e57762343ff7f503fe53fca553d18d7f0c369c6c"
+ integrity sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==
+
+postcss-discard-overridden@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz#7e8c5b53325747e9d90131bb88635282fb4a276e"
+ integrity sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==
+
+postcss-double-position-gradients@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz#b96318fdb477be95997e86edd29c6e3557a49b91"
+ integrity sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==
+ dependencies:
+ "@csstools/postcss-progressive-custom-properties" "^1.1.0"
+ postcss-value-parser "^4.2.0"
+
+postcss-env-function@^4.0.6:
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/postcss-env-function/-/postcss-env-function-4.0.6.tgz#7b2d24c812f540ed6eda4c81f6090416722a8e7a"
+ integrity sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+postcss-flexbugs-fixes@^5.0.2:
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/postcss-flexbugs-fixes/-/postcss-flexbugs-fixes-5.0.2.tgz#2028e145313074fc9abe276cb7ca14e5401eb49d"
+ integrity sha512-18f9voByak7bTktR2QgDveglpn9DTbBWPUzSOe9g0N4WR/2eSt6Vrcbf0hmspvMI6YWGywz6B9f7jzpFNJJgnQ==
+
+postcss-focus-visible@^6.0.4:
+ version "6.0.4"
+ resolved "https://registry.yarnpkg.com/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz#50c9ea9afa0ee657fb75635fabad25e18d76bf9e"
+ integrity sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==
+ dependencies:
+ postcss-selector-parser "^6.0.9"
+
+postcss-focus-within@^5.0.4:
+ version "5.0.4"
+ resolved "https://registry.yarnpkg.com/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz#5b1d2ec603195f3344b716c0b75f61e44e8d2e20"
+ integrity sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==
+ dependencies:
+ postcss-selector-parser "^6.0.9"
+
+postcss-font-variant@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz#efd59b4b7ea8bb06127f2d031bfbb7f24d32fa66"
+ integrity sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==
+
+postcss-gap-properties@^3.0.5:
+ version "3.0.5"
+ resolved "https://registry.yarnpkg.com/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz#f7e3cddcf73ee19e94ccf7cb77773f9560aa2fff"
+ integrity sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==
+
+postcss-image-set-function@^4.0.7:
+ version "4.0.7"
+ resolved "https://registry.yarnpkg.com/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz#08353bd756f1cbfb3b6e93182c7829879114481f"
+ integrity sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+postcss-import@^15.1.0:
+ version "15.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-15.1.0.tgz#41c64ed8cc0e23735a9698b3249ffdbf704adc70"
+ integrity sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==
+ dependencies:
+ postcss-value-parser "^4.0.0"
+ read-cache "^1.0.0"
+ resolve "^1.1.7"
+
+postcss-initial@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/postcss-initial/-/postcss-initial-4.0.1.tgz#529f735f72c5724a0fb30527df6fb7ac54d7de42"
+ integrity sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==
+
+postcss-js@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2"
+ integrity sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==
+ dependencies:
+ camelcase-css "^2.0.1"
+
+postcss-lab-function@^4.2.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz#6fe4c015102ff7cd27d1bd5385582f67ebdbdc98"
+ integrity sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==
+ dependencies:
+ "@csstools/postcss-progressive-custom-properties" "^1.1.0"
+ postcss-value-parser "^4.2.0"
+
+postcss-load-config@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-4.0.2.tgz#7159dcf626118d33e299f485d6afe4aff7c4a3e3"
+ integrity sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==
+ dependencies:
+ lilconfig "^3.0.0"
+ yaml "^2.3.4"
+
+postcss-loader@^6.2.1:
+ version "6.2.1"
+ resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-6.2.1.tgz#0895f7346b1702103d30fdc66e4d494a93c008ef"
+ integrity sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==
+ dependencies:
+ cosmiconfig "^7.0.0"
+ klona "^2.0.5"
+ semver "^7.3.5"
+
+postcss-logical@^5.0.4:
+ version "5.0.4"
+ resolved "https://registry.yarnpkg.com/postcss-logical/-/postcss-logical-5.0.4.tgz#ec75b1ee54421acc04d5921576b7d8db6b0e6f73"
+ integrity sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==
+
+postcss-media-minmax@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz#7140bddec173e2d6d657edbd8554a55794e2a5b5"
+ integrity sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==
+
+postcss-merge-longhand@^5.1.7:
+ version "5.1.7"
+ resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.7.tgz#24a1bdf402d9ef0e70f568f39bdc0344d568fb16"
+ integrity sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+ stylehacks "^5.1.1"
+
+postcss-merge-rules@^5.1.4:
+ version "5.1.4"
+ resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.4.tgz#2f26fa5cacb75b1402e213789f6766ae5e40313c"
+ integrity sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==
+ dependencies:
+ browserslist "^4.21.4"
+ caniuse-api "^3.0.0"
+ cssnano-utils "^3.1.0"
+ postcss-selector-parser "^6.0.5"
+
+postcss-minify-font-values@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz#f1df0014a726083d260d3bd85d7385fb89d1f01b"
+ integrity sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+postcss-minify-gradients@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz#f1fe1b4f498134a5068240c2f25d46fcd236ba2c"
+ integrity sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==
+ dependencies:
+ colord "^2.9.1"
+ cssnano-utils "^3.1.0"
+ postcss-value-parser "^4.2.0"
+
+postcss-minify-params@^5.1.4:
+ version "5.1.4"
+ resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.4.tgz#c06a6c787128b3208b38c9364cfc40c8aa5d7352"
+ integrity sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==
+ dependencies:
+ browserslist "^4.21.4"
+ cssnano-utils "^3.1.0"
+ postcss-value-parser "^4.2.0"
+
+postcss-minify-selectors@^5.2.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz#d4e7e6b46147b8117ea9325a915a801d5fe656c6"
+ integrity sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==
+ dependencies:
+ postcss-selector-parser "^6.0.5"
+
+postcss-modules-extract-imports@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz#b4497cb85a9c0c4b5aabeb759bb25e8d89f15002"
+ integrity sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==
+
+postcss-modules-local-by-default@^4.0.5:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz#d150f43837831dae25e4085596e84f6f5d6ec368"
+ integrity sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==
+ dependencies:
+ icss-utils "^5.0.0"
+ postcss-selector-parser "^7.0.0"
+ postcss-value-parser "^4.1.0"
+
+postcss-modules-scope@^3.2.0:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz#1bbccddcb398f1d7a511e0a2d1d047718af4078c"
+ integrity sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==
+ dependencies:
+ postcss-selector-parser "^7.0.0"
+
+postcss-modules-values@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c"
+ integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==
+ dependencies:
+ icss-utils "^5.0.0"
+
+postcss-nested@^6.2.0:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.2.0.tgz#4c2d22ab5f20b9cb61e2c5c5915950784d068131"
+ integrity sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==
+ dependencies:
+ postcss-selector-parser "^6.1.1"
+
+postcss-nesting@^10.2.0:
+ version "10.2.0"
+ resolved "https://registry.yarnpkg.com/postcss-nesting/-/postcss-nesting-10.2.0.tgz#0b12ce0db8edfd2d8ae0aaf86427370b898890be"
+ integrity sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==
+ dependencies:
+ "@csstools/selector-specificity" "^2.0.0"
+ postcss-selector-parser "^6.0.10"
+
+postcss-normalize-charset@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz#9302de0b29094b52c259e9b2cf8dc0879879f0ed"
+ integrity sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==
+
+postcss-normalize-display-values@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz#72abbae58081960e9edd7200fcf21ab8325c3da8"
+ integrity sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+postcss-normalize-positions@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz#ef97279d894087b59325b45c47f1e863daefbb92"
+ integrity sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+postcss-normalize-repeat-style@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz#e9eb96805204f4766df66fd09ed2e13545420fb2"
+ integrity sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+postcss-normalize-string@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz#411961169e07308c82c1f8c55f3e8a337757e228"
+ integrity sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+postcss-normalize-timing-functions@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz#d5614410f8f0b2388e9f240aa6011ba6f52dafbb"
+ integrity sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+postcss-normalize-unicode@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.1.tgz#f67297fca3fea7f17e0d2caa40769afc487aa030"
+ integrity sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==
+ dependencies:
+ browserslist "^4.21.4"
+ postcss-value-parser "^4.2.0"
+
+postcss-normalize-url@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz#ed9d88ca82e21abef99f743457d3729a042adcdc"
+ integrity sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==
+ dependencies:
+ normalize-url "^6.0.1"
+ postcss-value-parser "^4.2.0"
+
+postcss-normalize-whitespace@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz#08a1a0d1ffa17a7cc6efe1e6c9da969cc4493cfa"
+ integrity sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+postcss-normalize@^10.0.1:
+ version "10.0.1"
+ resolved "https://registry.yarnpkg.com/postcss-normalize/-/postcss-normalize-10.0.1.tgz#464692676b52792a06b06880a176279216540dd7"
+ integrity sha512-+5w18/rDev5mqERcG3W5GZNMJa1eoYYNGo8gB7tEwaos0ajk3ZXAI4mHGcNT47NE+ZnZD1pEpUOFLvltIwmeJA==
+ dependencies:
+ "@csstools/normalize.css" "*"
+ postcss-browser-comments "^4"
+ sanitize.css "*"
+
+postcss-opacity-percentage@^1.1.2:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.3.tgz#5b89b35551a556e20c5d23eb5260fbfcf5245da6"
+ integrity sha512-An6Ba4pHBiDtyVpSLymUUERMo2cU7s+Obz6BTrS+gxkbnSBNKSuD0AVUc+CpBMrpVPKKfoVz0WQCX+Tnst0i4A==
+
+postcss-ordered-values@^5.1.3:
+ version "5.1.3"
+ resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz#b6fd2bd10f937b23d86bc829c69e7732ce76ea38"
+ integrity sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==
+ dependencies:
+ cssnano-utils "^3.1.0"
+ postcss-value-parser "^4.2.0"
+
+postcss-overflow-shorthand@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz#7ed6486fec44b76f0eab15aa4866cda5d55d893e"
+ integrity sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+postcss-page-break@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/postcss-page-break/-/postcss-page-break-3.0.4.tgz#7fbf741c233621622b68d435babfb70dd8c1ee5f"
+ integrity sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==
+
+postcss-place@^7.0.5:
+ version "7.0.5"
+ resolved "https://registry.yarnpkg.com/postcss-place/-/postcss-place-7.0.5.tgz#95dbf85fd9656a3a6e60e832b5809914236986c4"
+ integrity sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+postcss-preset-env@^7.0.1:
+ version "7.8.3"
+ resolved "https://registry.yarnpkg.com/postcss-preset-env/-/postcss-preset-env-7.8.3.tgz#2a50f5e612c3149cc7af75634e202a5b2ad4f1e2"
+ integrity sha512-T1LgRm5uEVFSEF83vHZJV2z19lHg4yJuZ6gXZZkqVsqv63nlr6zabMH3l4Pc01FQCyfWVrh2GaUeCVy9Po+Aag==
+ dependencies:
+ "@csstools/postcss-cascade-layers" "^1.1.1"
+ "@csstools/postcss-color-function" "^1.1.1"
+ "@csstools/postcss-font-format-keywords" "^1.0.1"
+ "@csstools/postcss-hwb-function" "^1.0.2"
+ "@csstools/postcss-ic-unit" "^1.0.1"
+ "@csstools/postcss-is-pseudo-class" "^2.0.7"
+ "@csstools/postcss-nested-calc" "^1.0.0"
+ "@csstools/postcss-normalize-display-values" "^1.0.1"
+ "@csstools/postcss-oklab-function" "^1.1.1"
+ "@csstools/postcss-progressive-custom-properties" "^1.3.0"
+ "@csstools/postcss-stepped-value-functions" "^1.0.1"
+ "@csstools/postcss-text-decoration-shorthand" "^1.0.0"
+ "@csstools/postcss-trigonometric-functions" "^1.0.2"
+ "@csstools/postcss-unset-value" "^1.0.2"
+ autoprefixer "^10.4.13"
+ browserslist "^4.21.4"
+ css-blank-pseudo "^3.0.3"
+ css-has-pseudo "^3.0.4"
+ css-prefers-color-scheme "^6.0.3"
+ cssdb "^7.1.0"
+ postcss-attribute-case-insensitive "^5.0.2"
+ postcss-clamp "^4.1.0"
+ postcss-color-functional-notation "^4.2.4"
+ postcss-color-hex-alpha "^8.0.4"
+ postcss-color-rebeccapurple "^7.1.1"
+ postcss-custom-media "^8.0.2"
+ postcss-custom-properties "^12.1.10"
+ postcss-custom-selectors "^6.0.3"
+ postcss-dir-pseudo-class "^6.0.5"
+ postcss-double-position-gradients "^3.1.2"
+ postcss-env-function "^4.0.6"
+ postcss-focus-visible "^6.0.4"
+ postcss-focus-within "^5.0.4"
+ postcss-font-variant "^5.0.0"
+ postcss-gap-properties "^3.0.5"
+ postcss-image-set-function "^4.0.7"
+ postcss-initial "^4.0.1"
+ postcss-lab-function "^4.2.1"
+ postcss-logical "^5.0.4"
+ postcss-media-minmax "^5.0.0"
+ postcss-nesting "^10.2.0"
+ postcss-opacity-percentage "^1.1.2"
+ postcss-overflow-shorthand "^3.0.4"
+ postcss-page-break "^3.0.4"
+ postcss-place "^7.0.5"
+ postcss-pseudo-class-any-link "^7.1.6"
+ postcss-replace-overflow-wrap "^4.0.0"
+ postcss-selector-not "^6.0.1"
+ postcss-value-parser "^4.2.0"
+
+postcss-pseudo-class-any-link@^7.1.6:
+ version "7.1.6"
+ resolved "https://registry.yarnpkg.com/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz#2693b221902da772c278def85a4d9a64b6e617ab"
+ integrity sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==
+ dependencies:
+ postcss-selector-parser "^6.0.10"
+
+postcss-reduce-initial@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.1.2.tgz#798cd77b3e033eae7105c18c9d371d989e1382d6"
+ integrity sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==
+ dependencies:
+ browserslist "^4.21.4"
+ caniuse-api "^3.0.0"
+
+postcss-reduce-transforms@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz#333b70e7758b802f3dd0ddfe98bb1ccfef96b6e9"
+ integrity sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+
+postcss-replace-overflow-wrap@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz#d2df6bed10b477bf9c52fab28c568b4b29ca4319"
+ integrity sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==
+
+postcss-selector-not@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz#8f0a709bf7d4b45222793fc34409be407537556d"
+ integrity sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==
+ dependencies:
+ postcss-selector-parser "^6.0.10"
+
+postcss-selector-parser@^6.0.10, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9, postcss-selector-parser@^6.1.1, postcss-selector-parser@^6.1.2:
+ version "6.1.2"
+ resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de"
+ integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==
+ dependencies:
+ cssesc "^3.0.0"
+ util-deprecate "^1.0.2"
+
+postcss-selector-parser@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz#41bd8b56f177c093ca49435f65731befe25d6b9c"
+ integrity sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==
+ dependencies:
+ cssesc "^3.0.0"
+ util-deprecate "^1.0.2"
+
+postcss-svgo@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.1.0.tgz#0a317400ced789f233a28826e77523f15857d80d"
+ integrity sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==
+ dependencies:
+ postcss-value-parser "^4.2.0"
+ svgo "^2.7.0"
+
+postcss-unique-selectors@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz#a9f273d1eacd09e9aa6088f4b0507b18b1b541b6"
+ integrity sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==
+ dependencies:
+ postcss-selector-parser "^6.0.5"
+
+postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
+ integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
+
+postcss@^7.0.35:
+ version "7.0.39"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309"
+ integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==
+ dependencies:
+ picocolors "^0.2.1"
+ source-map "^0.6.1"
+
+postcss@^8.3.5, postcss@^8.4.33, postcss@^8.4.4, postcss@^8.4.47:
+ version "8.4.49"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.49.tgz#4ea479048ab059ab3ae61d082190fabfd994fe19"
+ integrity sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==
+ dependencies:
+ nanoid "^3.3.7"
+ picocolors "^1.1.1"
+ source-map-js "^1.2.1"
+
+prelude-ls@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
+ integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
+
+prelude-ls@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+ integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==
+
+prettier-linter-helpers@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b"
+ integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==
+ dependencies:
+ fast-diff "^1.1.2"
+
+prettier@^3.4.2:
+ version "3.4.2"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.4.2.tgz#a5ce1fb522a588bf2b78ca44c6e6fe5aa5a2b13f"
+ integrity sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==
+
+pretty-bytes@^5.3.0, pretty-bytes@^5.4.1:
+ version "5.6.0"
+ resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb"
+ integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==
+
+pretty-error@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-4.0.0.tgz#90a703f46dd7234adb46d0f84823e9d1cb8f10d6"
+ integrity sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==
+ dependencies:
+ lodash "^4.17.20"
+ renderkid "^3.0.0"
+
+pretty-format@^27.0.2, pretty-format@^27.5.1:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e"
+ integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==
+ dependencies:
+ ansi-regex "^5.0.1"
+ ansi-styles "^5.0.0"
+ react-is "^17.0.1"
+
+pretty-format@^28.1.3:
+ version "28.1.3"
+ resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-28.1.3.tgz#c9fba8cedf99ce50963a11b27d982a9ae90970d5"
+ integrity sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==
+ dependencies:
+ "@jest/schemas" "^28.1.3"
+ ansi-regex "^5.0.1"
+ ansi-styles "^5.0.0"
+ react-is "^18.0.0"
+
+pretty-format@^29.0.0, pretty-format@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812"
+ integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==
+ dependencies:
+ "@jest/schemas" "^29.6.3"
+ ansi-styles "^5.0.0"
+ react-is "^18.0.0"
+
+process-nextick-args@~2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
+ integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
+
+promise@^8.1.0:
+ version "8.3.0"
+ resolved "https://registry.yarnpkg.com/promise/-/promise-8.3.0.tgz#8cb333d1edeb61ef23869fbb8a4ea0279ab60e0a"
+ integrity sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==
+ dependencies:
+ asap "~2.0.6"
+
+prompts@^2.0.1, prompts@^2.4.2:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"
+ integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==
+ dependencies:
+ kleur "^3.0.3"
+ sisteransi "^1.0.5"
+
+prop-types@^15.8.1:
+ version "15.8.1"
+ resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
+ integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
+ dependencies:
+ loose-envify "^1.4.0"
+ object-assign "^4.1.1"
+ react-is "^16.13.1"
+
+proxy-addr@~2.0.7:
+ version "2.0.7"
+ resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025"
+ integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
+ dependencies:
+ forwarded "0.2.0"
+ ipaddr.js "1.9.1"
+
+psl@^1.1.33:
+ version "1.15.0"
+ resolved "https://registry.yarnpkg.com/psl/-/psl-1.15.0.tgz#bdace31896f1d97cec6a79e8224898ce93d974c6"
+ integrity sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==
+ dependencies:
+ punycode "^2.3.1"
+
+punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
+ integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
+
+q@^1.1.2:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
+ integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==
+
+qs@6.13.0:
+ version "6.13.0"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906"
+ integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==
+ dependencies:
+ side-channel "^1.0.6"
+
+querystringify@^2.1.1:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6"
+ integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==
+
+queue-microtask@^1.2.2:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
+ integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+
+raf@^3.4.1:
+ version "3.4.1"
+ resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39"
+ integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==
+ dependencies:
+ performance-now "^2.1.0"
+
+randombytes@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
+ integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
+ dependencies:
+ safe-buffer "^5.1.0"
+
+range-parser@^1.2.1, range-parser@~1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
+ integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
+
+raw-body@2.5.2:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
+ integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
+ dependencies:
+ bytes "3.1.2"
+ http-errors "2.0.0"
+ iconv-lite "0.4.24"
+ unpipe "1.0.0"
+
+react-app-polyfill@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/react-app-polyfill/-/react-app-polyfill-3.0.0.tgz#95221e0a9bd259e5ca6b177c7bb1cb6768f68fd7"
+ integrity sha512-sZ41cxiU5llIB003yxxQBYrARBqe0repqPTTYBTmMqTz9szeBbE37BehCE891NZsmdZqqP+xWKdT3eo3vOzN8w==
+ dependencies:
+ core-js "^3.19.2"
+ object-assign "^4.1.1"
+ promise "^8.1.0"
+ raf "^3.4.1"
+ regenerator-runtime "^0.13.9"
+ whatwg-fetch "^3.6.2"
+
+react-dev-utils@^12.0.1:
+ version "12.0.1"
+ resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-12.0.1.tgz#ba92edb4a1f379bd46ccd6bcd4e7bc398df33e73"
+ integrity sha512-84Ivxmr17KjUupyqzFode6xKhjwuEJDROWKJy/BthkL7Wn6NJ8h4WE6k/exAv6ImS+0oZLRRW5j/aINMHyeGeQ==
+ dependencies:
+ "@babel/code-frame" "^7.16.0"
+ address "^1.1.2"
+ browserslist "^4.18.1"
+ chalk "^4.1.2"
+ cross-spawn "^7.0.3"
+ detect-port-alt "^1.1.6"
+ escape-string-regexp "^4.0.0"
+ filesize "^8.0.6"
+ find-up "^5.0.0"
+ fork-ts-checker-webpack-plugin "^6.5.0"
+ global-modules "^2.0.0"
+ globby "^11.0.4"
+ gzip-size "^6.0.0"
+ immer "^9.0.7"
+ is-root "^2.1.0"
+ loader-utils "^3.2.0"
+ open "^8.4.0"
+ pkg-up "^3.1.0"
+ prompts "^2.4.2"
+ react-error-overlay "^6.0.11"
+ recursive-readdir "^2.2.2"
+ shell-quote "^1.7.3"
+ strip-ansi "^6.0.1"
+ text-table "^0.2.0"
+
+react-dom@^19.0.0:
+ version "19.0.0"
+ resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0.tgz#43446f1f01c65a4cd7f7588083e686a6726cfb57"
+ integrity sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==
+ dependencies:
+ scheduler "^0.25.0"
+
+react-error-overlay@^6.0.11:
+ version "6.0.11"
+ resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.11.tgz#92835de5841c5cf08ba00ddd2d677b6d17ff9adb"
+ integrity sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==
+
+react-is@^16.13.1:
+ version "16.13.1"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
+ integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
+
+react-is@^17.0.1:
+ version "17.0.2"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
+ integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
+
+react-is@^18.0.0:
+ version "18.3.1"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
+ integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
+
+react-redux@^9.2.0:
+ version "9.2.0"
+ resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-9.2.0.tgz#96c3ab23fb9a3af2cb4654be4b51c989e32366f5"
+ integrity sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==
+ dependencies:
+ "@types/use-sync-external-store" "^0.0.6"
+ use-sync-external-store "^1.4.0"
+
+react-refresh@^0.11.0:
+ version "0.11.0"
+ resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046"
+ integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==
+
+react-scripts@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-5.0.1.tgz#6285dbd65a8ba6e49ca8d651ce30645a6d980003"
+ integrity sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==
+ dependencies:
+ "@babel/core" "^7.16.0"
+ "@pmmmwh/react-refresh-webpack-plugin" "^0.5.3"
+ "@svgr/webpack" "^5.5.0"
+ babel-jest "^27.4.2"
+ babel-loader "^8.2.3"
+ babel-plugin-named-asset-import "^0.3.8"
+ babel-preset-react-app "^10.0.1"
+ bfj "^7.0.2"
+ browserslist "^4.18.1"
+ camelcase "^6.2.1"
+ case-sensitive-paths-webpack-plugin "^2.4.0"
+ css-loader "^6.5.1"
+ css-minimizer-webpack-plugin "^3.2.0"
+ dotenv "^10.0.0"
+ dotenv-expand "^5.1.0"
+ eslint "^8.3.0"
+ eslint-config-react-app "^7.0.1"
+ eslint-webpack-plugin "^3.1.1"
+ file-loader "^6.2.0"
+ fs-extra "^10.0.0"
+ html-webpack-plugin "^5.5.0"
+ identity-obj-proxy "^3.0.0"
+ jest "^27.4.3"
+ jest-resolve "^27.4.2"
+ jest-watch-typeahead "^1.0.0"
+ mini-css-extract-plugin "^2.4.5"
+ postcss "^8.4.4"
+ postcss-flexbugs-fixes "^5.0.2"
+ postcss-loader "^6.2.1"
+ postcss-normalize "^10.0.1"
+ postcss-preset-env "^7.0.1"
+ prompts "^2.4.2"
+ react-app-polyfill "^3.0.0"
+ react-dev-utils "^12.0.1"
+ react-refresh "^0.11.0"
+ resolve "^1.20.0"
+ resolve-url-loader "^4.0.0"
+ sass-loader "^12.3.0"
+ semver "^7.3.5"
+ source-map-loader "^3.0.0"
+ style-loader "^3.3.1"
+ tailwindcss "^3.0.2"
+ terser-webpack-plugin "^5.2.5"
+ webpack "^5.64.4"
+ webpack-dev-server "^4.6.0"
+ webpack-manifest-plugin "^4.0.2"
+ workbox-webpack-plugin "^6.4.1"
+ optionalDependencies:
+ fsevents "^2.3.2"
+
+react-spinners@^0.15.0:
+ version "0.15.0"
+ resolved "https://registry.yarnpkg.com/react-spinners/-/react-spinners-0.15.0.tgz#bb9536a3839ab4e1513bb98847d79cc1fc930b93"
+ integrity sha512-ZO3/fNB9Qc+kgpG3SfdlMnvTX6LtLmTnOogb3W6sXIaU/kZ1ydEViPfZ06kSOaEsor58C/tzXw2wROGQu3X2pA==
+
+react@^19.0.0:
+ version "19.0.0"
+ resolved "https://registry.yarnpkg.com/react/-/react-19.0.0.tgz#6e1969251b9f108870aa4bff37a0ce9ddfaaabdd"
+ integrity sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==
+
+read-cache@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
+ integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==
+ dependencies:
+ pify "^2.3.0"
+
+readable-stream@^2.0.1:
+ version "2.3.8"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b"
+ integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.3"
+ isarray "~1.0.0"
+ process-nextick-args "~2.0.0"
+ safe-buffer "~5.1.1"
+ string_decoder "~1.1.1"
+ util-deprecate "~1.0.1"
+
+readable-stream@^3.0.6:
+ version "3.6.2"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
+ integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
+ dependencies:
+ inherits "^2.0.3"
+ string_decoder "^1.1.1"
+ util-deprecate "^1.0.1"
+
+readdirp@^4.0.1:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.0.2.tgz#388fccb8b75665da3abffe2d8f8ed59fe74c230a"
+ integrity sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==
+
+readdirp@~3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
+ integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
+ dependencies:
+ picomatch "^2.2.1"
+
+recursive-readdir@^2.2.2:
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.3.tgz#e726f328c0d69153bcabd5c322d3195252379372"
+ integrity sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==
+ dependencies:
+ minimatch "^3.0.5"
+
+redent@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
+ integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==
+ dependencies:
+ indent-string "^4.0.0"
+ strip-indent "^3.0.0"
+
+redux-thunk@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-3.1.0.tgz#94aa6e04977c30e14e892eae84978c1af6058ff3"
+ integrity sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==
+
+redux@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/redux/-/redux-5.0.1.tgz#97fa26881ce5746500125585d5642c77b6e9447b"
+ integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==
+
+reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.8:
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.9.tgz#c905f3386008de95a62315f3ea8630404be19e2f"
+ integrity sha512-r0Ay04Snci87djAsI4U+WNRcSw5S4pOH7qFjd/veA5gC7TbqESR3tcj28ia95L/fYUDw11JKP7uqUKUAfVvV5Q==
+ dependencies:
+ call-bind "^1.0.8"
+ define-properties "^1.2.1"
+ dunder-proto "^1.0.1"
+ es-abstract "^1.23.6"
+ es-errors "^1.3.0"
+ get-intrinsic "^1.2.6"
+ gopd "^1.2.0"
+ which-builtin-type "^1.2.1"
+
+regenerate-unicode-properties@^10.2.0:
+ version "10.2.0"
+ resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz#626e39df8c372338ea9b8028d1f99dc3fd9c3db0"
+ integrity sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==
+ dependencies:
+ regenerate "^1.4.2"
+
+regenerate@^1.4.2:
+ version "1.4.2"
+ resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a"
+ integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==
+
+regenerator-runtime@^0.13.9:
+ version "0.13.11"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9"
+ integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==
+
+regenerator-runtime@^0.14.0:
+ version "0.14.1"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
+ integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
+
+regenerator-transform@^0.15.2:
+ version "0.15.2"
+ resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4"
+ integrity sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==
+ dependencies:
+ "@babel/runtime" "^7.8.4"
+
+regex-parser@^2.2.11:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.3.0.tgz#4bb61461b1a19b8b913f3960364bb57887f920ee"
+ integrity sha512-TVILVSz2jY5D47F4mA4MppkBrafEaiUWJO/TcZHEIuI13AqoZMkK1WMA4Om1YkYbTx+9Ki1/tSUXbceyr9saRg==
+
+regexp.prototype.flags@^1.5.2, regexp.prototype.flags@^1.5.3:
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz#b3ae40b1d2499b8350ab2c3fe6ef3845d3a96f42"
+ integrity sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==
+ dependencies:
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-errors "^1.3.0"
+ set-function-name "^2.0.2"
+
+regexpu-core@^6.2.0:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-6.2.0.tgz#0e5190d79e542bf294955dccabae04d3c7d53826"
+ integrity sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==
+ dependencies:
+ regenerate "^1.4.2"
+ regenerate-unicode-properties "^10.2.0"
+ regjsgen "^0.8.0"
+ regjsparser "^0.12.0"
+ unicode-match-property-ecmascript "^2.0.0"
+ unicode-match-property-value-ecmascript "^2.1.0"
+
+regjsgen@^0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.8.0.tgz#df23ff26e0c5b300a6470cad160a9d090c3a37ab"
+ integrity sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==
+
+regjsparser@^0.12.0:
+ version "0.12.0"
+ resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.12.0.tgz#0e846df6c6530586429377de56e0475583b088dc"
+ integrity sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==
+ dependencies:
+ jsesc "~3.0.2"
+
+relateurl@^0.2.7:
+ version "0.2.7"
+ resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
+ integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==
+
+renderkid@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a"
+ integrity sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==
+ dependencies:
+ css-select "^4.1.3"
+ dom-converter "^0.2.0"
+ htmlparser2 "^6.1.0"
+ lodash "^4.17.21"
+ strip-ansi "^6.0.1"
+
+require-directory@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+ integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
+
+require-from-string@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
+ integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
+
+requires-port@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
+ integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==
+
+reselect@^5.1.0:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/reselect/-/reselect-5.1.1.tgz#c766b1eb5d558291e5e550298adb0becc24bb72e"
+ integrity sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==
+
+resolve-cwd@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
+ integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==
+ dependencies:
+ resolve-from "^5.0.0"
+
+resolve-from@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+ integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+
+resolve-from@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
+ integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
+
+resolve-url-loader@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-url-loader/-/resolve-url-loader-4.0.0.tgz#d50d4ddc746bb10468443167acf800dcd6c3ad57"
+ integrity sha512-05VEMczVREcbtT7Bz+C+96eUO5HDNvdthIiMB34t7FcF8ehcu4wC0sSgPUubs3XW2Q3CNLJk/BJrCU9wVRymiA==
+ dependencies:
+ adjust-sourcemap-loader "^4.0.0"
+ convert-source-map "^1.7.0"
+ loader-utils "^2.0.0"
+ postcss "^7.0.35"
+ source-map "0.6.1"
+
+resolve.exports@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.1.tgz#05cfd5b3edf641571fd46fa608b610dda9ead999"
+ integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==
+
+resolve@^1.1.7, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.4, resolve@^1.22.8:
+ version "1.22.9"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.9.tgz#6da76e4cdc57181fa4471231400e8851d0a924f3"
+ integrity sha512-QxrmX1DzraFIi9PxdG5VkRfRwIgjwyud+z/iBwfRRrVmHc+P9Q7u2lSSpQ6bjr2gy5lrqIiU9vb6iAeGf2400A==
+ dependencies:
+ is-core-module "^2.16.0"
+ path-parse "^1.0.7"
+ supports-preserve-symlinks-flag "^1.0.0"
+
+resolve@^2.0.0-next.5:
+ version "2.0.0-next.5"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c"
+ integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==
+ dependencies:
+ is-core-module "^2.13.0"
+ path-parse "^1.0.7"
+ supports-preserve-symlinks-flag "^1.0.0"
+
+retry@^0.13.1:
+ version "0.13.1"
+ resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658"
+ integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==
+
+reusify@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+ integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
+
+rimraf@^3.0.0, rimraf@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+ integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
+ dependencies:
+ glob "^7.1.3"
+
+rollup-plugin-terser@^7.0.0:
+ version "7.0.2"
+ resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d"
+ integrity sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==
+ dependencies:
+ "@babel/code-frame" "^7.10.4"
+ jest-worker "^26.2.1"
+ serialize-javascript "^4.0.0"
+ terser "^5.0.0"
+
+rollup@^2.43.1:
+ version "2.79.2"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.2.tgz#f150e4a5db4b121a21a747d762f701e5e9f49090"
+ integrity sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==
+ optionalDependencies:
+ fsevents "~2.3.2"
+
+run-parallel@^1.1.9:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
+ integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
+ dependencies:
+ queue-microtask "^1.2.2"
+
+safe-array-concat@^1.1.2, safe-array-concat@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3"
+ integrity sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==
+ dependencies:
+ call-bind "^1.0.8"
+ call-bound "^1.0.2"
+ get-intrinsic "^1.2.6"
+ has-symbols "^1.1.0"
+ isarray "^2.0.5"
+
+safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.1.0, safe-buffer@~5.2.0:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+ integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
+safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+ integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
+
+safe-regex-test@^1.0.3, safe-regex-test@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1"
+ integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==
+ dependencies:
+ call-bound "^1.0.2"
+ es-errors "^1.3.0"
+ is-regex "^1.2.1"
+
+"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0":
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+ integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
+sanitize.css@*:
+ version "13.0.0"
+ resolved "https://registry.yarnpkg.com/sanitize.css/-/sanitize.css-13.0.0.tgz#2675553974b27964c75562ade3bd85d79879f173"
+ integrity sha512-ZRwKbh/eQ6w9vmTjkuG0Ioi3HBwPFce0O+v//ve+aOq1oeCy7jMV2qzzAlpsNuqpqCBjjriM1lbtZbF/Q8jVyA==
+
+sass-loader@^12.3.0:
+ version "12.6.0"
+ resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-12.6.0.tgz#5148362c8e2cdd4b950f3c63ac5d16dbfed37bcb"
+ integrity sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==
+ dependencies:
+ klona "^2.0.4"
+ neo-async "^2.6.2"
+
+sass@^1.83.0:
+ version "1.83.0"
+ resolved "https://registry.yarnpkg.com/sass/-/sass-1.83.0.tgz#e36842c0b88a94ed336fd16249b878a0541d536f"
+ integrity sha512-qsSxlayzoOjdvXMVLkzF84DJFc2HZEL/rFyGIKbbilYtAvlCxyuzUeff9LawTn4btVnLKg75Z8MMr1lxU1lfGw==
+ dependencies:
+ chokidar "^4.0.0"
+ immutable "^5.0.2"
+ source-map-js ">=0.6.2 <2.0.0"
+ optionalDependencies:
+ "@parcel/watcher" "^2.4.1"
+
+sax@~1.2.4:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
+ integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
+
+saxes@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d"
+ integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==
+ dependencies:
+ xmlchars "^2.2.0"
+
+scheduler@^0.25.0:
+ version "0.25.0"
+ resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0.tgz#336cd9768e8cceebf52d3c80e3dcf5de23e7e015"
+ integrity sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==
+
+schema-utils@2.7.0:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.0.tgz#17151f76d8eae67fbbf77960c33c676ad9f4efc7"
+ integrity sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==
+ dependencies:
+ "@types/json-schema" "^7.0.4"
+ ajv "^6.12.2"
+ ajv-keywords "^3.4.1"
+
+schema-utils@^2.6.5:
+ version "2.7.1"
+ resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.7.1.tgz#1ca4f32d1b24c590c203b8e7a50bf0ea4cd394d7"
+ integrity sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==
+ dependencies:
+ "@types/json-schema" "^7.0.5"
+ ajv "^6.12.4"
+ ajv-keywords "^3.5.2"
+
+schema-utils@^3.0.0, schema-utils@^3.2.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe"
+ integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==
+ dependencies:
+ "@types/json-schema" "^7.0.8"
+ ajv "^6.12.5"
+ ajv-keywords "^3.5.2"
+
+schema-utils@^4.0.0, schema-utils@^4.2.0, schema-utils@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.3.0.tgz#3b669f04f71ff2dfb5aba7ce2d5a9d79b35622c0"
+ integrity sha512-Gf9qqc58SpCA/xdziiHz35F4GNIWYWZrEshUc/G/r5BnLph6xpKuLeoJoQuj5WfBIx/eQLf+hmVPYHaxJu7V2g==
+ dependencies:
+ "@types/json-schema" "^7.0.9"
+ ajv "^8.9.0"
+ ajv-formats "^2.1.1"
+ ajv-keywords "^5.1.0"
+
+select-hose@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
+ integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==
+
+selfsigned@^2.1.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.4.1.tgz#560d90565442a3ed35b674034cec4e95dceb4ae0"
+ integrity sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==
+ dependencies:
+ "@types/node-forge" "^1.3.0"
+ node-forge "^1"
+
+semver@^6.0.0, semver@^6.3.0, semver@^6.3.1:
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
+ integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
+
+semver@^7.3.2, semver@^7.3.5, semver@^7.3.7, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0:
+ version "7.6.3"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
+ integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
+
+send@0.19.0:
+ version "0.19.0"
+ resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8"
+ integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==
+ dependencies:
+ debug "2.6.9"
+ depd "2.0.0"
+ destroy "1.2.0"
+ encodeurl "~1.0.2"
+ escape-html "~1.0.3"
+ etag "~1.8.1"
+ fresh "0.5.2"
+ http-errors "2.0.0"
+ mime "1.6.0"
+ ms "2.1.3"
+ on-finished "2.4.1"
+ range-parser "~1.2.1"
+ statuses "2.0.1"
+
+serialize-javascript@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa"
+ integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==
+ dependencies:
+ randombytes "^2.1.0"
+
+serialize-javascript@^6.0.0, serialize-javascript@^6.0.2:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2"
+ integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==
+ dependencies:
+ randombytes "^2.1.0"
+
+serve-index@^1.9.1:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239"
+ integrity sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==
+ dependencies:
+ accepts "~1.3.4"
+ batch "0.6.1"
+ debug "2.6.9"
+ escape-html "~1.0.3"
+ http-errors "~1.6.2"
+ mime-types "~2.1.17"
+ parseurl "~1.3.2"
+
+serve-static@1.16.2:
+ version "1.16.2"
+ resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296"
+ integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==
+ dependencies:
+ encodeurl "~2.0.0"
+ escape-html "~1.0.3"
+ parseurl "~1.3.3"
+ send "0.19.0"
+
+set-function-length@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
+ integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
+ dependencies:
+ define-data-property "^1.1.4"
+ es-errors "^1.3.0"
+ function-bind "^1.1.2"
+ get-intrinsic "^1.2.4"
+ gopd "^1.0.1"
+ has-property-descriptors "^1.0.2"
+
+set-function-name@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985"
+ integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==
+ dependencies:
+ define-data-property "^1.1.4"
+ es-errors "^1.3.0"
+ functions-have-names "^1.2.3"
+ has-property-descriptors "^1.0.2"
+
+setprototypeof@1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
+ integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
+
+setprototypeof@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
+ integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
+
+shebang-command@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+ integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
+ dependencies:
+ shebang-regex "^3.0.0"
+
+shebang-regex@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+ integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
+
+shell-quote@^1.7.3, shell-quote@^1.8.1:
+ version "1.8.2"
+ resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.2.tgz#d2d83e057959d53ec261311e9e9b8f51dcb2934a"
+ integrity sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==
+
+side-channel-list@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad"
+ integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==
+ dependencies:
+ es-errors "^1.3.0"
+ object-inspect "^1.13.3"
+
+side-channel-map@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42"
+ integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==
+ dependencies:
+ call-bound "^1.0.2"
+ es-errors "^1.3.0"
+ get-intrinsic "^1.2.5"
+ object-inspect "^1.13.3"
+
+side-channel-weakmap@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea"
+ integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==
+ dependencies:
+ call-bound "^1.0.2"
+ es-errors "^1.3.0"
+ get-intrinsic "^1.2.5"
+ object-inspect "^1.13.3"
+ side-channel-map "^1.0.1"
+
+side-channel@^1.0.6, side-channel@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9"
+ integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==
+ dependencies:
+ es-errors "^1.3.0"
+ object-inspect "^1.13.3"
+ side-channel-list "^1.0.0"
+ side-channel-map "^1.0.1"
+ side-channel-weakmap "^1.0.2"
+
+signal-exit@^3.0.2, signal-exit@^3.0.3:
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
+ integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
+
+signal-exit@^4.0.1:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
+ integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
+
+sisteransi@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
+ integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==
+
+slash@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
+ integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
+
+slash@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7"
+ integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==
+
+sockjs@^0.3.24:
+ version "0.3.24"
+ resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce"
+ integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==
+ dependencies:
+ faye-websocket "^0.11.3"
+ uuid "^8.3.2"
+ websocket-driver "^0.7.4"
+
+source-list-map@^2.0.0, source-list-map@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
+ integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
+
+"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
+ integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==
+
+source-map-loader@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/source-map-loader/-/source-map-loader-3.0.2.tgz#af23192f9b344daa729f6772933194cc5fa54fee"
+ integrity sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg==
+ dependencies:
+ abab "^2.0.5"
+ iconv-lite "^0.6.3"
+ source-map-js "^1.0.1"
+
+source-map-support@^0.5.6, source-map-support@~0.5.20:
+ version "0.5.21"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
+ integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
+ dependencies:
+ buffer-from "^1.0.0"
+ source-map "^0.6.0"
+
+source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+ integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+source-map@^0.7.3:
+ version "0.7.4"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656"
+ integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==
+
+source-map@^0.8.0-beta.0:
+ version "0.8.0-beta.0"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.8.0-beta.0.tgz#d4c1bb42c3f7ee925f005927ba10709e0d1d1f11"
+ integrity sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==
+ dependencies:
+ whatwg-url "^7.0.0"
+
+sourcemap-codec@^1.4.8:
+ version "1.4.8"
+ resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
+ integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
+
+spdy-transport@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31"
+ integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==
+ dependencies:
+ debug "^4.1.0"
+ detect-node "^2.0.4"
+ hpack.js "^2.1.6"
+ obuf "^1.1.2"
+ readable-stream "^3.0.6"
+ wbuf "^1.7.3"
+
+spdy@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b"
+ integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==
+ dependencies:
+ debug "^4.1.0"
+ handle-thing "^2.0.0"
+ http-deceiver "^1.2.7"
+ select-hose "^2.0.0"
+ spdy-transport "^3.0.0"
+
+sprintf-js@~1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+ integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
+
+stable@^0.1.8:
+ version "0.1.8"
+ resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
+ integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
+
+stack-utils@^2.0.3:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f"
+ integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==
+ dependencies:
+ escape-string-regexp "^2.0.0"
+
+stackframe@^1.3.4:
+ version "1.3.4"
+ resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310"
+ integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==
+
+static-eval@2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-2.0.2.tgz#2d1759306b1befa688938454c546b7871f806a42"
+ integrity sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg==
+ dependencies:
+ escodegen "^1.8.1"
+
+statuses@2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
+ integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
+
+"statuses@>= 1.4.0 < 2":
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
+ integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
+
+string-length@^4.0.1:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a"
+ integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==
+ dependencies:
+ char-regex "^1.0.2"
+ strip-ansi "^6.0.0"
+
+string-length@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/string-length/-/string-length-5.0.1.tgz#3d647f497b6e8e8d41e422f7e0b23bc536c8381e"
+ integrity sha512-9Ep08KAMUn0OadnVaBuRdE2l615CQ508kr0XMadjClfYpdCyvrbFp6Taebo8yyxokQ4viUd/xPPUA4FGgUa0ow==
+ dependencies:
+ char-regex "^2.0.0"
+ strip-ansi "^7.0.1"
+
+string-natural-compare@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/string-natural-compare/-/string-natural-compare-3.0.1.tgz#7a42d58474454963759e8e8b7ae63d71c1e7fdf4"
+ integrity sha512-n3sPwynL1nwKi3WJ6AIsClwBMa0zTi54fn2oLU6ndfTSIO05xaznjSf15PcBZU6FNWbmN5Q6cxT4V5hGvB4taw==
+
+"string-width-cjs@npm:string-width@^4.2.0":
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.1"
+
+string-width@^4.1.0, string-width@^4.2.0:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.1"
+
+string-width@^5.0.1, string-width@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
+ integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==
+ dependencies:
+ eastasianwidth "^0.2.0"
+ emoji-regex "^9.2.2"
+ strip-ansi "^7.0.1"
+
+string.prototype.includes@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz#eceef21283640761a81dbe16d6c7171a4edf7d92"
+ integrity sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==
+ dependencies:
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.3"
+
+string.prototype.matchall@^4.0.11, string.prototype.matchall@^4.0.6:
+ version "4.0.11"
+ resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz#1092a72c59268d2abaad76582dccc687c0297e0a"
+ integrity sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==
+ dependencies:
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.2"
+ es-errors "^1.3.0"
+ es-object-atoms "^1.0.0"
+ get-intrinsic "^1.2.4"
+ gopd "^1.0.1"
+ has-symbols "^1.0.3"
+ internal-slot "^1.0.7"
+ regexp.prototype.flags "^1.5.2"
+ set-function-name "^2.0.2"
+ side-channel "^1.0.6"
+
+string.prototype.repeat@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz#e90872ee0308b29435aa26275f6e1b762daee01a"
+ integrity sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==
+ dependencies:
+ define-properties "^1.1.3"
+ es-abstract "^1.17.5"
+
+string.prototype.trim@^1.2.10:
+ version "1.2.10"
+ resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz#40b2dd5ee94c959b4dcfb1d65ce72e90da480c81"
+ integrity sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==
+ dependencies:
+ call-bind "^1.0.8"
+ call-bound "^1.0.2"
+ define-data-property "^1.1.4"
+ define-properties "^1.2.1"
+ es-abstract "^1.23.5"
+ es-object-atoms "^1.0.0"
+ has-property-descriptors "^1.0.2"
+
+string.prototype.trimend@^1.0.8, string.prototype.trimend@^1.0.9:
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz#62e2731272cd285041b36596054e9f66569b6942"
+ integrity sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==
+ dependencies:
+ call-bind "^1.0.8"
+ call-bound "^1.0.2"
+ define-properties "^1.2.1"
+ es-object-atoms "^1.0.0"
+
+string.prototype.trimstart@^1.0.8:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde"
+ integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==
+ dependencies:
+ call-bind "^1.0.7"
+ define-properties "^1.2.1"
+ es-object-atoms "^1.0.0"
+
+string_decoder@^1.1.1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
+ integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
+ dependencies:
+ safe-buffer "~5.2.0"
+
+string_decoder@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
+ integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
+ dependencies:
+ safe-buffer "~5.1.0"
+
+stringify-object@^3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629"
+ integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==
+ dependencies:
+ get-own-enumerable-property-symbols "^3.0.0"
+ is-obj "^1.0.1"
+ is-regexp "^1.0.0"
+
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+ integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+ dependencies:
+ ansi-regex "^5.0.1"
+
+strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+ integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+ dependencies:
+ ansi-regex "^5.0.1"
+
+strip-ansi@^7.0.1:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
+ integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==
+ dependencies:
+ ansi-regex "^6.0.1"
+
+strip-bom@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
+ integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==
+
+strip-bom@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878"
+ integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==
+
+strip-comments@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/strip-comments/-/strip-comments-2.0.1.tgz#4ad11c3fbcac177a67a40ac224ca339ca1c1ba9b"
+ integrity sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw==
+
+strip-final-newline@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
+ integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
+
+strip-indent@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001"
+ integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==
+ dependencies:
+ min-indent "^1.0.0"
+
+strip-json-comments@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
+ integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
+
+style-loader@^3.3.1:
+ version "3.3.4"
+ resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.4.tgz#f30f786c36db03a45cbd55b6a70d930c479090e7"
+ integrity sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==
+
+stylehacks@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.1.tgz#7934a34eb59d7152149fa69d6e9e56f2fc34bcc9"
+ integrity sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==
+ dependencies:
+ browserslist "^4.21.4"
+ postcss-selector-parser "^6.0.4"
+
+sucrase@^3.35.0:
+ version "3.35.0"
+ resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.35.0.tgz#57f17a3d7e19b36d8995f06679d121be914ae263"
+ integrity sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==
+ dependencies:
+ "@jridgewell/gen-mapping" "^0.3.2"
+ commander "^4.0.0"
+ glob "^10.3.10"
+ lines-and-columns "^1.1.6"
+ mz "^2.7.0"
+ pirates "^4.0.1"
+ ts-interface-checker "^0.1.9"
+
+supports-color@^5.3.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+ integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+ dependencies:
+ has-flag "^3.0.0"
+
+supports-color@^7.0.0, supports-color@^7.1.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+ integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
+ dependencies:
+ has-flag "^4.0.0"
+
+supports-color@^8.0.0:
+ version "8.1.1"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
+ integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
+ dependencies:
+ has-flag "^4.0.0"
+
+supports-hyperlinks@^2.0.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624"
+ integrity sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==
+ dependencies:
+ has-flag "^4.0.0"
+ supports-color "^7.0.0"
+
+supports-preserve-symlinks-flag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
+ integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+
+svg-parser@^2.0.2:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5"
+ integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==
+
+svgo@^1.2.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167"
+ integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==
+ dependencies:
+ chalk "^2.4.1"
+ coa "^2.0.2"
+ css-select "^2.0.0"
+ css-select-base-adapter "^0.1.1"
+ css-tree "1.0.0-alpha.37"
+ csso "^4.0.2"
+ js-yaml "^3.13.1"
+ mkdirp "~0.5.1"
+ object.values "^1.1.0"
+ sax "~1.2.4"
+ stable "^0.1.8"
+ unquote "~1.1.1"
+ util.promisify "~1.0.0"
+
+svgo@^2.7.0:
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24"
+ integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==
+ dependencies:
+ "@trysound/sax" "0.2.0"
+ commander "^7.2.0"
+ css-select "^4.1.3"
+ css-tree "^1.1.3"
+ csso "^4.2.0"
+ picocolors "^1.0.0"
+ stable "^0.1.8"
+
+symbol-tree@^3.2.4:
+ version "3.2.4"
+ resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
+ integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==
+
+synckit@^0.9.1:
+ version "0.9.2"
+ resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.2.tgz#a3a935eca7922d48b9e7d6c61822ee6c3ae4ec62"
+ integrity sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==
+ dependencies:
+ "@pkgr/core" "^0.1.0"
+ tslib "^2.6.2"
+
+tailwind-merge@^2.5.5:
+ version "2.5.5"
+ resolved "https://registry.yarnpkg.com/tailwind-merge/-/tailwind-merge-2.5.5.tgz#98167859b856a2a6b8d2baf038ee171b9d814e39"
+ integrity sha512-0LXunzzAZzo0tEPxV3I297ffKZPlKDrjj7NXphC8V5ak9yHC5zRmxnOe2m/Rd/7ivsOMJe3JZ2JVocoDdQTRBA==
+
+tailwindcss-animate@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz#318b692c4c42676cc9e67b19b78775742388bef4"
+ integrity sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==
+
+tailwindcss@^3.0.2, tailwindcss@^3.4.17:
+ version "3.4.17"
+ resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.4.17.tgz#ae8406c0f96696a631c790768ff319d46d5e5a63"
+ integrity sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==
+ dependencies:
+ "@alloc/quick-lru" "^5.2.0"
+ arg "^5.0.2"
+ chokidar "^3.6.0"
+ didyoumean "^1.2.2"
+ dlv "^1.1.3"
+ fast-glob "^3.3.2"
+ glob-parent "^6.0.2"
+ is-glob "^4.0.3"
+ jiti "^1.21.6"
+ lilconfig "^3.1.3"
+ micromatch "^4.0.8"
+ normalize-path "^3.0.0"
+ object-hash "^3.0.0"
+ picocolors "^1.1.1"
+ postcss "^8.4.47"
+ postcss-import "^15.1.0"
+ postcss-js "^4.0.1"
+ postcss-load-config "^4.0.2"
+ postcss-nested "^6.2.0"
+ postcss-selector-parser "^6.1.2"
+ resolve "^1.22.8"
+ sucrase "^3.35.0"
+
+tapable@^1.0.0:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
+ integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
+
+tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
+ integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
+
+temp-dir@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-2.0.0.tgz#bde92b05bdfeb1516e804c9c00ad45177f31321e"
+ integrity sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==
+
+tempy@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/tempy/-/tempy-0.6.0.tgz#65e2c35abc06f1124a97f387b08303442bde59f3"
+ integrity sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==
+ dependencies:
+ is-stream "^2.0.0"
+ temp-dir "^2.0.0"
+ type-fest "^0.16.0"
+ unique-string "^2.0.0"
+
+terminal-link@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994"
+ integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==
+ dependencies:
+ ansi-escapes "^4.2.1"
+ supports-hyperlinks "^2.0.0"
+
+terser-webpack-plugin@^5.2.5, terser-webpack-plugin@^5.3.10:
+ version "5.3.11"
+ resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.11.tgz#93c21f44ca86634257cac176f884f942b7ba3832"
+ integrity sha512-RVCsMfuD0+cTt3EwX8hSl2Ks56EbFHWmhluwcqoPKtBnfjiT6olaq7PRIRfhyU8nnC2MrnDrBLfrD/RGE+cVXQ==
+ dependencies:
+ "@jridgewell/trace-mapping" "^0.3.25"
+ jest-worker "^27.4.5"
+ schema-utils "^4.3.0"
+ serialize-javascript "^6.0.2"
+ terser "^5.31.1"
+
+terser@^5.0.0, terser@^5.10.0, terser@^5.31.1:
+ version "5.37.0"
+ resolved "https://registry.yarnpkg.com/terser/-/terser-5.37.0.tgz#38aa66d1cfc43d0638fab54e43ff8a4f72a21ba3"
+ integrity sha512-B8wRRkmre4ERucLM/uXx4MOV5cbnOlVAqUst+1+iLKPI0dOgFO28f84ptoQt9HEI537PMzfYa/d+GEPKTRXmYA==
+ dependencies:
+ "@jridgewell/source-map" "^0.3.3"
+ acorn "^8.8.2"
+ commander "^2.20.0"
+ source-map-support "~0.5.20"
+
+test-exclude@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e"
+ integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==
+ dependencies:
+ "@istanbuljs/schema" "^0.1.2"
+ glob "^7.1.4"
+ minimatch "^3.0.4"
+
+text-table@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
+ integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==
+
+thenify-all@^1.0.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726"
+ integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==
+ dependencies:
+ thenify ">= 3.1.0 < 4"
+
+"thenify@>= 3.1.0 < 4":
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f"
+ integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==
+ dependencies:
+ any-promise "^1.0.0"
+
+throat@^6.0.1:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.2.tgz#51a3fbb5e11ae72e2cf74861ed5c8020f89f29fe"
+ integrity sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==
+
+thunky@^1.0.2:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d"
+ integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==
+
+tmpl@1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc"
+ integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==
+
+to-regex-range@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+ integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+ dependencies:
+ is-number "^7.0.0"
+
+toidentifier@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
+ integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
+
+tough-cookie@^4.0.0:
+ version "4.1.4"
+ resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36"
+ integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==
+ dependencies:
+ psl "^1.1.33"
+ punycode "^2.1.1"
+ universalify "^0.2.0"
+ url-parse "^1.5.3"
+
+tr46@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
+ integrity sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==
+ dependencies:
+ punycode "^2.1.0"
+
+tr46@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240"
+ integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==
+ dependencies:
+ punycode "^2.1.1"
+
+tryer@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"
+ integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==
+
+ts-api-utils@^1.3.0:
+ version "1.4.3"
+ resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz#bfc2215fe6528fecab2b0fba570a2e8a4263b064"
+ integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==
+
+ts-interface-checker@^0.1.9:
+ version "0.1.13"
+ resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699"
+ integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==
+
+tsconfig-paths@^3.15.0:
+ version "3.15.0"
+ resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4"
+ integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==
+ dependencies:
+ "@types/json5" "^0.0.29"
+ json5 "^1.0.2"
+ minimist "^1.2.6"
+ strip-bom "^3.0.0"
+
+tslib@^1.8.1:
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
+ integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
+
+tslib@^2.0.3, tslib@^2.6.2:
+ version "2.8.1"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
+ integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
+
+tsutils@^3.21.0:
+ version "3.21.0"
+ resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
+ integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==
+ dependencies:
+ tslib "^1.8.1"
+
+type-check@^0.4.0, type-check@~0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1"
+ integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==
+ dependencies:
+ prelude-ls "^1.2.1"
+
+type-check@~0.3.2:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+ integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==
+ dependencies:
+ prelude-ls "~1.1.2"
+
+type-detect@4.0.8:
+ version "4.0.8"
+ resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
+ integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
+
+type-fest@^0.16.0:
+ version "0.16.0"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.16.0.tgz#3240b891a78b0deae910dbeb86553e552a148860"
+ integrity sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==
+
+type-fest@^0.20.2:
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
+ integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
+
+type-fest@^0.21.3:
+ version "0.21.3"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
+ integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
+
+type-is@~1.6.18:
+ version "1.6.18"
+ resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
+ integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
+ dependencies:
+ media-typer "0.3.0"
+ mime-types "~2.1.24"
+
+typed-array-buffer@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536"
+ integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==
+ dependencies:
+ call-bound "^1.0.3"
+ es-errors "^1.3.0"
+ is-typed-array "^1.1.14"
+
+typed-array-byte-length@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz#8407a04f7d78684f3d252aa1a143d2b77b4160ce"
+ integrity sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==
+ dependencies:
+ call-bind "^1.0.8"
+ for-each "^0.3.3"
+ gopd "^1.2.0"
+ has-proto "^1.2.0"
+ is-typed-array "^1.1.14"
+
+typed-array-byte-offset@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.3.tgz#3fa9f22567700cc86aaf86a1e7176f74b59600f2"
+ integrity sha512-GsvTyUHTriq6o/bHcTd0vM7OQ9JEdlvluu9YISaA7+KzDzPaIzEeDFNkTfhdE3MYcNhNi0vq/LlegYgIs5yPAw==
+ dependencies:
+ available-typed-arrays "^1.0.7"
+ call-bind "^1.0.7"
+ for-each "^0.3.3"
+ gopd "^1.0.1"
+ has-proto "^1.0.3"
+ is-typed-array "^1.1.13"
+ reflect.getprototypeof "^1.0.6"
+
+typed-array-length@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.7.tgz#ee4deff984b64be1e118b0de8c9c877d5ce73d3d"
+ integrity sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==
+ dependencies:
+ call-bind "^1.0.7"
+ for-each "^0.3.3"
+ gopd "^1.0.1"
+ is-typed-array "^1.1.13"
+ possible-typed-array-names "^1.0.0"
+ reflect.getprototypeof "^1.0.6"
+
+typedarray-to-buffer@^3.1.5:
+ version "3.1.5"
+ resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
+ integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
+ dependencies:
+ is-typedarray "^1.0.0"
+
+typescript@^5.7.2:
+ version "5.7.2"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.7.2.tgz#3169cf8c4c8a828cde53ba9ecb3d2b1d5dd67be6"
+ integrity sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==
+
+unbox-primitive@^1.0.2:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz#8d9d2c9edeea8460c7f35033a88867944934d1e2"
+ integrity sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==
+ dependencies:
+ call-bound "^1.0.3"
+ has-bigints "^1.0.2"
+ has-symbols "^1.1.0"
+ which-boxed-primitive "^1.1.1"
+
+underscore@1.12.1:
+ version "1.12.1"
+ resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.12.1.tgz#7bb8cc9b3d397e201cf8553336d262544ead829e"
+ integrity sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==
+
+undici-types@~6.20.0:
+ version "6.20.0"
+ resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433"
+ integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==
+
+unicode-canonical-property-names-ecmascript@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz#cb3173fe47ca743e228216e4a3ddc4c84d628cc2"
+ integrity sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==
+
+unicode-match-property-ecmascript@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3"
+ integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==
+ dependencies:
+ unicode-canonical-property-names-ecmascript "^2.0.0"
+ unicode-property-aliases-ecmascript "^2.0.0"
+
+unicode-match-property-value-ecmascript@^2.1.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz#a0401aee72714598f739b68b104e4fe3a0cb3c71"
+ integrity sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==
+
+unicode-property-aliases-ecmascript@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd"
+ integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==
+
+unique-string@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d"
+ integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==
+ dependencies:
+ crypto-random-string "^2.0.0"
+
+universalify@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0"
+ integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==
+
+universalify@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d"
+ integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==
+
+unpipe@1.0.0, unpipe@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+ integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
+
+unquote@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544"
+ integrity sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg==
+
+upath@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894"
+ integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==
+
+update-browserslist-db@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5"
+ integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==
+ dependencies:
+ escalade "^3.2.0"
+ picocolors "^1.1.0"
+
+uri-js@^4.2.2:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
+ integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
+ dependencies:
+ punycode "^2.1.0"
+
+url-parse@^1.5.3:
+ version "1.5.10"
+ resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1"
+ integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==
+ dependencies:
+ querystringify "^2.1.1"
+ requires-port "^1.0.0"
+
+use-reducer-async@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/use-reducer-async/-/use-reducer-async-2.1.1.tgz#c90eb7af3a7ef23c772b2712a9d56b03a0e272aa"
+ integrity sha512-oPSFzOIEPgMenQkMHzqeRgsQLSpcyGkspAnyTWP4l1tKlt31wMVMz6wWj6g/jea/Ms7lRvBz4AL+Okt83Tntig==
+
+use-sync-external-store@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz#adbc795d8eeb47029963016cefdf89dc799fcebc"
+ integrity sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==
+
+util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+ integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
+
+util.promisify@~1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.1.tgz#6baf7774b80eeb0f7520d8b81d07982a59abbaee"
+ integrity sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==
+ dependencies:
+ define-properties "^1.1.3"
+ es-abstract "^1.17.2"
+ has-symbols "^1.0.1"
+ object.getownpropertydescriptors "^2.1.0"
+
+utila@~0.4:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c"
+ integrity sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==
+
+utils-merge@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
+ integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
+
+uuid@^8.3.2:
+ version "8.3.2"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
+ integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
+
+v8-to-istanbul@^8.1.0:
+ version "8.1.1"
+ resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed"
+ integrity sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==
+ dependencies:
+ "@types/istanbul-lib-coverage" "^2.0.1"
+ convert-source-map "^1.6.0"
+ source-map "^0.7.3"
+
+vary@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+ integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
+
+w3c-hr-time@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"
+ integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==
+ dependencies:
+ browser-process-hrtime "^1.0.0"
+
+w3c-xmlserializer@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a"
+ integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==
+ dependencies:
+ xml-name-validator "^3.0.0"
+
+walker@^1.0.7:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f"
+ integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==
+ dependencies:
+ makeerror "1.0.12"
+
+watchpack@^2.4.1:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.2.tgz#2feeaed67412e7c33184e5a79ca738fbd38564da"
+ integrity sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==
+ dependencies:
+ glob-to-regexp "^0.4.1"
+ graceful-fs "^4.1.2"
+
+wbuf@^1.1.0, wbuf@^1.7.3:
+ version "1.7.3"
+ resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df"
+ integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==
+ dependencies:
+ minimalistic-assert "^1.0.0"
+
+web-vitals@^4.2.4:
+ version "4.2.4"
+ resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-4.2.4.tgz#1d20bc8590a37769bd0902b289550936069184b7"
+ integrity sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==
+
+webidl-conversions@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
+ integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
+
+webidl-conversions@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff"
+ integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==
+
+webidl-conversions@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514"
+ integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==
+
+webpack-dev-middleware@^5.3.4:
+ version "5.3.4"
+ resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz#eb7b39281cbce10e104eb2b8bf2b63fce49a3517"
+ integrity sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==
+ dependencies:
+ colorette "^2.0.10"
+ memfs "^3.4.3"
+ mime-types "^2.1.31"
+ range-parser "^1.2.1"
+ schema-utils "^4.0.0"
+
+webpack-dev-server@^4.6.0:
+ version "4.15.2"
+ resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.15.2.tgz#9e0c70a42a012560860adb186986da1248333173"
+ integrity sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==
+ dependencies:
+ "@types/bonjour" "^3.5.9"
+ "@types/connect-history-api-fallback" "^1.3.5"
+ "@types/express" "^4.17.13"
+ "@types/serve-index" "^1.9.1"
+ "@types/serve-static" "^1.13.10"
+ "@types/sockjs" "^0.3.33"
+ "@types/ws" "^8.5.5"
+ ansi-html-community "^0.0.8"
+ bonjour-service "^1.0.11"
+ chokidar "^3.5.3"
+ colorette "^2.0.10"
+ compression "^1.7.4"
+ connect-history-api-fallback "^2.0.0"
+ default-gateway "^6.0.3"
+ express "^4.17.3"
+ graceful-fs "^4.2.6"
+ html-entities "^2.3.2"
+ http-proxy-middleware "^2.0.3"
+ ipaddr.js "^2.0.1"
+ launch-editor "^2.6.0"
+ open "^8.0.9"
+ p-retry "^4.5.0"
+ rimraf "^3.0.2"
+ schema-utils "^4.0.0"
+ selfsigned "^2.1.1"
+ serve-index "^1.9.1"
+ sockjs "^0.3.24"
+ spdy "^4.0.2"
+ webpack-dev-middleware "^5.3.4"
+ ws "^8.13.0"
+
+webpack-manifest-plugin@^4.0.2:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/webpack-manifest-plugin/-/webpack-manifest-plugin-4.1.1.tgz#10f8dbf4714ff93a215d5a45bcc416d80506f94f"
+ integrity sha512-YXUAwxtfKIJIKkhg03MKuiFAD72PlrqCiwdwO4VEXdRO5V0ORCNwaOwAZawPZalCbmH9kBDmXnNeQOw+BIEiow==
+ dependencies:
+ tapable "^2.0.0"
+ webpack-sources "^2.2.0"
+
+webpack-sources@^1.4.3:
+ version "1.4.3"
+ resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
+ integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==
+ dependencies:
+ source-list-map "^2.0.0"
+ source-map "~0.6.1"
+
+webpack-sources@^2.2.0:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.3.1.tgz#570de0af163949fe272233c2cefe1b56f74511fd"
+ integrity sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==
+ dependencies:
+ source-list-map "^2.0.1"
+ source-map "^0.6.1"
+
+webpack-sources@^3.2.3:
+ version "3.2.3"
+ resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
+ integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
+
+webpack@^5.64.4:
+ version "5.97.1"
+ resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.97.1.tgz#972a8320a438b56ff0f1d94ade9e82eac155fa58"
+ integrity sha512-EksG6gFY3L1eFMROS/7Wzgrii5mBAFe4rIr3r2BTfo7bcc+DWwFZ4OJ/miOuHJO/A85HwyI4eQ0F6IKXesO7Fg==
+ dependencies:
+ "@types/eslint-scope" "^3.7.7"
+ "@types/estree" "^1.0.6"
+ "@webassemblyjs/ast" "^1.14.1"
+ "@webassemblyjs/wasm-edit" "^1.14.1"
+ "@webassemblyjs/wasm-parser" "^1.14.1"
+ acorn "^8.14.0"
+ browserslist "^4.24.0"
+ chrome-trace-event "^1.0.2"
+ enhanced-resolve "^5.17.1"
+ es-module-lexer "^1.2.1"
+ eslint-scope "5.1.1"
+ events "^3.2.0"
+ glob-to-regexp "^0.4.1"
+ graceful-fs "^4.2.11"
+ json-parse-even-better-errors "^2.3.1"
+ loader-runner "^4.2.0"
+ mime-types "^2.1.27"
+ neo-async "^2.6.2"
+ schema-utils "^3.2.0"
+ tapable "^2.1.1"
+ terser-webpack-plugin "^5.3.10"
+ watchpack "^2.4.1"
+ webpack-sources "^3.2.3"
+
+websocket-driver@>=0.5.1, websocket-driver@^0.7.4:
+ version "0.7.4"
+ resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760"
+ integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==
+ dependencies:
+ http-parser-js ">=0.5.1"
+ safe-buffer ">=5.1.0"
+ websocket-extensions ">=0.1.1"
+
+websocket-extensions@>=0.1.1:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42"
+ integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==
+
+whatwg-encoding@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0"
+ integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==
+ dependencies:
+ iconv-lite "0.4.24"
+
+whatwg-fetch@^3.6.2:
+ version "3.6.20"
+ resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz#580ce6d791facec91d37c72890995a0b48d31c70"
+ integrity sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==
+
+whatwg-mimetype@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf"
+ integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==
+
+whatwg-url@^7.0.0:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06"
+ integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==
+ dependencies:
+ lodash.sortby "^4.7.0"
+ tr46 "^1.0.1"
+ webidl-conversions "^4.0.2"
+
+whatwg-url@^8.0.0, whatwg-url@^8.5.0:
+ version "8.7.0"
+ resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77"
+ integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==
+ dependencies:
+ lodash "^4.7.0"
+ tr46 "^2.1.0"
+ webidl-conversions "^6.1.0"
+
+which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz#d76ec27df7fa165f18d5808374a5fe23c29b176e"
+ integrity sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==
+ dependencies:
+ is-bigint "^1.1.0"
+ is-boolean-object "^1.2.1"
+ is-number-object "^1.1.1"
+ is-string "^1.1.1"
+ is-symbol "^1.1.1"
+
+which-builtin-type@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz#89183da1b4907ab089a6b02029cc5d8d6574270e"
+ integrity sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==
+ dependencies:
+ call-bound "^1.0.2"
+ function.prototype.name "^1.1.6"
+ has-tostringtag "^1.0.2"
+ is-async-function "^2.0.0"
+ is-date-object "^1.1.0"
+ is-finalizationregistry "^1.1.0"
+ is-generator-function "^1.0.10"
+ is-regex "^1.2.1"
+ is-weakref "^1.0.2"
+ isarray "^2.0.5"
+ which-boxed-primitive "^1.1.0"
+ which-collection "^1.0.2"
+ which-typed-array "^1.1.16"
+
+which-collection@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0"
+ integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==
+ dependencies:
+ is-map "^2.0.3"
+ is-set "^2.0.3"
+ is-weakmap "^2.0.2"
+ is-weakset "^2.0.3"
+
+which-typed-array@^1.1.16:
+ version "1.1.18"
+ resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.18.tgz#df2389ebf3fbb246a71390e90730a9edb6ce17ad"
+ integrity sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==
+ dependencies:
+ available-typed-arrays "^1.0.7"
+ call-bind "^1.0.8"
+ call-bound "^1.0.3"
+ for-each "^0.3.3"
+ gopd "^1.2.0"
+ has-tostringtag "^1.0.2"
+
+which@^1.3.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
+ integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
+ dependencies:
+ isexe "^2.0.0"
+
+which@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+ integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
+ dependencies:
+ isexe "^2.0.0"
+
+word-wrap@^1.2.5, word-wrap@~1.2.3:
+ version "1.2.5"
+ resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
+ integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
+
+workbox-background-sync@6.6.1:
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/workbox-background-sync/-/workbox-background-sync-6.6.1.tgz#08d603a33717ce663e718c30cc336f74909aff2f"
+ integrity sha512-trJd3ovpWCvzu4sW0E8rV3FUyIcC0W8G+AZ+VcqzzA890AsWZlUGOTSxIMmIHVusUw/FDq1HFWfy/kC/WTRqSg==
+ dependencies:
+ idb "^7.0.1"
+ workbox-core "6.6.1"
+
+workbox-broadcast-update@6.6.1:
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/workbox-broadcast-update/-/workbox-broadcast-update-6.6.1.tgz#0fad9454cf8e4ace0c293e5617c64c75d8a8c61e"
+ integrity sha512-fBhffRdaANdeQ1V8s692R9l/gzvjjRtydBOvR6WCSB0BNE2BacA29Z4r9/RHd9KaXCPl6JTdI9q0bR25YKP8TQ==
+ dependencies:
+ workbox-core "6.6.1"
+
+workbox-build@6.6.1:
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/workbox-build/-/workbox-build-6.6.1.tgz#6010e9ce550910156761448f2dbea8cfcf759cb0"
+ integrity sha512-INPgDx6aRycAugUixbKgiEQBWD0MPZqU5r0jyr24CehvNuLPSXp/wGOpdRJmts656lNiXwqV7dC2nzyrzWEDnw==
+ dependencies:
+ "@apideck/better-ajv-errors" "^0.3.1"
+ "@babel/core" "^7.11.1"
+ "@babel/preset-env" "^7.11.0"
+ "@babel/runtime" "^7.11.2"
+ "@rollup/plugin-babel" "^5.2.0"
+ "@rollup/plugin-node-resolve" "^11.2.1"
+ "@rollup/plugin-replace" "^2.4.1"
+ "@surma/rollup-plugin-off-main-thread" "^2.2.3"
+ ajv "^8.6.0"
+ common-tags "^1.8.0"
+ fast-json-stable-stringify "^2.1.0"
+ fs-extra "^9.0.1"
+ glob "^7.1.6"
+ lodash "^4.17.20"
+ pretty-bytes "^5.3.0"
+ rollup "^2.43.1"
+ rollup-plugin-terser "^7.0.0"
+ source-map "^0.8.0-beta.0"
+ stringify-object "^3.3.0"
+ strip-comments "^2.0.1"
+ tempy "^0.6.0"
+ upath "^1.2.0"
+ workbox-background-sync "6.6.1"
+ workbox-broadcast-update "6.6.1"
+ workbox-cacheable-response "6.6.1"
+ workbox-core "6.6.1"
+ workbox-expiration "6.6.1"
+ workbox-google-analytics "6.6.1"
+ workbox-navigation-preload "6.6.1"
+ workbox-precaching "6.6.1"
+ workbox-range-requests "6.6.1"
+ workbox-recipes "6.6.1"
+ workbox-routing "6.6.1"
+ workbox-strategies "6.6.1"
+ workbox-streams "6.6.1"
+ workbox-sw "6.6.1"
+ workbox-window "6.6.1"
+
+workbox-cacheable-response@6.6.1:
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/workbox-cacheable-response/-/workbox-cacheable-response-6.6.1.tgz#284c2b86be3f4fd191970ace8c8e99797bcf58e9"
+ integrity sha512-85LY4veT2CnTCDxaVG7ft3NKaFbH6i4urZXgLiU4AiwvKqS2ChL6/eILiGRYXfZ6gAwDnh5RkuDbr/GMS4KSag==
+ dependencies:
+ workbox-core "6.6.1"
+
+workbox-core@6.6.1:
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/workbox-core/-/workbox-core-6.6.1.tgz#7184776d4134c5ed2f086878c882728fc9084265"
+ integrity sha512-ZrGBXjjaJLqzVothoE12qTbVnOAjFrHDXpZe7coCb6q65qI/59rDLwuFMO4PcZ7jcbxY+0+NhUVztzR/CbjEFw==
+
+workbox-expiration@6.6.1:
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/workbox-expiration/-/workbox-expiration-6.6.1.tgz#a841fa36676104426dbfb9da1ef6a630b4f93739"
+ integrity sha512-qFiNeeINndiOxaCrd2DeL1Xh1RFug3JonzjxUHc5WkvkD2u5abY3gZL1xSUNt3vZKsFFGGORItSjVTVnWAZO4A==
+ dependencies:
+ idb "^7.0.1"
+ workbox-core "6.6.1"
+
+workbox-google-analytics@6.6.1:
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/workbox-google-analytics/-/workbox-google-analytics-6.6.1.tgz#a07a6655ab33d89d1b0b0a935ffa5dea88618c5d"
+ integrity sha512-1TjSvbFSLmkpqLcBsF7FuGqqeDsf+uAXO/pjiINQKg3b1GN0nBngnxLcXDYo1n/XxK4N7RaRrpRlkwjY/3ocuA==
+ dependencies:
+ workbox-background-sync "6.6.1"
+ workbox-core "6.6.1"
+ workbox-routing "6.6.1"
+ workbox-strategies "6.6.1"
+
+workbox-navigation-preload@6.6.1:
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/workbox-navigation-preload/-/workbox-navigation-preload-6.6.1.tgz#61a34fe125558dd88cf09237f11bd966504ea059"
+ integrity sha512-DQCZowCecO+wRoIxJI2V6bXWK6/53ff+hEXLGlQL4Rp9ZaPDLrgV/32nxwWIP7QpWDkVEtllTAK5h6cnhxNxDA==
+ dependencies:
+ workbox-core "6.6.1"
+
+workbox-precaching@6.6.1:
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/workbox-precaching/-/workbox-precaching-6.6.1.tgz#dedeeba10a2d163d990bf99f1c2066ac0d1a19e2"
+ integrity sha512-K4znSJ7IKxCnCYEdhNkMr7X1kNh8cz+mFgx9v5jFdz1MfI84pq8C2zG+oAoeE5kFrUf7YkT5x4uLWBNg0DVZ5A==
+ dependencies:
+ workbox-core "6.6.1"
+ workbox-routing "6.6.1"
+ workbox-strategies "6.6.1"
+
+workbox-range-requests@6.6.1:
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/workbox-range-requests/-/workbox-range-requests-6.6.1.tgz#ddaf7e73af11d362fbb2f136a9063a4c7f507a39"
+ integrity sha512-4BDzk28govqzg2ZpX0IFkthdRmCKgAKreontYRC5YsAPB2jDtPNxqx3WtTXgHw1NZalXpcH/E4LqUa9+2xbv1g==
+ dependencies:
+ workbox-core "6.6.1"
+
+workbox-recipes@6.6.1:
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/workbox-recipes/-/workbox-recipes-6.6.1.tgz#ea70d2b2b0b0bce8de0a9d94f274d4a688e69fae"
+ integrity sha512-/oy8vCSzromXokDA+X+VgpeZJvtuf8SkQ8KL0xmRivMgJZrjwM3c2tpKTJn6PZA6TsbxGs3Sc7KwMoZVamcV2g==
+ dependencies:
+ workbox-cacheable-response "6.6.1"
+ workbox-core "6.6.1"
+ workbox-expiration "6.6.1"
+ workbox-precaching "6.6.1"
+ workbox-routing "6.6.1"
+ workbox-strategies "6.6.1"
+
+workbox-routing@6.6.1:
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/workbox-routing/-/workbox-routing-6.6.1.tgz#cba9a1c7e0d1ea11e24b6f8c518840efdc94f581"
+ integrity sha512-j4ohlQvfpVdoR8vDYxTY9rA9VvxTHogkIDwGdJ+rb2VRZQ5vt1CWwUUZBeD/WGFAni12jD1HlMXvJ8JS7aBWTg==
+ dependencies:
+ workbox-core "6.6.1"
+
+workbox-strategies@6.6.1:
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/workbox-strategies/-/workbox-strategies-6.6.1.tgz#38d0f0fbdddba97bd92e0c6418d0b1a2ccd5b8bf"
+ integrity sha512-WQLXkRnsk4L81fVPkkgon1rZNxnpdO5LsO+ws7tYBC6QQQFJVI6v98klrJEjFtZwzw/mB/HT5yVp7CcX0O+mrw==
+ dependencies:
+ workbox-core "6.6.1"
+
+workbox-streams@6.6.1:
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/workbox-streams/-/workbox-streams-6.6.1.tgz#b2f7ba7b315c27a6e3a96a476593f99c5d227d26"
+ integrity sha512-maKG65FUq9e4BLotSKWSTzeF0sgctQdYyTMq529piEN24Dlu9b6WhrAfRpHdCncRS89Zi2QVpW5V33NX8PgH3Q==
+ dependencies:
+ workbox-core "6.6.1"
+ workbox-routing "6.6.1"
+
+workbox-sw@6.6.1:
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/workbox-sw/-/workbox-sw-6.6.1.tgz#d4c4ca3125088e8b9fd7a748ed537fa0247bd72c"
+ integrity sha512-R7whwjvU2abHH/lR6kQTTXLHDFU2izht9kJOvBRYK65FbwutT4VvnUAJIgHvfWZ/fokrOPhfoWYoPCMpSgUKHQ==
+
+workbox-webpack-plugin@^6.4.1:
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/workbox-webpack-plugin/-/workbox-webpack-plugin-6.6.1.tgz#4f81cc1ad4e5d2cd7477a86ba83c84ee2d187531"
+ integrity sha512-zpZ+ExFj9NmiI66cFEApyjk7hGsfJ1YMOaLXGXBoZf0v7Iu6hL0ZBe+83mnDq3YYWAfA3fnyFejritjOHkFcrA==
+ dependencies:
+ fast-json-stable-stringify "^2.1.0"
+ pretty-bytes "^5.4.1"
+ upath "^1.2.0"
+ webpack-sources "^1.4.3"
+ workbox-build "6.6.1"
+
+workbox-window@6.6.1:
+ version "6.6.1"
+ resolved "https://registry.yarnpkg.com/workbox-window/-/workbox-window-6.6.1.tgz#f22a394cbac36240d0dadcbdebc35f711bb7b89e"
+ integrity sha512-wil4nwOY58nTdCvif/KEZjQ2NP8uk3gGeRNy2jPBbzypU4BT4D9L8xiwbmDBpZlSgJd2xsT9FvSNU0gsxV51JQ==
+ dependencies:
+ "@types/trusted-types" "^2.0.2"
+ workbox-core "6.6.1"
+
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
+wrap-ansi@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
+wrap-ansi@^8.1.0:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
+ integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==
+ dependencies:
+ ansi-styles "^6.1.0"
+ string-width "^5.0.1"
+ strip-ansi "^7.0.1"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
+
+write-file-atomic@^3.0.0:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8"
+ integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==
+ dependencies:
+ imurmurhash "^0.1.4"
+ is-typedarray "^1.0.0"
+ signal-exit "^3.0.2"
+ typedarray-to-buffer "^3.1.5"
+
+ws@^7.4.6:
+ version "7.5.10"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9"
+ integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==
+
+ws@^8.13.0:
+ version "8.18.0"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc"
+ integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==
+
+xml-name-validator@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
+ integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==
+
+xmlchars@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"
+ integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==
+
+y18n@^5.0.5:
+ version "5.0.8"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
+ integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
+
+yallist@^3.0.2:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd"
+ integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==
+
+yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2:
+ version "1.10.2"
+ resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
+ integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
+
+yaml@^2.3.4:
+ version "2.6.1"
+ resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.6.1.tgz#42f2b1ba89203f374609572d5349fb8686500773"
+ integrity sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==
+
+yargs-parser@^20.2.2:
+ version "20.2.9"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
+ integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
+
+yargs@^16.2.0:
+ version "16.2.0"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
+ integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
+ dependencies:
+ cliui "^7.0.2"
+ escalade "^3.1.1"
+ get-caller-file "^2.0.5"
+ require-directory "^2.1.1"
+ string-width "^4.2.0"
+ y18n "^5.0.5"
+ yargs-parser "^20.2.2"
+
+yocto-queue@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
+ integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
diff --git a/examples/rag/elastic-chatbot-rag-app/k8s-manifest.yml b/examples/rag/elastic-chatbot-rag-app/k8s-manifest.yml
new file mode 100644
index 00000000..91e5cdd1
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/k8s-manifest.yml
@@ -0,0 +1,58 @@
+---
+# chatbot-rag-app deploys "create-index" to install ELSER and load values.
+# Then, it starts "api-frontend" to serve the application.
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: chatbot-rag-app
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: chatbot-rag-app
+ template:
+ metadata:
+ labels:
+ app: chatbot-rag-app
+ spec:
+ # For `LLM_TYPE=vertex`: create a volume for application_default_credentials.json
+ volumes:
+ - name: gcloud-credentials
+ secret:
+ secretName: gcloud-credentials
+ optional: true # only read when `LLM_TYPE=vertex`
+ initContainers:
+ - name: create-index
+ image: &image ghcr.io/elastic/elasticsearch-labs/chatbot-rag-app:latest
+ command: &command [ "opentelemetry-instrument" ] # match image
+ args: [ "flask", "create-index" ]
+ # This recreates your configmap based on your .env file:
+ # kubectl create configmap chatbot-rag-app-env --from-env-file=.env
+ envFrom: &envFrom
+ - configMapRef:
+ name: chatbot-rag-app-env
+ containers:
+ - name: api-frontend
+ image: *image
+ command: *command
+ args: [ "python", "api/app.py" ]
+ ports:
+ - containerPort: 4000
+ envFrom: *envFrom
+ # For `LLM_TYPE=vertex`: mount credentials to the path read by the google-cloud-sdk
+ volumeMounts:
+ - name: gcloud-credentials
+ mountPath: /root/.config/gcloud
+ readOnly: true
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: api
+spec:
+ selector:
+ app: chatbot-rag-app
+ ports:
+ - protocol: TCP
+ port: 4000
+ targetPort: 4000
diff --git a/examples/rag/elastic-chatbot-rag-app/requirements.in b/examples/rag/elastic-chatbot-rag-app/requirements.in
new file mode 100644
index 00000000..9b027660
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/requirements.in
@@ -0,0 +1,24 @@
+# core dependencies
+elasticsearch
+langchain
+langchain-elasticsearch
+tiktoken
+flask
+flask-cors
+halo
+
+# LLM dependencies
+langchain-openai
+langchain-cohere
+langchain-google-vertexai
+langchain-aws
+langchain-mistralai
+langgraph
+
+# EDOT dependencies
+elastic-opentelemetry
+# Additional LLM support not yet in EDOT
+langtrace-python-sdk
+
+# Logging dependencies
+galileo
\ No newline at end of file
diff --git a/examples/rag/elastic-chatbot-rag-app/requirements.txt b/examples/rag/elastic-chatbot-rag-app/requirements.txt
new file mode 100644
index 00000000..075e3c78
--- /dev/null
+++ b/examples/rag/elastic-chatbot-rag-app/requirements.txt
@@ -0,0 +1,535 @@
+#
+# This file is autogenerated by pip-compile with Python 3.12
+# by the following command:
+#
+# pip-compile
+#
+aiohappyeyeballs==2.6.1
+ # via aiohttp
+aiohttp==3.11.14
+ # via langchain-community
+aiosignal==1.3.2
+ # via aiohttp
+annotated-types==0.7.0
+ # via pydantic
+anyio==4.9.0
+ # via
+ # httpx
+ # openai
+attrs==25.3.0
+ # via aiohttp
+blinker==1.9.0
+ # via flask
+boto3==1.37.13
+ # via
+ # langchain-aws
+ # langtrace-python-sdk
+botocore==1.37.13
+ # via
+ # boto3
+ # s3transfer
+cachetools==5.5.2
+ # via google-auth
+certifi==2025.1.31
+ # via
+ # elastic-transport
+ # httpcore
+ # httpx
+ # requests
+ # sentry-sdk
+charset-normalizer==3.4.1
+ # via requests
+click==8.1.8
+ # via flask
+cohere==5.14.0
+ # via langchain-cohere
+colorama==0.4.6
+ # via
+ # halo
+ # langtrace-python-sdk
+ # log-symbols
+dataclasses-json==0.6.7
+ # via langchain-community
+deprecated==1.2.18
+ # via
+ # opentelemetry-api
+ # opentelemetry-exporter-otlp-proto-grpc
+ # opentelemetry-exporter-otlp-proto-http
+ # opentelemetry-semantic-conventions
+distro==1.9.0
+ # via openai
+docstring-parser==0.16
+ # via google-cloud-aiplatform
+elastic-opentelemetry==0.8.0
+ # via -r requirements.in
+elastic-transport==8.17.1
+ # via elasticsearch
+elasticsearch[vectorstore-mmr]==8.17.2
+ # via
+ # -r requirements.in
+ # langchain-elasticsearch
+fastavro==1.10.0
+ # via cohere
+filelock==3.18.0
+ # via
+ # huggingface-hub
+ # transformers
+flask==3.1.0
+ # via
+ # -r requirements.in
+ # flask-cors
+flask-cors==5.0.1
+ # via -r requirements.in
+frozenlist==1.5.0
+ # via
+ # aiohttp
+ # aiosignal
+fsspec==2025.3.0
+ # via
+ # huggingface-hub
+ # langtrace-python-sdk
+google-api-core[grpc]==2.24.2
+ # via
+ # google-cloud-aiplatform
+ # google-cloud-bigquery
+ # google-cloud-core
+ # google-cloud-resource-manager
+ # google-cloud-storage
+google-auth==2.38.0
+ # via
+ # google-api-core
+ # google-cloud-aiplatform
+ # google-cloud-bigquery
+ # google-cloud-core
+ # google-cloud-resource-manager
+ # google-cloud-storage
+google-cloud-aiplatform==1.84.0
+ # via langchain-google-vertexai
+google-cloud-bigquery==3.30.0
+ # via google-cloud-aiplatform
+google-cloud-core==2.4.3
+ # via
+ # google-cloud-bigquery
+ # google-cloud-storage
+google-cloud-resource-manager==1.14.2
+ # via google-cloud-aiplatform
+google-cloud-storage==2.19.0
+ # via
+ # google-cloud-aiplatform
+ # langchain-google-vertexai
+google-crc32c==1.6.0
+ # via
+ # google-cloud-storage
+ # google-resumable-media
+google-resumable-media==2.7.2
+ # via
+ # google-cloud-bigquery
+ # google-cloud-storage
+googleapis-common-protos[grpc]==1.69.2
+ # via
+ # google-api-core
+ # grpc-google-iam-v1
+ # grpcio-status
+ # opentelemetry-exporter-otlp-proto-grpc
+ # opentelemetry-exporter-otlp-proto-http
+greenlet==3.1.1
+ # via sqlalchemy
+grpc-google-iam-v1==0.14.2
+ # via google-cloud-resource-manager
+grpcio==1.71.0
+ # via
+ # google-api-core
+ # googleapis-common-protos
+ # grpc-google-iam-v1
+ # grpcio-status
+ # opentelemetry-exporter-otlp-proto-grpc
+grpcio-status==1.71.0
+ # via google-api-core
+h11==0.14.0
+ # via httpcore
+halo==0.0.31
+ # via -r requirements.in
+httpcore==1.0.7
+ # via httpx
+httpx==0.28.1
+ # via
+ # cohere
+ # langchain-google-vertexai
+ # langchain-mistralai
+ # langsmith
+ # openai
+httpx-sse==0.4.0
+ # via
+ # cohere
+ # langchain-community
+ # langchain-google-vertexai
+ # langchain-mistralai
+huggingface-hub==0.29.3
+ # via
+ # tokenizers
+ # transformers
+idna==3.10
+ # via
+ # anyio
+ # httpx
+ # requests
+ # yarl
+importlib-metadata==8.6.1
+ # via opentelemetry-api
+itsdangerous==2.2.0
+ # via flask
+jinja2==3.1.6
+ # via flask
+jiter==0.9.0
+ # via openai
+jmespath==1.0.1
+ # via
+ # boto3
+ # botocore
+jsonpatch==1.33
+ # via langchain-core
+jsonpointer==3.0.0
+ # via jsonpatch
+langchain==0.3.20
+ # via
+ # -r requirements.in
+ # langchain-community
+langchain-aws==0.2.15
+ # via -r requirements.in
+langchain-cohere==0.4.3
+ # via -r requirements.in
+langchain-community==0.3.19
+ # via langchain-cohere
+langchain-core==0.3.45
+ # via
+ # langchain
+ # langchain-aws
+ # langchain-cohere
+ # langchain-community
+ # langchain-elasticsearch
+ # langchain-google-vertexai
+ # langchain-mistralai
+ # langchain-openai
+ # langchain-text-splitters
+langchain-elasticsearch==0.3.2
+ # via -r requirements.in
+langchain-google-vertexai==2.0.15
+ # via -r requirements.in
+langchain-mistralai==0.2.8
+ # via -r requirements.in
+langchain-openai==0.3.8
+ # via -r requirements.in
+langchain-text-splitters==0.3.6
+ # via langchain
+langsmith==0.3.15
+ # via
+ # langchain
+ # langchain-community
+ # langchain-core
+langtrace-python-sdk==3.8.6
+ # via -r requirements.in
+log-symbols==0.0.14
+ # via halo
+markupsafe==3.0.2
+ # via
+ # jinja2
+ # werkzeug
+marshmallow==3.26.1
+ # via dataclasses-json
+multidict==6.1.0
+ # via
+ # aiohttp
+ # yarl
+mypy-extensions==1.0.0
+ # via typing-inspect
+numpy
+ # via
+ # elasticsearch
+ # langchain-aws
+ # langchain-community
+ # shapely
+ # transformers
+openai==1.66.3
+ # via langchain-openai
+opentelemetry-api==1.31.0
+ # via
+ # elastic-opentelemetry
+ # langtrace-python-sdk
+ # opentelemetry-exporter-otlp-proto-grpc
+ # opentelemetry-exporter-otlp-proto-http
+ # opentelemetry-instrumentation
+ # opentelemetry-instrumentation-sqlalchemy
+ # opentelemetry-instrumentation-system-metrics
+ # opentelemetry-resourcedetector-gcp
+ # opentelemetry-sdk
+ # opentelemetry-semantic-conventions
+opentelemetry-exporter-otlp==1.31.0
+ # via elastic-opentelemetry
+opentelemetry-exporter-otlp-proto-common==1.31.0
+ # via
+ # opentelemetry-exporter-otlp-proto-grpc
+ # opentelemetry-exporter-otlp-proto-http
+opentelemetry-exporter-otlp-proto-grpc==1.31.0
+ # via
+ # langtrace-python-sdk
+ # opentelemetry-exporter-otlp
+opentelemetry-exporter-otlp-proto-http==1.31.0
+ # via
+ # langtrace-python-sdk
+ # opentelemetry-exporter-otlp
+opentelemetry-instrumentation==0.52b0
+ # via
+ # elastic-opentelemetry
+ # langtrace-python-sdk
+ # opentelemetry-instrumentation-sqlalchemy
+ # opentelemetry-instrumentation-system-metrics
+opentelemetry-instrumentation-sqlalchemy==0.52b0
+ # via langtrace-python-sdk
+opentelemetry-instrumentation-system-metrics==0.52b0
+ # via elastic-opentelemetry
+opentelemetry-proto==1.31.0
+ # via
+ # opentelemetry-exporter-otlp-proto-common
+ # opentelemetry-exporter-otlp-proto-grpc
+ # opentelemetry-exporter-otlp-proto-http
+opentelemetry-resource-detector-azure==0.1.5
+ # via elastic-opentelemetry
+opentelemetry-resourcedetector-gcp==1.8.0a0
+ # via elastic-opentelemetry
+opentelemetry-sdk==1.31.0
+ # via
+ # elastic-opentelemetry
+ # langtrace-python-sdk
+ # opentelemetry-exporter-otlp-proto-grpc
+ # opentelemetry-exporter-otlp-proto-http
+ # opentelemetry-resource-detector-azure
+ # opentelemetry-resourcedetector-gcp
+ # opentelemetry-sdk-extension-aws
+opentelemetry-sdk-extension-aws==2.1.0
+ # via elastic-opentelemetry
+opentelemetry-semantic-conventions==0.52b0
+ # via
+ # elastic-opentelemetry
+ # opentelemetry-instrumentation
+ # opentelemetry-instrumentation-sqlalchemy
+ # opentelemetry-sdk
+orjson==3.10.15
+ # via langsmith
+packaging==24.2
+ # via
+ # elastic-opentelemetry
+ # google-cloud-aiplatform
+ # google-cloud-bigquery
+ # huggingface-hub
+ # langchain-core
+ # langsmith
+ # marshmallow
+ # opentelemetry-instrumentation
+ # opentelemetry-instrumentation-sqlalchemy
+ # transformers
+propcache==0.3.0
+ # via
+ # aiohttp
+ # yarl
+proto-plus==1.26.1
+ # via
+ # google-api-core
+ # google-cloud-aiplatform
+ # google-cloud-resource-manager
+protobuf==5.29.3
+ # via
+ # google-api-core
+ # google-cloud-aiplatform
+ # google-cloud-resource-manager
+ # googleapis-common-protos
+ # grpc-google-iam-v1
+ # grpcio-status
+ # opentelemetry-proto
+ # proto-plus
+psutil==7.0.0
+ # via opentelemetry-instrumentation-system-metrics
+pyasn1==0.6.1
+ # via
+ # pyasn1-modules
+ # rsa
+pyasn1-modules==0.4.1
+ # via google-auth
+pydantic==2.10.6
+ # via
+ # cohere
+ # google-cloud-aiplatform
+ # langchain
+ # langchain-aws
+ # langchain-cohere
+ # langchain-core
+ # langchain-google-vertexai
+ # langchain-mistralai
+ # langsmith
+ # openai
+ # pydantic-settings
+ # trace-attributes
+pydantic-core==2.27.2
+ # via
+ # cohere
+ # pydantic
+pydantic-settings==2.8.1
+ # via langchain-community
+python-dateutil==2.9.0.post0
+ # via
+ # botocore
+ # google-cloud-bigquery
+python-dotenv==1.0.1
+ # via pydantic-settings
+pyyaml==6.0.2
+ # via
+ # huggingface-hub
+ # langchain
+ # langchain-community
+ # langchain-core
+ # transformers
+regex==2024.11.6
+ # via
+ # tiktoken
+ # transformers
+requests==2.32.3
+ # via
+ # cohere
+ # google-api-core
+ # google-cloud-bigquery
+ # google-cloud-storage
+ # huggingface-hub
+ # langchain
+ # langchain-community
+ # langsmith
+ # opentelemetry-exporter-otlp-proto-http
+ # opentelemetry-resourcedetector-gcp
+ # requests-toolbelt
+ # tiktoken
+ # transformers
+requests-toolbelt==1.0.0
+ # via langsmith
+rsa==4.9
+ # via google-auth
+s3transfer==0.11.4
+ # via boto3
+safetensors==0.5.3
+ # via transformers
+sentry-sdk==2.23.1
+ # via langtrace-python-sdk
+shapely==2.0.7
+ # via google-cloud-aiplatform
+simsimd==6.2.1
+ # via elasticsearch
+six==1.17.0
+ # via
+ # halo
+ # python-dateutil
+sniffio==1.3.1
+ # via
+ # anyio
+ # openai
+spinners==0.0.24
+ # via halo
+sqlalchemy==2.0.39
+ # via
+ # langchain
+ # langchain-community
+ # langtrace-python-sdk
+tenacity==9.0.0
+ # via
+ # langchain-community
+ # langchain-core
+termcolor==2.5.0
+ # via halo
+tiktoken==0.9.0
+ # via
+ # -r requirements.in
+ # langchain-openai
+ # langtrace-python-sdk
+tokenizers==0.21.1
+ # via
+ # cohere
+ # langchain-mistralai
+ # transformers
+tqdm==4.67.1
+ # via
+ # huggingface-hub
+ # openai
+ # transformers
+trace-attributes==7.2.0
+ # via langtrace-python-sdk
+transformers==4.49.0
+ # via langtrace-python-sdk
+types-pyyaml==6.0.12.20241230
+ # via langchain-cohere
+types-requests==2.32.0.20250306
+ # via cohere
+typing-extensions==4.12.2
+ # via
+ # anyio
+ # cohere
+ # google-cloud-aiplatform
+ # huggingface-hub
+ # langchain-core
+ # openai
+ # opentelemetry-resourcedetector-gcp
+ # opentelemetry-sdk
+ # pydantic
+ # pydantic-core
+ # sqlalchemy
+ # typing-inspect
+typing-inspect==0.9.0
+ # via dataclasses-json
+ujson==5.10.0
+ # via langtrace-python-sdk
+urllib3==2.3.0
+ # via
+ # botocore
+ # elastic-transport
+ # requests
+ # sentry-sdk
+ # types-requests
+werkzeug==3.1.3
+ # via
+ # flask
+ # flask-cors
+wrapt==1.17.2
+ # via
+ # deprecated
+ # opentelemetry-instrumentation
+ # opentelemetry-instrumentation-sqlalchemy
+yarl==1.18.3
+ # via aiohttp
+zipp==3.21.0
+ # via importlib-metadata
+zstandard==0.23.0
+ # via langsmith
+
+# The following packages are considered to be unsafe in a requirements file:
+# setuptools
+opentelemetry-instrumentation-asyncio==0.52b0
+opentelemetry-instrumentation-dbapi==0.52b0
+opentelemetry-instrumentation-logging==0.52b0
+opentelemetry-instrumentation-sqlite3==0.52b0
+opentelemetry-instrumentation-threading==0.52b0
+opentelemetry-instrumentation-urllib==0.52b0
+opentelemetry-instrumentation-wsgi==0.52b0
+opentelemetry-instrumentation-aiohttp-client==0.52b0
+opentelemetry-instrumentation-aiohttp-server==0.52b0
+opentelemetry-instrumentation-boto3sqs==0.52b0
+opentelemetry-instrumentation-botocore==0.52b0
+opentelemetry-instrumentation-click==0.52b0
+opentelemetry-instrumentation-elasticsearch==0.52b0
+opentelemetry-instrumentation-flask==0.52b0
+opentelemetry-instrumentation-grpc==0.52b0
+opentelemetry-instrumentation-httpx==0.52b0
+opentelemetry-instrumentation-jinja2==0.52b0
+opentelemetry-instrumentation-requests==0.52b0
+opentelemetry-instrumentation-sqlalchemy==0.52b0
+opentelemetry-instrumentation-system-metrics==0.52b0
+opentelemetry-instrumentation-tortoiseorm==0.52b0
+opentelemetry-instrumentation-urllib3==0.52b0
+elastic-opentelemetry-instrumentation-openai==0.6.1
+
+galileo
+langgraph
\ No newline at end of file