feat(rnd): add FastAPI support to existing project outline (#7165)
### Background ###### Project Outline Currently, the project mainly consists of these components: *agent_api* A component that will expose API endpoints for the creation & execution of agents. This component will make connections to the database to persist and read the agents. It will also trigger the agent execution by pushing its execution request to the ExecutionQueue. *agent_executor* A component that will execute the agents. This component will be a pool of processes/threads that will consume the ExecutionQueue and execute the agent accordingly. The result and progress of its execution will be persisted in the database. ###### How to test Execute `poetry run app`. Access the swagger page `http://localhost:8000/docs`, there is one API to trigger an execution of one dummy slow task, you fire the API a couple of times and see the `agent_executor` executes the multiple slow tasks concurrently by the pool of Python processes. The pool size is currently set to `5` (hardcoded in app.py, the code entry point). ##### Changes 🏗️ * Initialize FastAPI for the AutoGPT server project. * Reduced number of queues to 1 and abstracted into `ExecutionQueue` class. * Reduced the number of main components into two `api` and `executor`.pull/7168/head
parent
4e76768bc9
commit
7a932cdf00
|
@ -0,0 +1,20 @@
|
|||
# Next Gen AutoGPT
|
||||
|
||||
This is a research project into creating the next generation of autogpt, which is an autogpt agent server.
|
||||
|
||||
The agent server will enable the creation of composite multi-agent system that utilize AutoGPT Agent as its default agent.
|
||||
|
||||
|
||||
## Project Outline
|
||||
|
||||
Currently the project mainly consist of these components:
|
||||
|
||||
*agent_api*
|
||||
A component that will expose API endpoints for the creation & execution of agents.
|
||||
This component will make connections to the database to persist and read the agents.
|
||||
It will also trigger the agent execution by pushing its execution request to the ExecutionQueue.
|
||||
|
||||
*agent_executor*
|
||||
A component that will execute the agents.
|
||||
This component will be a pool of processes/threads that will consume the ExecutionQueue and execute the agent accordingly.
|
||||
The result and progress of its execution will be persisted in the database.
|
|
@ -0,0 +1 @@
|
|||
from .server import start_server # noqa
|
|
@ -0,0 +1,39 @@
|
|||
import uvicorn
|
||||
from fastapi import FastAPI, APIRouter
|
||||
|
||||
from autogpt_server.data import ExecutionQueue
|
||||
|
||||
|
||||
class AgentServer:
|
||||
|
||||
def __init__(self, queue: ExecutionQueue):
|
||||
self.app = FastAPI(
|
||||
title="AutoGPT Agent Server",
|
||||
description=(
|
||||
"This server is used to execute agents that are created by the "
|
||||
"AutoGPT system."
|
||||
),
|
||||
summary="AutoGPT Agent Server",
|
||||
version="0.1",
|
||||
)
|
||||
self.execution_queue = queue
|
||||
|
||||
# Define the API routes
|
||||
self.router = APIRouter()
|
||||
self.router.add_api_route(
|
||||
path="/agents/{agent_id}/execute",
|
||||
endpoint=self.execute_agent,
|
||||
methods=["POST"],
|
||||
)
|
||||
self.app.include_router(self.router)
|
||||
|
||||
def execute_agent(self, agent_id: str):
|
||||
execution_id = self.execution_queue.add(agent_id)
|
||||
return {"execution_id": execution_id, "agent_id": agent_id}
|
||||
|
||||
|
||||
def start_server(queue: ExecutionQueue, use_uvicorn: bool = True):
|
||||
app = AgentServer(queue).app
|
||||
if use_uvicorn:
|
||||
uvicorn.run(app)
|
||||
return app
|
|
@ -0,0 +1 @@
|
|||
from .executor import start_executors # noqa
|
|
@ -0,0 +1,42 @@
|
|||
import logging
|
||||
import time
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from multiprocessing import Process
|
||||
|
||||
from autogpt_server.data import ExecutionQueue
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AgentExecutor:
|
||||
# TODO: Replace this by an actual Agent Execution.
|
||||
def __execute(id: str, data: str) -> None:
|
||||
logger.warning(f"Executor processing started, execution_id: {id}, data: {data}")
|
||||
for i in range(5):
|
||||
logger.warning(
|
||||
f"Executor processing step {i}, execution_id: {id}, data: {data}"
|
||||
)
|
||||
time.sleep(1)
|
||||
logger.warning(
|
||||
f"Executor processing completed, execution_id: {id}, data: {data}"
|
||||
)
|
||||
|
||||
def start_executor(pool_size: int, queue: ExecutionQueue) -> None:
|
||||
with ThreadPoolExecutor(max_workers=pool_size) as executor:
|
||||
while True:
|
||||
execution = queue.get()
|
||||
if not execution:
|
||||
time.sleep(1)
|
||||
continue
|
||||
executor.submit(
|
||||
AgentExecutor.__execute,
|
||||
execution.execution_id,
|
||||
execution.data,
|
||||
)
|
||||
|
||||
|
||||
def start_executors(pool_size: int, queue: ExecutionQueue) -> None:
|
||||
executor_process = Process(
|
||||
target=AgentExecutor.start_executor, args=(pool_size, queue)
|
||||
)
|
||||
executor_process.start()
|
|
@ -0,0 +1,13 @@
|
|||
from autogpt_server.agent_api import start_server
|
||||
from autogpt_server.agent_executor import start_executors
|
||||
from autogpt_server.data import ExecutionQueue
|
||||
|
||||
|
||||
def main() -> None:
|
||||
queue = ExecutionQueue()
|
||||
start_executors(5, queue)
|
||||
start_server(queue)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,36 @@
|
|||
import uuid
|
||||
from multiprocessing import Queue
|
||||
|
||||
|
||||
class Execution:
|
||||
"""Data model for an execution of an Agent"""
|
||||
|
||||
def __init__(self, execution_id: str, data: str):
|
||||
self.execution_id = execution_id
|
||||
self.data = data
|
||||
|
||||
|
||||
# TODO: This shared class make api & executor coupled in one machine.
|
||||
# Replace this with a persistent & remote-hosted queue.
|
||||
# One very likely candidate would be persisted Redis (Redis Queue).
|
||||
# It will also open the possibility of using it for other purposes like
|
||||
# caching, execution engine broker (like Celery), user session management etc.
|
||||
class ExecutionQueue:
|
||||
"""
|
||||
Queue for managing the execution of agents.
|
||||
This will be shared between different processes
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.queue = Queue()
|
||||
|
||||
def add(self, data: str) -> str:
|
||||
execution_id = uuid.uuid4()
|
||||
self.queue.put(Execution(str(execution_id), data))
|
||||
return str(execution_id)
|
||||
|
||||
def get(self) -> Execution | None:
|
||||
return self.queue.get()
|
||||
|
||||
def empty(self) -> bool:
|
||||
return self.queue.empty()
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
|||
[tool.poetry]
|
||||
name = "rnd"
|
||||
name = "autogpt_server"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["SwiftyOS <craigswift13@gmail.com>"]
|
||||
|
@ -9,8 +9,14 @@ readme = "README.md"
|
|||
python = "^3.10"
|
||||
click = "^8.1.7"
|
||||
pydantic = "^2.7.1"
|
||||
pytest = "^8.2.1"
|
||||
uvicorn = "^0.30.1"
|
||||
fastapi = "^0.111.0"
|
||||
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
app = "autogpt_server.app:main"
|
|
@ -0,0 +1,30 @@
|
|||
import pytest
|
||||
|
||||
from autogpt_server.data import ExecutionQueue
|
||||
from autogpt_server.agent_api import start_server
|
||||
from autogpt_server.agent_executor import start_executors
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def client():
|
||||
execution_queue = ExecutionQueue()
|
||||
start_executors(5, execution_queue)
|
||||
return TestClient(start_server(execution_queue, use_uvicorn=False))
|
||||
|
||||
|
||||
def test_execute_agent(client):
|
||||
# Assert API is working
|
||||
response = client.post("/agents/dummy_agent_1/execute")
|
||||
assert response.status_code == 200
|
||||
|
||||
# Assert response is correct
|
||||
data = response.json()
|
||||
exec_id = data["execution_id"]
|
||||
agent_id = data["agent_id"]
|
||||
assert agent_id == "dummy_agent_1"
|
||||
assert isinstance(exec_id, str)
|
||||
assert len(exec_id) == 36
|
||||
|
||||
# TODO: Add assertion that the executor is executed after some time
|
||||
# Add this when db integration is done.
|
|
@ -1,27 +0,0 @@
|
|||
# Next Gen AutoGPT
|
||||
|
||||
This is a research project into creating the next generation of autogpt, which is an autogpt agent server.
|
||||
|
||||
It will come with the AutoGPT Agent as the default agent
|
||||
|
||||
|
||||
## Project Outline
|
||||
|
||||
```
|
||||
.
|
||||
├── READEME.md
|
||||
├── nextgenautogpt
|
||||
│ ├── __init__.py
|
||||
│ ├── __main__.py
|
||||
│ ├── cli.py # The CLI tool for running the system
|
||||
│ ├── executor # The Component Executor Process
|
||||
│ │ └── __init__.py
|
||||
│ ├── manager # The Agent Manager it manages a pool of executors and schedules components to run
|
||||
│ │ └── __init__.py
|
||||
│ └── server # The main application. It includes the api server and additional modules
|
||||
│ └── __init__.py
|
||||
└── pyproject.toml
|
||||
```
|
||||
|
||||
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
import multiprocessing as mp
|
||||
from typing import Any
|
||||
|
||||
import nextgenautogpt.manager.manager as mod_manager
|
||||
import nextgenautogpt.server.server as mod_server
|
||||
|
||||
|
||||
def main() -> None:
|
||||
# Create queues/pipes for communication
|
||||
server_to_manager: mp.Queue[Any] = mp.Queue()
|
||||
manager_to_server: mp.Queue[Any] = mp.Queue()
|
||||
|
||||
# Create and start server process
|
||||
server: mp.Process = mp.Process(
|
||||
target=mod_server.run_server,
|
||||
args=(
|
||||
server_to_manager,
|
||||
manager_to_server,
|
||||
),
|
||||
)
|
||||
server.start()
|
||||
|
||||
# Create and start manager process
|
||||
manager: mp.Process = mp.Process(
|
||||
target=mod_manager.run_manager,
|
||||
args=(
|
||||
server_to_manager,
|
||||
manager_to_server,
|
||||
),
|
||||
)
|
||||
manager.start()
|
||||
|
||||
server.join()
|
||||
manager.join()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
mp.set_start_method("spawn")
|
||||
main()
|
|
@ -1,15 +0,0 @@
|
|||
import multiprocessing as mp
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
|
||||
def run_executor(manager_to_executor: mp.Queue, executors_to_manager: mp.Queue) -> None:
|
||||
# Each executor process will run this initializer
|
||||
print("Executor process started")
|
||||
while True:
|
||||
if not manager_to_executor.empty():
|
||||
task = manager_to_executor.get()
|
||||
print(f"Executor processing: {task}")
|
||||
executors_to_manager.put("Task completed")
|
||||
# Simulate executor work
|
||||
time.sleep(1)
|
|
@ -1,33 +0,0 @@
|
|||
import multiprocessing as mp
|
||||
import time
|
||||
|
||||
import nextgenautogpt.executor.executor as mod_executor
|
||||
|
||||
|
||||
def run_manager(server_to_manager: mp.Queue, manager_to_server: mp.Queue) -> None:
|
||||
# Create queue for communication between manager and executors
|
||||
print("Manager process started")
|
||||
manager_to_executor = mp.Queue()
|
||||
executors_to_manager = mp.Queue()
|
||||
# Create and start a pool of executor processes
|
||||
with mp.Pool(
|
||||
processes=5,
|
||||
initializer=mod_executor.run_executor,
|
||||
initargs=(
|
||||
manager_to_executor,
|
||||
executors_to_manager,
|
||||
),
|
||||
):
|
||||
while True:
|
||||
if not server_to_manager.empty():
|
||||
message = server_to_manager.get()
|
||||
print(f"Manager received: {message}")
|
||||
manager_to_server.put("Manager: Received message from server")
|
||||
manager_to_executor.put("Task for executor")
|
||||
# Simulate manager work
|
||||
time.sleep(1)
|
||||
if not executors_to_manager.empty():
|
||||
message = executors_to_manager.get()
|
||||
print(f"Manager received: {message}")
|
||||
# Simulate manager work
|
||||
time.sleep(1)
|
|
@ -1,17 +0,0 @@
|
|||
import multiprocessing as mp
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
|
||||
def run_server(server_to_manager: mp.Queue, manager_to_server: mp.Queue) -> None:
|
||||
print("Server process started")
|
||||
while True:
|
||||
message = "Message from server"
|
||||
server_to_manager.put(message)
|
||||
# Simulate server work
|
||||
time.sleep(1)
|
||||
if not manager_to_server.empty():
|
||||
message = manager_to_server.get()
|
||||
print(f"Server received: {message}")
|
||||
# Simulate server work
|
||||
time.sleep(1)
|
|
@ -1,163 +0,0 @@
|
|||
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "annotated-types"
|
||||
version = "0.7.0"
|
||||
description = "Reusable constraint types to use with typing.Annotated"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
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 = "click"
|
||||
version = "8.1.7"
|
||||
description = "Composable command line interface toolkit"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
|
||||
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
|
||||
]
|
||||
|
||||
[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"
|
||||
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 = "pydantic"
|
||||
version = "2.7.1"
|
||||
description = "Data validation using Python type hints"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pydantic-2.7.1-py3-none-any.whl", hash = "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5"},
|
||||
{file = "pydantic-2.7.1.tar.gz", hash = "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
annotated-types = ">=0.4.0"
|
||||
pydantic-core = "2.18.2"
|
||||
typing-extensions = ">=4.6.1"
|
||||
|
||||
[package.extras]
|
||||
email = ["email-validator (>=2.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
version = "2.18.2"
|
||||
description = "Core functionality for Pydantic validation and serialization"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38"},
|
||||
{file = "pydantic_core-2.18.2-cp310-none-win32.whl", hash = "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027"},
|
||||
{file = "pydantic_core-2.18.2-cp310-none-win_amd64.whl", hash = "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664"},
|
||||
{file = "pydantic_core-2.18.2-cp311-none-win32.whl", hash = "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e"},
|
||||
{file = "pydantic_core-2.18.2-cp311-none-win_amd64.whl", hash = "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3"},
|
||||
{file = "pydantic_core-2.18.2-cp311-none-win_arm64.whl", hash = "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3"},
|
||||
{file = "pydantic_core-2.18.2-cp312-none-win32.whl", hash = "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038"},
|
||||
{file = "pydantic_core-2.18.2-cp312-none-win_amd64.whl", hash = "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438"},
|
||||
{file = "pydantic_core-2.18.2-cp312-none-win_arm64.whl", hash = "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788"},
|
||||
{file = "pydantic_core-2.18.2-cp38-none-win32.whl", hash = "sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350"},
|
||||
{file = "pydantic_core-2.18.2-cp38-none-win_amd64.whl", hash = "sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b"},
|
||||
{file = "pydantic_core-2.18.2-cp39-none-win32.whl", hash = "sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e"},
|
||||
{file = "pydantic_core-2.18.2-cp39-none-win_amd64.whl", hash = "sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374"},
|
||||
{file = "pydantic_core-2.18.2.tar.gz", hash = "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.11.0"
|
||||
description = "Backported and Experimental Type Hints for Python 3.8+"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"},
|
||||
{file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"},
|
||||
]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "37f738f9702fe6c311bc32b3ccbd182c35a6a612c5866def9e8fc14dfbf058a5"
|
Loading…
Reference in New Issue