diff --git a/.github/workflows/run_coverage.yml b/.github/workflows/run_coverage.yml index a0cf695..eb265a2 100644 --- a/.github/workflows/run_coverage.yml +++ b/.github/workflows/run_coverage.yml @@ -36,6 +36,9 @@ jobs: poetry install poetry run coverage run -m pytest poetry run coverage report --format=markdown > coverage.md + echo -e "\n---\n# Docstring Coverage\n\`\`\`" >> coverage.md + poetry run interrogate -v honcho >> coverage.md + echo -e "\`\`\`" >> coverage.md cd .. - name: Add Coverage PR Comment uses: marocchino/sticky-pull-request-comment@v2 diff --git a/.gitignore b/.gitignore index d8fa784..558b175 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ api/**/*.db - +api/data +api/docker-compose.yml # Byte-compiled / optimized / DLL files diff --git a/README.md b/README.md index 0845a28..0c020cd 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,30 @@ -# Honcho -![Static Badge](https://img.shields.io/badge/Version-0.0.5-blue) +# 🫡 Honcho +![Static Badge](https://img.shields.io/badge/Version-0.0.6-blue) [![Discord](https://img.shields.io/discord/1016845111637839922?style=flat&logo=discord&logoColor=23ffffff&label=Plastic%20Labs&labelColor=235865F2)](https://discord.gg/plasticlabs) ![GitHub License](https://img.shields.io/github/license/plastic-labs/honcho) ![GitHub Repo stars](https://img.shields.io/github/stars/plastic-labs/honcho) [![X (formerly Twitter) URL](https://img.shields.io/twitter/url?url=https%3A%2F%2Ftwitter.com%2Fplastic_labs)](https://twitter.com/plastic_labs) -A User context management solution for building AI Agents and LLM powered -applications. +Honcho is a platform for making AI agents and LLM powered applications that are personalized +to their end users. Read about the motivation of this project [here](https://blog.plasticlabs.ai). Read the user documenation [here](https://docs.honcho.dev) +## Table of Contents + +- [Project Structure](#project-structure) +- [Usage](#usage) + - [API](#api) + - [Docker](#docker) + - [Manually](#manually) + - [Deploying on Fly.io](#deploy-on-fly) + - [Client SDK](#client-sdk) + - [Use Locally](#use-locally) +- [Contributing](#contributing) +- [License](#license) + ## Project Structure The Honcho repo is a monorepo containing the server/API that manages database @@ -35,6 +48,19 @@ directories. ### API +#### Docker + +The API can be run using docker-compose. The `docker-compose.yml.example` file can be copied to `docker-compose.yml` and the environment variables can be set in the `.env` file. + +```bash +cd honcho/api +cp docker-compose.yml.example docker-compose.yml +[ update the file with openai key and other wanted environment variables ] +docker compose up -d +``` + +#### Manually + The API can be run either by installing the necessary dependencies and then specifying the appropriate environment variables. @@ -48,7 +74,7 @@ poetry install # install dependencies 2. Copy the `.env.template` file and specify the type of database and connection_uri. For testing sqlite is fine. The below example uses an - in-memory sqlite database. + in-memory sqlite database. > Honcho has been tested with Postgresql and PGVector @@ -72,26 +98,11 @@ poetry shell # Activate virtual environment if not already enabled python -m uvicorn src.main:app --reload ``` -#### Docker - -Alternatively there is also a `Dockerfile` included to run the API server from a -docker container. - -The `.env` file is not loaded into the docker container and should still be -configured from outside. - -```bash -cd honcho/api -docker build -t honcho-api . -docker run --env-file .env -p 8000:8000 honcho-api:latest -``` - #### Deploy on Fly The API can also be deployed on fly.io. Follow the [Fly.io Docs](https://fly.io/docs/getting-started/) to setup your environment and the -`flyctl`. - +`flyctl`. Once `flyctl` is set up use the following commands to launch the application: @@ -116,7 +127,10 @@ alternatively if you are using poetry run: poetry add honcho-ai ``` -checkout the [example folder](./example/) for examples of how to use the sdk +checkout the [SDK Reference](https://api.python.honcho.dev) for a detailed +look at the different methods and how to use them. + +Also, check out the[example folder](./example/) for examples of how to use the sdk #### Use Locally @@ -134,12 +148,12 @@ See more information [here](https://python-poetry.org/docs/cli/#add) This project is completely open source and welcomes any and all open source contributions. The workflow for contributing is to make a fork of the repository. You can claim an issue in the issues tab or start a new thread to -indicate a feature or bug fix you are working on. +indicate a feature or bug fix you are working on. Once you have finished your contribution make a PR pointed at the `staging` branch, and it will be reviewed by a project manager. Feel free to join us in our [discord](http://discord.gg/plasticlabs) to discuss your changes or get -help. +help. Once your changes are accepted and merged into staging they will undergo a period of live testing before entering the upstream into `main` diff --git a/api/CHANGELOG.md b/api/CHANGELOG.md index 2385bc2..aa75c81 100644 --- a/api/CHANGELOG.md +++ b/api/CHANGELOG.md @@ -4,6 +4,23 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [0.0.6] — 2024-03-21 + +### Added + +* Full docker-compose for API and Database + +### Fixed + +* API Response schema removed unnecessary fields +* OTEL logging to properly work with async database engine +* `fly.toml` default settings for deriver set `auto_stop=false` + +### Changed + +* Refactored API server into multiple route files + + ## [0.0.5] — 2024-03-14 ### Added diff --git a/api/docker-compose.yml.example b/api/docker-compose.yml.example new file mode 100644 index 0000000..5be0752 --- /dev/null +++ b/api/docker-compose.yml.example @@ -0,0 +1,41 @@ +version: "3.8" +services: + api: + build: + context: . + dockerfile: Dockerfile + ports: + - 8000:8000 + volumes: + - .:/app + environment: + - DATABASE_TYPE=postgres + - CONNECTION_URI=postgresql+psycopg://testuser:testpwd@database:5432/honcho + - OPENAI_API_KEY=[YOUR_OPENAI_API_KEY] + - OPENTELEMETRY_ENABLED=false + - SENTRY_ENABLED=false + - SENTRY_DSN= + - OTEL_SERVICE_NAME=honcho + - OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true + - OTEL_PYTHON_LOG_CORRELATION=true + - OTEL_PYTHON_LOG_LEVEL= + - OTEL_EXPORTER_OTLP_PROTOCOL= + - OTEL_EXPORTER_OTLP_ENDPOINT= + - OTEL_EXPORTER_OTLP_HEADERS= + - OTEL_RESOURCE_ATTRIBUTES= + - DEBUG_LOG_OTEL_TO_PROVIDER=false + - DEBUG_LOG_OTEL_TO_CONSOLE=true + database: + image: ankane/pgvector + restart: always + ports: + - 5432:5432 + environment: + - POSTGRES_DB=honcho + - POSTGRES_USER=testuser + - POSTGRES_PASSWORD=testpwd + - POSTGRES_HOST_AUTH_METHOD=trust + - PGDATA=/var/lib/postgresql/data/pgdata + volumes: + - ./local/init.sql:/docker-entrypoint-initdb.d/init.sql + - ./data:/var/lib/postgresql/data/ diff --git a/api/fly.toml b/api/fly.toml index 104eaa8..cf47e59 100644 --- a/api/fly.toml +++ b/api/fly.toml @@ -14,7 +14,17 @@ kill_timeout = "5s" [processes] api = "python -m uvicorn src.main:app --host 0.0.0.0 --port 8000" - deriver = "python -m src.harvester" + deriver = "python -m src.deriver" + +[[services]] + auto_stop_machines = false + auto_start_machines = true + min_machines_running = 1 + processes = ["deriver"] + protocol = "tcp" + [services.concurrency] + hard_limit = 250 + soft_limit = 200 [http_service] internal_port = 8000 @@ -31,4 +41,4 @@ kill_timeout = "5s" cpu_kind = "shared" cpus = 1 memory_mb = 512 - processes = ["api"] + processes = ["api", "deriver"] diff --git a/api/pyproject.toml b/api/pyproject.toml index de8f327..17c6c60 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "honcho" -version = "0.0.5" +version = "0.0.6" description = "Honcho Server" authors = ["Plastic Labs "] readme = "README.md" diff --git a/api/src/db.py b/api/src/db.py index 7da3dd2..5c431d8 100644 --- a/api/src/db.py +++ b/api/src/db.py @@ -5,7 +5,7 @@ from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine from sqlalchemy.ext.declarative import declarative_base -load_dotenv() +load_dotenv(override=True) connect_args = {} diff --git a/api/src/dependencies.py b/api/src/dependencies.py new file mode 100644 index 0000000..d328700 --- /dev/null +++ b/api/src/dependencies.py @@ -0,0 +1,15 @@ +from fastapi import Depends +from .db import SessionLocal +from sqlalchemy.ext.asyncio import AsyncSession + + +async def get_db(): + """FastAPI Dependency Generator for Database""" + db: AsyncSession = SessionLocal() + try: + yield db + finally: + await db.close() + + +db: AsyncSession = Depends(get_db) diff --git a/api/src/deriver.py b/api/src/deriver.py new file mode 100644 index 0000000..6fbb760 --- /dev/null +++ b/api/src/deriver.py @@ -0,0 +1,211 @@ +import asyncio +import os +import uuid +from typing import List + +import sentry_sdk +from dotenv import load_dotenv +from langchain_core.output_parsers import NumberedListOutputParser +from langchain_core.prompts import ( + ChatPromptTemplate, + SystemMessagePromptTemplate, + load_prompt, +) +from langchain_openai import ChatOpenAI +from realtime.connection import Socket +from sqlalchemy import select +from sqlalchemy.orm import selectinload + +from . import crud, models, schemas +from .db import SessionLocal + +load_dotenv() + +SENTRY_ENABLED = os.getenv("SENTRY_ENABLED", "False").lower() == "true" +if SENTRY_ENABLED: + sentry_sdk.init( + dsn=os.getenv("SENTRY_DSN"), + enable_tracing=True, + ) + + +SUPABASE_ID = os.getenv("SUPABASE_ID") +SUPABASE_API_KEY = os.getenv("SUPABASE_API_KEY") + +llm = ChatOpenAI(model_name="gpt-4") +output_parser = NumberedListOutputParser() + +SYSTEM_DERIVE_FACTS = load_prompt( + os.path.join(os.path.dirname(__file__), "prompts/derive_facts.yaml") +) +SYSTEM_CHECK_DUPS = load_prompt( + os.path.join(os.path.dirname(__file__), "prompts/check_dup_facts.yaml") +) + +system_check_dups: SystemMessagePromptTemplate = SystemMessagePromptTemplate( + prompt=SYSTEM_CHECK_DUPS +) + +system_derive_facts: SystemMessagePromptTemplate = SystemMessagePromptTemplate( + prompt=SYSTEM_DERIVE_FACTS +) + + +async def callback(payload): + # print(payload["record"]["is_user"]) + # print(type(payload["record"]["is_user"])) + if payload["record"]["is_user"]: # Check if the message is from a user + session_id = payload["record"]["session_id"] + message_id = payload["record"]["id"] + content = payload["record"]["content"] + + # Example of querying for a user_id based on session_id, adjust according to your schema + session: models.Session + user_id: uuid.UUID + app_id: uuid.UUID + async with SessionLocal() as db: + stmt = ( + select(models.Session) + .join(models.Session.messages) + .where(models.Message.id == message_id) + .where(models.Session.id == session_id) + .options(selectinload(models.Session.user)) + ) + result = await db.execute(stmt) + session = result.scalars().one() + user = session.user + user_id = user.id + app_id = user.app_id + collection: models.Collection + async with SessionLocal() as db: + collection = await crud.get_collection_by_name( + db, app_id, user_id, "honcho" + ) + if collection is None: + collection_create = schemas.CollectionCreate(name="honcho", metadata={}) + collection = await crud.create_collection( + db, + collection=collection_create, + app_id=app_id, + user_id=user_id, + ) + collection_id = collection.id + await process_user_message( + content, app_id, user_id, session_id, collection_id, message_id + ) + return + + +async def process_user_message( + content: str, + app_id: uuid.UUID, + user_id: uuid.UUID, + session_id: uuid.UUID, + collection_id: uuid.UUID, + message_id: uuid.UUID, +): + async with SessionLocal() as db: + messages_stmt = await crud.get_messages( + db=db, app_id=app_id, user_id=user_id, session_id=session_id, reverse=True + ) + messages_stmt = messages_stmt.limit(10) + response = await db.execute(messages_stmt) + messages = response.scalars().all() + messages = messages[::-1] + # contents = [m.content for m in messages] + # print(contents) + + facts = await derive_facts(messages, content) + print("===================") + print(f"DERIVED FACTS: {facts}") + print("===================") + new_facts = await check_dups(app_id, user_id, collection_id, facts) + + print("===================") + print(f"CHECKED FOR DUPLICATES: {new_facts}") + print("===================") + + for fact in new_facts: + create_document = schemas.DocumentCreate(content=fact) + async with SessionLocal() as db: + doc = await crud.create_document( + db, + document=create_document, + app_id=app_id, + user_id=user_id, + collection_id=collection_id, + ) + print(f"Returned Document: {doc}") + # doc = crud.create_document(content=fact) + # for fact in new_facts: + # session.create_metamessage( + # message=user_message, metamessage_type="fact", content=fact + # ) + # print(f"Created fact: {fact}") + + +async def derive_facts(chat_history, input: str) -> List[str]: + """Derive facts from the user input""" + + fact_derivation = ChatPromptTemplate.from_messages([system_derive_facts]) + chain = fact_derivation | llm + response = await chain.ainvoke( + { + "chat_history": [ + ( + "user: " + message.content + if message.is_user + else "ai: " + message.content + ) + for message in chat_history + ], + "user_input": input, + } + ) + facts = output_parser.parse(response.content) + + return facts + + +async def check_dups( + app_id: uuid.UUID, user_id: uuid.UUID, collection_id: uuid.UUID, facts: List[str] +): + """Check that we're not storing duplicate facts""" + + check_duplication = ChatPromptTemplate.from_messages([system_check_dups]) + query = " ".join(facts) + result = None + async with SessionLocal() as db: + result = await crud.query_documents( + db=db, + app_id=app_id, + user_id=user_id, + collection_id=collection_id, + query=query, + top_k=10, + ) + # result = collection.query(query=query, top_k=10) + existing_facts = [document.content for document in result] + print("===================") + print(f"Existing Facts {existing_facts}") + print("===================") + if len(existing_facts) == 0: + return facts + chain = check_duplication | llm + response = await chain.ainvoke({"existing_facts": existing_facts, "facts": facts}) + new_facts = output_parser.parse(response.content) + print("===================") + print(f"New Facts {facts}") + print("===================") + return new_facts + + +if __name__ == "__main__": + URL = f"wss://{SUPABASE_ID}.supabase.co/realtime/v1/websocket?apikey={SUPABASE_API_KEY}&vsn=1.0.0" + # URL = f"ws://127.0.0.1:54321/realtime/v1/websocket?apikey={SUPABASE_API_KEY}" # For local Supabase + s = Socket(URL) + s.connect() + + channel = s.set_channel("realtime:public:messages") + channel.join().on("INSERT", lambda payload: asyncio.create_task(callback(payload))) + s.listen() diff --git a/api/src/main.py b/api/src/main.py index e7f20b1..8d7f9d6 100644 --- a/api/src/main.py +++ b/api/src/main.py @@ -8,25 +8,14 @@ import sentry_sdk from fastapi import ( APIRouter, - Depends, FastAPI, - HTTPException, - Request, ) from fastapi.responses import PlainTextResponse -from fastapi_pagination import Page, add_pagination -from fastapi_pagination.ext.sqlalchemy import paginate +from fastapi_pagination import add_pagination from opentelemetry import trace from opentelemetry._logs import ( - SeverityNumber, - get_logger, - get_logger_provider, set_logger_provider, - std_to_otel, ) - -# from opentelemetry.exporter.otlp.proto.grpc._log_exporter import OTLPLogExporter -# from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter from opentelemetry.exporter.otlp.proto.http._log_exporter import ( OTLPLogExporter, ) @@ -53,12 +42,19 @@ from slowapi.errors import RateLimitExceeded from slowapi.middleware import SlowAPIMiddleware from slowapi.util import get_remote_address -from sqlalchemy.ext.asyncio import AsyncSession -from sqlalchemy.orm import Session from starlette.exceptions import HTTPException as StarletteHTTPException -from . import agent, crud, schemas -from .db import SessionLocal, engine, scaffold_db +from src.routers import ( + apps, + collections, + documents, + messages, + metamessages, + sessions, + users, +) + +from .db import engine, scaffold_db # Otel Setup @@ -99,11 +95,11 @@ def otel_trace_init(): otlp_span_exporter = OTLPSpanExporter( endpoint=otel_endpoint_url, headers=otel_http_headers ) - trace.get_tracer_provider().add_span_processor( + trace.get_tracer_provider().add_span_processor( # type: ignore BatchSpanProcessor(otlp_span_exporter) ) if DEBUG_LOG_OTEL_TO_CONSOLE: - trace.get_tracer_provider().add_span_processor( + trace.get_tracer_provider().add_span_processor( # type: ignore SimpleSpanProcessor(ConsoleSpanExporter()) ) @@ -178,7 +174,8 @@ def otel_logging_init(): otel_trace_init() otel_logging_init() - SQLAlchemyInstrumentor().instrument(engine=engine) + SQLAlchemyInstrumentor().instrument(engine=engine.sync_engine) + # Sentry Setup @@ -220,15 +217,6 @@ async def lifespan(app: FastAPI): add_pagination(app) -async def get_db(): - """FastAPI Dependency Generator for Database""" - db: AsyncSession = SessionLocal() - try: - yield db - finally: - await db.close() - - @app.exception_handler(StarletteHTTPException) async def http_exception_handler(request, exc): current_span = trace.get_current_span() @@ -245,1033 +233,10 @@ async def http_exception_handler(request, exc): ) -######################################################## -# App Routes -######################################################## -@app.get("/apps/{app_id}", response_model=schemas.App) -async def get_app( - request: Request, - app_id: uuid.UUID, - db: AsyncSession = Depends(get_db), -): - """Get an App by ID - - Args: - app_id (uuid.UUID): The ID of the app - - Returns: - schemas.App: App object - - """ - app = await crud.get_app(db, app_id=app_id) - if app is None: - raise HTTPException(status_code=404, detail="App not found") - return app - - -@app.get("/apps/name/{name}", response_model=schemas.App) -async def get_app_by_name( - request: Request, - name: str, - db: AsyncSession = Depends(get_db), -): - """Get an App by Name - - Args: - app_name (str): The name of the app - - Returns: - schemas.App: App object - - """ - app = await crud.get_app_by_name(db, name=name) - if app is None: - raise HTTPException(status_code=404, detail="App not found") - return app - - -@app.post("/apps", response_model=schemas.App) -async def create_app( - request: Request, - app: schemas.AppCreate, - db: AsyncSession = Depends(get_db), -): - """Create an App - - Args: - app (schemas.AppCreate): The App object containing any metadata - - Returns: - schemas.App: Created App object - - """ - - return await crud.create_app(db, app=app) - - -@app.get("/apps/get_or_create/{name}", response_model=schemas.App) -async def get_or_create_app( - request: Request, - name: str, - db: AsyncSession = Depends(get_db), -): - """Get or Create an App - - Args: - app_name (str): The name of the app - - Returns: - schemas.App: App object - - """ - app = await crud.get_app_by_name(db, name=name) - if app is None: - app = await crud.create_app(db, app=schemas.AppCreate(name=name)) - return app - - -@app.put("/apps/{app_id}", response_model=schemas.App) -async def update_app( - request: Request, - app_id: uuid.UUID, - app: schemas.AppUpdate, - db: AsyncSession = Depends(get_db), -): - """Update an App - - Args: - app_id (uuid.UUID): The ID of the app to update - app (schemas.AppUpdate): The App object containing any new metadata - - Returns: - schemas.App: The App object of the updated App - - """ - honcho_app = await crud.update_app(db, app_id=app_id, app=app) - if honcho_app is None: - raise HTTPException(status_code=404, detail="App not found") - return honcho_app - - -######################################################## -# User Routes -######################################################## - - -@app.post("/apps/{app_id}/users", response_model=schemas.User) -async def create_user( - request: Request, - app_id: uuid.UUID, - user: schemas.UserCreate, - db: AsyncSession = Depends(get_db), -): - """Create a User - - Args: - app_id (uuid.UUID): The ID of the app representing the client application using - honcho - user (schemas.UserCreate): The User object containing any metadata - - Returns: - schemas.User: Created User object - - """ - return await crud.create_user(db, app_id=app_id, user=user) - - -@app.get("/apps/{app_id}/users", response_model=Page[schemas.User]) -async def get_users( - request: Request, - app_id: uuid.UUID, - reverse: bool = False, - filter: Optional[str] = None, - db: AsyncSession = Depends(get_db), -): - """Get All Users for an App - - Args: - app_id (uuid.UUID): The ID of the app representing the client - application using honcho - - Returns: - list[schemas.User]: List of User objects - - """ - data = None - if filter is not None: - data = json.loads(filter) - - return await paginate( - db, await crud.get_users(db, app_id=app_id, reverse=reverse, filter=data) - ) - - -@app.get("/apps/{app_id}/users/{name}", response_model=schemas.User) -async def get_user_by_name( - request: Request, - app_id: uuid.UUID, - name: str, - db: AsyncSession = Depends(get_db), -): - """Get a User - - Args: - app_id (uuid.UUID): The ID of the app representing the client application using - honcho - user_id (str): The User ID representing the user, managed by the user - - Returns: - schemas.User: User object - - """ - return await crud.get_user_by_name(db, app_id=app_id, name=name) - - -@app.get("/apps/{app_id}/users/get_or_create/{name}", response_model=schemas.User) -async def get_or_create_user( - request: Request, app_id: uuid.UUID, name: str, db: AsyncSession = Depends(get_db) -): - """Get or Create a User - - Args: - app_id (uuid.UUID): The ID of the app representing the client application using - honcho - user_id (str): The User ID representing the user, managed by the user - - Returns: - schemas.User: User object - - """ - user = await crud.get_user_by_name(db, app_id=app_id, name=name) - if user is None: - user = await crud.create_user( - db, app_id=app_id, user=schemas.UserCreate(name=name) - ) - return user - - -@app.put("/apps/{app_id}/users/{user_id}", response_model=schemas.User) -async def update_user( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - user: schemas.UserUpdate, - db: AsyncSession = Depends(get_db), -): - """Update a User - - Args: - app_id (uuid.UUID): The ID of the app representing the client application using - honcho - user_id (str): The User ID representing the user, managed by the user - user (schemas.UserCreate): The User object containing any metadata - - Returns: - schemas.User: Updated User object - - """ - return await crud.update_user(db, app_id=app_id, user_id=user_id, user=user) - - -######################################################## -# Session Routes -######################################################## - - -@router.get("/sessions", response_model=Page[schemas.Session]) -async def get_sessions( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - location_id: Optional[str] = None, - is_active: Optional[bool] = False, - reverse: Optional[bool] = False, - filter: Optional[str] = None, - db: AsyncSession = Depends(get_db), -): - """Get All Sessions for a User - - Args: - app_id (uuid.UUID): The ID of the app representing the client application using - honcho - user_id (uuid.UUID): The User ID representing the user, managed by the user - location_id (str, optional): Optional Location ID representing the location of a - session - - Returns: - list[schemas.Session]: List of Session objects - - """ - - data = None - if filter is not None: - data = json.loads(filter) - - return await paginate( - db, - await crud.get_sessions( - db, - app_id=app_id, - user_id=user_id, - location_id=location_id, - reverse=reverse, - is_active=is_active, - filter=data, - ), - ) - - -@router.post("/sessions", response_model=schemas.Session) -async def create_session( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - session: schemas.SessionCreate, - db: AsyncSession = Depends(get_db), -): - """Create a Session for a User - - Args: - app_id (uuid.UUID): The ID of the app representing the client - application using honcho - user_id (uuid.UUID): The User ID representing the user, managed by the user - session (schemas.SessionCreate): The Session object containing any - metadata and a location ID - - Returns: - schemas.Session: The Session object of the new Session - - """ - value = await crud.create_session( - db, app_id=app_id, user_id=user_id, session=session - ) - return value - - -@router.put("/sessions/{session_id}", response_model=schemas.Session) -async def update_session( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - session_id: uuid.UUID, - session: schemas.SessionUpdate, - db: AsyncSession = Depends(get_db), -): - """Update the metadata of a Session - - Args: - app_id (uuid.UUID): The ID of the app representing the client application using - honcho - user_id (uuid.UUID): The User ID representing the user, managed by the user - session_id (uuid.UUID): The ID of the Session to update - session (schemas.SessionUpdate): The Session object containing any new metadata - - Returns: - schemas.Session: The Session object of the updated Session - - """ - if session.metadata is None: - raise HTTPException(status_code=400, detail="Session metadata cannot be empty") - try: - return await crud.update_session( - db, app_id=app_id, user_id=user_id, session_id=session_id, session=session - ) - except ValueError: - raise HTTPException(status_code=404, detail="Session not found") from None - - -@router.delete("/sessions/{session_id}") -async def delete_session( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - session_id: uuid.UUID, - db: AsyncSession = Depends(get_db), -): - """Delete a session by marking it as inactive - - Args: - app_id (uuid.UUID): The ID of the app representing the client application using - honcho - user_id (uuid.UUID): The User ID representing the user, managed by the user - session_id (uuid.UUID): The ID of the Session to delete - - Returns: - dict: A message indicating that the session was deleted - - Raises: - HTTPException: If the session is not found - - """ - response = await crud.delete_session( - db, app_id=app_id, user_id=user_id, session_id=session_id - ) - if response: - return {"message": "Session deleted successfully"} - else: - raise HTTPException(status_code=404, detail="Session not found") - - -@router.get("/sessions/{session_id}", response_model=schemas.Session) -async def get_session( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - session_id: uuid.UUID, - db: AsyncSession = Depends(get_db), -): - """Get a specific session for a user by ID - - Args: - app_id (uuid.UUID): The ID of the app representing the client application using - honcho - user_id (uuid.UUID): The User ID representing the user, managed by the user - session_id (uuid.UUID): The ID of the Session to retrieve - - Returns: - schemas.Session: The Session object of the requested Session - - Raises: - HTTPException: If the session is not found - """ - honcho_session = await crud.get_session( - db, app_id=app_id, session_id=session_id, user_id=user_id - ) - if honcho_session is None: - raise HTTPException(status_code=404, detail="Session not found") - return honcho_session - - -######################################################## -# Message Routes -######################################################## - - -@router.post("/sessions/{session_id}/messages", response_model=schemas.Message) -async def create_message_for_session( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - session_id: uuid.UUID, - message: schemas.MessageCreate, - db: AsyncSession = Depends(get_db), -): - """Adds a message to a session - - Args: - app_id (uuid.UUID): The ID of the app representing the client application using - honcho - user_id (str): The User ID representing the user, managed by the user - session_id (int): The ID of the Session to add the message to - message (schemas.MessageCreate): The Message object to add containing the - message content and type - - Returns: - schemas.Message: The Message object of the added message - - Raises: - HTTPException: If the session is not found - - """ - try: - return await crud.create_message( - db, message=message, app_id=app_id, user_id=user_id, session_id=session_id - ) - except ValueError: - raise HTTPException(status_code=404, detail="Session not found") from None - - -@router.get("/sessions/{session_id}/messages", response_model=Page[schemas.Message]) -async def get_messages( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - session_id: uuid.UUID, - reverse: Optional[bool] = False, - filter: Optional[str] = None, - db: AsyncSession = Depends(get_db), -): - """Get all messages for a session - - Args: - app_id (uuid.UUID): The ID of the app representing the client application using - honcho - user_id (str): The User ID representing the user, managed by the user - session_id (int): The ID of the Session to retrieve - reverse (bool): Whether to reverse the order of the messages - - Returns: - list[schemas.Message]: List of Message objects - - Raises: - HTTPException: If the session is not found - - """ - try: - data = None - if filter is not None: - data = json.loads(filter) - return await paginate( - db, - await crud.get_messages( - db, - app_id=app_id, - user_id=user_id, - session_id=session_id, - filter=data, - reverse=reverse, - ), - ) - except ValueError: - raise HTTPException(status_code=404, detail="Session not found") from None - - -@router.get( - "sessions/{session_id}/messages/{message_id}", response_model=schemas.Message -) -async def get_message( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - session_id: uuid.UUID, - message_id: uuid.UUID, - db: AsyncSession = Depends(get_db), -): - """ """ - honcho_message = await crud.get_message( - db, app_id=app_id, session_id=session_id, user_id=user_id, message_id=message_id - ) - if honcho_message is None: - raise HTTPException(status_code=404, detail="Session not found") - return honcho_message - - -@router.put( - "sessions/{session_id}/messages/{message_id}", response_model=schemas.Message -) -async def update_message( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - session_id: uuid.UUID, - message_id: uuid.UUID, - message: schemas.MessageUpdate, - db: AsyncSession = Depends(get_db), -): - """Update's the metadata of a message""" - if message.metadata is None: - raise HTTPException(status_code=400, detail="Message metadata cannot be empty") - try: - return await crud.update_message( - db, - message=message, - app_id=app_id, - user_id=user_id, - session_id=session_id, - message_id=message_id, - ) - except ValueError: - raise HTTPException(status_code=404, detail="Session not found") from None - - -######################################################## -# metamessage routes -######################################################## - - -@router.post("/sessions/{session_id}/metamessages", response_model=schemas.Metamessage) -async def create_metamessage( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - session_id: uuid.UUID, - metamessage: schemas.MetamessageCreate, - db: AsyncSession = Depends(get_db), -): - """Adds a message to a session - - Args: - app_id (uuid.UUID): The ID of the app representing the client application using - honcho - user_id (str): The User ID representing the user, managed by the user - session_id (int): The ID of the Session to add the message to - message (schemas.MessageCreate): The Message object to add containing the - message content and type - - Returns: - schemas.Message: The Message object of the added message - - Raises: - HTTPException: If the session is not found - - """ - try: - return await crud.create_metamessage( - db, - metamessage=metamessage, - app_id=app_id, - user_id=user_id, - session_id=session_id, - ) - except ValueError: - raise HTTPException(status_code=404, detail="Session not found") from None - - -@router.get( - "/sessions/{session_id}/metamessages", response_model=Page[schemas.Metamessage] -) -async def get_metamessages( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - session_id: uuid.UUID, - message_id: Optional[uuid.UUID] = None, - metamessage_type: Optional[str] = None, - reverse: Optional[bool] = False, - filter: Optional[str] = None, - db: AsyncSession = Depends(get_db), -): - """Get all messages for a session - - Args: - app_id (uuid.UUID): The ID of the app representing the client application using - honcho - user_id (str): The User ID representing the user, managed by the user - session_id (int): The ID of the Session to retrieve - reverse (bool): Whether to reverse the order of the metamessages - - Returns: - list[schemas.Message]: List of Message objects - - Raises: - HTTPException: If the session is not found - - """ - try: - data = None - if filter is not None: - data = json.loads(filter) - return await paginate( - db, - await crud.get_metamessages( - db, - app_id=app_id, - user_id=user_id, - session_id=session_id, - message_id=message_id, - metamessage_type=metamessage_type, - filter=data, - reverse=reverse, - ), - ) - except ValueError: - raise HTTPException(status_code=404, detail="Session not found") from None - - -@router.get( - "/sessions/{session_id}/metamessages/{metamessage_id}", - response_model=schemas.Metamessage, -) -async def get_metamessage( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - session_id: uuid.UUID, - message_id: uuid.UUID, - metamessage_id: uuid.UUID, - db: AsyncSession = Depends(get_db), -): - """Get a specific Metamessage by ID - - Args: - app_id (uuid.UUID): The ID of the app representing the client application using - honcho - user_id (str): The User ID representing the user, managed by the user - session_id (int): The ID of the Session to retrieve - - Returns: - schemas.Session: The Session object of the requested Session - - Raises: - HTTPException: If the session is not found - """ - honcho_metamessage = await crud.get_metamessage( - db, - app_id=app_id, - session_id=session_id, - user_id=user_id, - message_id=message_id, - metamessage_id=metamessage_id, - ) - if honcho_metamessage is None: - raise HTTPException(status_code=404, detail="Session not found") - return honcho_metamessage - - -@router.put( - "sessions/{session_id}/metamessages/{metamessage_id}", - response_model=schemas.Metamessage, -) -async def update_metamessage( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - session_id: uuid.UUID, - metamessage_id: uuid.UUID, - metamessage: schemas.MetamessageUpdate, - db: AsyncSession = Depends(get_db), -): - """Update's the metadata of a metamessage""" - if metamessage.metadata is None: - raise HTTPException( - status_code=400, detail="Metamessage metadata cannot be empty" - ) - try: - return await crud.update_metamessage( - db, - metamessage=metamessage, - app_id=app_id, - user_id=user_id, - session_id=session_id, - metamessage_id=metamessage_id, - ) - except ValueError: - raise HTTPException(status_code=404, detail="Session not found") from None - - -######################################################## -# collection routes -######################################################## - - -@router.get("/collections", response_model=Page[schemas.Collection]) -async def get_collections( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - reverse: Optional[bool] = False, - filter: Optional[str] = None, - db: AsyncSession = Depends(get_db), -): - """Get All Collections for a User - - Args: - app_id (uuid.UUID): The ID of the app representing the client - application using honcho - user_id (uuid.UUID): The User ID representing the user, managed by the user - - Returns: - list[schemas.Collection]: List of Collection objects - - """ - data = None - if filter is not None: - data = json.loads(filter) - return await paginate( - db, - await crud.get_collections( - db, app_id=app_id, user_id=user_id, filter=data, reverse=reverse - ), - ) - - -# @router.get("/collections/id/{collection_id}", response_model=schemas.Collection) -# def get_collection_by_id( -# request: Request, -# app_id: uuid.UUID, -# user_id: uuid.UUID, -# collection_id: uuid.UUID, -# db: AsyncSession = Depends(get_db), -# ) -> schemas.Collection: -# honcho_collection = crud.get_collection_by_id( -# db, app_id=app_id, user_id=user_id, collection_id=collection_id -# ) -# if honcho_collection is None: -# raise HTTPException( -# status_code=404, detail="collection not found or does not belong to user" -# ) -# return honcho_collection - - -@router.get("/collections/{name}", response_model=schemas.Collection) -async def get_collection_by_name( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - name: str, - db: AsyncSession = Depends(get_db), -) -> schemas.Collection: - honcho_collection = await crud.get_collection_by_name( - db, app_id=app_id, user_id=user_id, name=name - ) - if honcho_collection is None: - raise HTTPException( - status_code=404, detail="collection not found or does not belong to user" - ) - return honcho_collection - - -@router.post("/collections", response_model=schemas.Collection) -async def create_collection( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - collection: schemas.CollectionCreate, - db: AsyncSession = Depends(get_db), -): - if collection.name == "honcho": - raise HTTPException( - status_code=406, - detail="error invalid collection configuration - honcho is a reserved name", - ) - try: - return await crud.create_collection( - db, collection=collection, app_id=app_id, user_id=user_id - ) - except ValueError: - raise HTTPException( - status_code=406, - detail="Error invalid collection configuration - name may already exist", - ) from None - - -@router.put("/collections/{collection_id}", response_model=schemas.Collection) -async def update_collection( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - collection_id: uuid.UUID, - collection: schemas.CollectionUpdate, - db: AsyncSession = Depends(get_db), -): - if collection.name is None: - raise HTTPException( - status_code=400, detail="invalid request - name cannot be None" - ) - if collection.name == "honcho": - raise HTTPException( - status_code=406, - detail="error invalid collection configuration - honcho is a reserved name", - ) - - try: - honcho_collection = await crud.update_collection( - db, - collection=collection, - app_id=app_id, - user_id=user_id, - collection_id=collection_id, - ) - except ValueError: - raise HTTPException( - status_code=406, - detail="Error invalid collection configuration - name may already exist", - ) from None - return honcho_collection - - -@router.delete("/collections/{collection_id}") -async def delete_collection( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - collection_id: uuid.UUID, - db: AsyncSession = Depends(get_db), -): - response = await crud.delete_collection( - db, app_id=app_id, user_id=user_id, collection_id=collection_id - ) - if response: - return {"message": "Collection deleted successfully"} - else: - raise HTTPException( - status_code=404, detail="collection not found or does not belong to user" - ) - - -######################################################## -# Document routes -######################################################## - - -@router.get( - "/collections/{collection_id}/documents", response_model=Page[schemas.Document] -) -async def get_documents( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - collection_id: uuid.UUID, - reverse: Optional[bool] = False, - filter: Optional[str] = None, - db: AsyncSession = Depends(get_db), -): - try: - data = None - if filter is not None: - data = json.loads(filter) - return await paginate( - db, - await crud.get_documents( - db, - app_id=app_id, - user_id=user_id, - collection_id=collection_id, - filter=data, - reverse=reverse, - ), - ) - except ( - ValueError - ): # TODO can probably remove this exception ok to return empty here - raise HTTPException( - status_code=404, detail="collection not found or does not belong to user" - ) from None - - -router.get( - "/collections/{collection_id}/documents/{document_id}", - response_model=schemas.Document, -) - - -async def get_document( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - collection_id: uuid.UUID, - document_id: uuid.UUID, - db: AsyncSession = Depends(get_db), -): - honcho_document = await crud.get_document( - db, - app_id=app_id, - user_id=user_id, - collection_id=collection_id, - document_id=document_id, - ) - if honcho_document is None: - raise HTTPException( - status_code=404, detail="document not found or does not belong to user" - ) - return honcho_document - - -@router.get( - "/collections/{collection_id}/query", response_model=Sequence[schemas.Document] -) -async def query_documents( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - collection_id: uuid.UUID, - query: str, - top_k: int = 5, - filter: Optional[str] = None, - db: AsyncSession = Depends(get_db), -): - if top_k is not None and top_k > 50: - top_k = 50 # TODO see if we need to paginate this - data = None - if filter is not None: - data = json.loads(filter) - return await crud.query_documents( - db=db, - app_id=app_id, - user_id=user_id, - collection_id=collection_id, - query=query, - filter=data, - top_k=top_k, - ) - - -@router.post("/collections/{collection_id}/documents", response_model=schemas.Document) -async def create_document( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - collection_id: uuid.UUID, - document: schemas.DocumentCreate, - db: AsyncSession = Depends(get_db), -): - try: - return await crud.create_document( - db, - document=document, - app_id=app_id, - user_id=user_id, - collection_id=collection_id, - ) - except ValueError: - raise HTTPException( - status_code=404, detail="collection not found or does not belong to user" - ) from None - - -@router.put( - "/collections/{collection_id}/documents/{document_id}", - response_model=schemas.Document, -) -async def update_document( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - collection_id: uuid.UUID, - document_id: uuid.UUID, - document: schemas.DocumentUpdate, - db: AsyncSession = Depends(get_db), -): - if document.content is None and document.metadata is None: - raise HTTPException( - status_code=400, detail="content and metadata cannot both be None" - ) - return await crud.update_document( - db, - document=document, - app_id=app_id, - user_id=user_id, - collection_id=collection_id, - document_id=document_id, - ) - - -@router.delete("/collections/{collection_id}/documents/{document_id}") -async def delete_document( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - collection_id: uuid.UUID, - document_id: uuid.UUID, - db: AsyncSession = Depends(get_db), -): - response = await crud.delete_document( - db, - app_id=app_id, - user_id=user_id, - collection_id=collection_id, - document_id=document_id, - ) - if response: - return {"message": "Document deleted successfully"} - else: - raise HTTPException( - status_code=404, detail="document not found or does not belong to user" - ) - - -@router.get("/sessions/{session_id}/chat", response_model=schemas.AgentChat) -async def get_chat( - request: Request, - app_id: uuid.UUID, - user_id: uuid.UUID, - session_id: uuid.UUID, - query: str, - db: AsyncSession = Depends(get_db), -): - return await agent.chat( - app_id=app_id, user_id=user_id, session_id=session_id, query=query, db=db - ) - - -app.include_router(router) +app.include_router(apps.router) +app.include_router(users.router) +app.include_router(sessions.router) +app.include_router(messages.router) +app.include_router(metamessages.router) +app.include_router(collections.router) +app.include_router(documents.router) diff --git a/api/src/routers/apps.py b/api/src/routers/apps.py new file mode 100644 index 0000000..648c28b --- /dev/null +++ b/api/src/routers/apps.py @@ -0,0 +1,99 @@ +import uuid + +from fastapi import APIRouter, HTTPException, Request +from sqlalchemy.ext.asyncio import AsyncSession + +from src import crud, schemas +from src.dependencies import db + +router = APIRouter( + prefix="/apps", + tags=["apps"], +) + + +@router.get("/{app_id}", response_model=schemas.App) +async def get_app(request: Request, app_id: uuid.UUID, db=db): + """Get an App by ID + + Args: + app_id (uuid.UUID): The ID of the app + + Returns: + schemas.App: App object + + """ + app = await crud.get_app(db, app_id=app_id) + if app is None: + raise HTTPException(status_code=404, detail="App not found") + return app + + +@router.get("/name/{name}", response_model=schemas.App) +async def get_app_by_name(request: Request, name: str, db=db): + """Get an App by Name + + Args: + app_name (str): The name of the app + + Returns: + schemas.App: App object + + """ + app = await crud.get_app_by_name(db, name=name) + if app is None: + raise HTTPException(status_code=404, detail="App not found") + return app + + +@router.post("", response_model=schemas.App) +async def create_app(request: Request, app: schemas.AppCreate, db=db): + """Create an App + + Args: + app (schemas.AppCreate): The App object containing any metadata + + Returns: + schemas.App: Created App object + + """ + + return await crud.create_app(db, app=app) + + +@router.get("/get_or_create/{name}", response_model=schemas.App) +async def get_or_create_app(request: Request, name: str, db=db): + """Get or Create an App + + Args: + app_name (str): The name of the app + + Returns: + schemas.App: App object + + """ + print("name", name) + app = await crud.get_app_by_name(db, name=name) + if app is None: + app = await crud.create_app(db, app=schemas.AppCreate(name=name)) + return app + + +@router.put("/{app_id}", response_model=schemas.App) +async def update_app( + request: Request, app_id: uuid.UUID, app: schemas.AppUpdate, db=db +): + """Update an App + + Args: + app_id (uuid.UUID): The ID of the app to update + app (schemas.AppUpdate): The App object containing any new metadata + + Returns: + schemas.App: The App object of the updated App + + """ + honcho_app = await crud.update_app(db, app_id=app_id, app=app) + if honcho_app is None: + raise HTTPException(status_code=404, detail="App not found") + return honcho_app diff --git a/api/src/routers/collections.py b/api/src/routers/collections.py new file mode 100644 index 0000000..1f9e788 --- /dev/null +++ b/api/src/routers/collections.py @@ -0,0 +1,160 @@ +import json +from typing import Optional +import uuid +from fastapi import APIRouter, HTTPException, Request +from fastapi_pagination import Page +from fastapi_pagination.ext.sqlalchemy import paginate + +from src import crud, schemas +from src.dependencies import db + + +router = APIRouter( + prefix="/apps/{app_id}/users/{user_id}/collections", + tags=["collections"], +) + + +@router.get("", response_model=Page[schemas.Collection]) +async def get_collections( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + reverse: Optional[bool] = False, + filter: Optional[str] = None, + db=db, +): + """Get All Collections for a User + + Args: + app_id (uuid.UUID): The ID of the app representing the client + application using honcho + user_id (uuid.UUID): The User ID representing the user, managed by the user + + Returns: + list[schemas.Collection]: List of Collection objects + + """ + data = None + if filter is not None: + data = json.loads(filter) + return await paginate( + db, + await crud.get_collections( + db, app_id=app_id, user_id=user_id, filter=data, reverse=reverse + ), + ) + + +# @router.get("/id/{collection_id}", response_model=schemas.Collection) +# def get_collection_by_id( +# request: Request, +# app_id: uuid.UUID, +# user_id: uuid.UUID, +# collection_id: uuid.UUID, +# db=db, +# ) -> schemas.Collection: +# honcho_collection = crud.get_collection_by_id( +# db, app_id=app_id, user_id=user_id, collection_id=collection_id +# ) +# if honcho_collection is None: +# raise HTTPException( +# status_code=404, detail="collection not found or does not belong to user" +# ) +# return honcho_collection + + +@router.get("/{name}", response_model=schemas.Collection) +async def get_collection_by_name( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + name: str, + db=db, +) -> schemas.Collection: + honcho_collection = await crud.get_collection_by_name( + db, app_id=app_id, user_id=user_id, name=name + ) + if honcho_collection is None: + raise HTTPException( + status_code=404, detail="collection not found or does not belong to user" + ) + return honcho_collection + + +@router.post("", response_model=schemas.Collection) +async def create_collection( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + collection: schemas.CollectionCreate, + db=db, +): + if collection.name == "honcho": + raise HTTPException( + status_code=406, + detail="error invalid collection configuration - honcho is a reserved name", + ) + try: + return await crud.create_collection( + db, collection=collection, app_id=app_id, user_id=user_id + ) + except ValueError: + raise HTTPException( + status_code=406, + detail="Error invalid collection configuration - name may already exist", + ) from None + + +@router.put("/{collection_id}", response_model=schemas.Collection) +async def update_collection( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + collection_id: uuid.UUID, + collection: schemas.CollectionUpdate, + db=db, +): + if collection.name is None: + raise HTTPException( + status_code=400, detail="invalid request - name cannot be None" + ) + if collection.name == "honcho": + raise HTTPException( + status_code=406, + detail="error invalid collection configuration - honcho is a reserved name", + ) + + try: + honcho_collection = await crud.update_collection( + db, + collection=collection, + app_id=app_id, + user_id=user_id, + collection_id=collection_id, + ) + except ValueError: + raise HTTPException( + status_code=406, + detail="Error invalid collection configuration - name may already exist", + ) from None + return honcho_collection + + +@router.delete("/{collection_id}") +async def delete_collection( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + collection_id: uuid.UUID, + db=db, +): + response = await crud.delete_collection( + db, app_id=app_id, user_id=user_id, collection_id=collection_id + ) + if response: + return {"message": "Collection deleted successfully"} + else: + raise HTTPException( + status_code=404, detail="collection not found or does not belong to user" + ) diff --git a/api/src/routers/documents.py b/api/src/routers/documents.py new file mode 100644 index 0000000..cb2b8f7 --- /dev/null +++ b/api/src/routers/documents.py @@ -0,0 +1,175 @@ +import json +from typing import Optional, Sequence +import uuid +from fastapi import APIRouter, HTTPException, Request +from fastapi_pagination import Page +from fastapi_pagination.ext.sqlalchemy import paginate + +from src import crud, schemas +from src.dependencies import db + + +router = APIRouter( + prefix="/apps/{app_id}/users/{user_id}/collections/{collection_id}", + tags=["documents"], +) + + +@router.get("/documents", response_model=Page[schemas.Document]) +async def get_documents( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + collection_id: uuid.UUID, + reverse: Optional[bool] = False, + filter: Optional[str] = None, + db=db, +): + try: + data = None + if filter is not None: + data = json.loads(filter) + return await paginate( + db, + await crud.get_documents( + db, + app_id=app_id, + user_id=user_id, + collection_id=collection_id, + filter=data, + reverse=reverse, + ), + ) + except ( + ValueError + ): # TODO can probably remove this exception ok to return empty here + raise HTTPException( + status_code=404, detail="collection not found or does not belong to user" + ) from None + + +@router.get( + "/documents/{document_id}", + response_model=schemas.Document, +) +async def get_document( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + collection_id: uuid.UUID, + document_id: uuid.UUID, + db=db, +): + honcho_document = await crud.get_document( + db, + app_id=app_id, + user_id=user_id, + collection_id=collection_id, + document_id=document_id, + ) + if honcho_document is None: + raise HTTPException( + status_code=404, detail="document not found or does not belong to user" + ) + return honcho_document + + +@router.get("/query", response_model=Sequence[schemas.Document]) +async def query_documents( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + collection_id: uuid.UUID, + query: str, + top_k: int = 5, + filter: Optional[str] = None, + db=db, +): + if top_k is not None and top_k > 50: + top_k = 50 # TODO see if we need to paginate this + data = None + if filter is not None: + data = json.loads(filter) + return await crud.query_documents( + db=db, + app_id=app_id, + user_id=user_id, + collection_id=collection_id, + query=query, + filter=data, + top_k=top_k, + ) + + +@router.post("/documents", response_model=schemas.Document) +async def create_document( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + collection_id: uuid.UUID, + document: schemas.DocumentCreate, + db=db, +): + try: + return await crud.create_document( + db, + document=document, + app_id=app_id, + user_id=user_id, + collection_id=collection_id, + ) + except ValueError: + raise HTTPException( + status_code=404, detail="collection not found or does not belong to user" + ) from None + + +@router.put( + "/documents/{document_id}", + response_model=schemas.Document, +) +async def update_document( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + collection_id: uuid.UUID, + document_id: uuid.UUID, + document: schemas.DocumentUpdate, + db=db, +): + if document.content is None and document.metadata is None: + raise HTTPException( + status_code=400, detail="content and metadata cannot both be None" + ) + return await crud.update_document( + db, + document=document, + app_id=app_id, + user_id=user_id, + collection_id=collection_id, + document_id=document_id, + ) + + +@router.delete("/documents/{document_id}") +async def delete_document( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + collection_id: uuid.UUID, + document_id: uuid.UUID, + db=db, +): + response = await crud.delete_document( + db, + app_id=app_id, + user_id=user_id, + collection_id=collection_id, + document_id=document_id, + ) + if response: + return {"message": "Document deleted successfully"} + else: + raise HTTPException( + status_code=404, detail="document not found or does not belong to user" + ) diff --git a/api/src/routers/messages.py b/api/src/routers/messages.py new file mode 100644 index 0000000..e901dc5 --- /dev/null +++ b/api/src/routers/messages.py @@ -0,0 +1,138 @@ +import json +from typing import Optional +import uuid +from fastapi import APIRouter, HTTPException, Request +from fastapi_pagination import Page +from fastapi_pagination.ext.sqlalchemy import paginate + +from src import crud, schemas +from src.dependencies import db + + +router = APIRouter( + prefix="/apps/{app_id}/users/{user_id}/sessions/{session_id}/messages", + tags=["messages"], +) + + +@router.post("", response_model=schemas.Message) +async def create_message_for_session( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + session_id: uuid.UUID, + message: schemas.MessageCreate, + db=db, +): + """Adds a message to a session + + Args: + app_id (uuid.UUID): The ID of the app representing the client application using + honcho + user_id (str): The User ID representing the user, managed by the user + session_id (int): The ID of the Session to add the message to + message (schemas.MessageCreate): The Message object to add containing the + message content and type + + Returns: + schemas.Message: The Message object of the added message + + Raises: + HTTPException: If the session is not found + + """ + try: + return await crud.create_message( + db, message=message, app_id=app_id, user_id=user_id, session_id=session_id + ) + except ValueError: + raise HTTPException(status_code=404, detail="Session not found") from None + + +@router.get("", response_model=Page[schemas.Message]) +async def get_messages( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + session_id: uuid.UUID, + reverse: Optional[bool] = False, + filter: Optional[str] = None, + db=db, +): + """Get all messages for a session + + Args: + app_id (uuid.UUID): The ID of the app representing the client application using + honcho + user_id (str): The User ID representing the user, managed by the user + session_id (int): The ID of the Session to retrieve + reverse (bool): Whether to reverse the order of the messages + + Returns: + list[schemas.Message]: List of Message objects + + Raises: + HTTPException: If the session is not found + + """ + try: + data = None + if filter is not None: + data = json.loads(filter) + return await paginate( + db, + await crud.get_messages( + db, + app_id=app_id, + user_id=user_id, + session_id=session_id, + filter=data, + reverse=reverse, + ), + ) + except ValueError: + raise HTTPException(status_code=404, detail="Session not found") from None + + +@router.get("/{message_id}", response_model=schemas.Message) +async def get_message( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + session_id: uuid.UUID, + message_id: uuid.UUID, + db=db, +): + """ """ + honcho_message = await crud.get_message( + db, app_id=app_id, session_id=session_id, user_id=user_id, message_id=message_id + ) + if honcho_message is None: + raise HTTPException(status_code=404, detail="Session not found") + return honcho_message + + +@router.put("/{message_id}", response_model=schemas.Message) +async def update_message( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + session_id: uuid.UUID, + message_id: uuid.UUID, + message: schemas.MessageUpdate, + db=db, +): + """Update's the metadata of a message""" + if message.metadata is None: + raise HTTPException(status_code=400, detail="Message metadata cannot be empty") + try: + return await crud.update_message( + db, + message=message, + app_id=app_id, + user_id=user_id, + session_id=session_id, + message_id=message_id, + ) + except ValueError: + raise HTTPException(status_code=404, detail="Session not found") from None diff --git a/api/src/routers/metamessages.py b/api/src/routers/metamessages.py new file mode 100644 index 0000000..bf83329 --- /dev/null +++ b/api/src/routers/metamessages.py @@ -0,0 +1,173 @@ +import json +from typing import Optional +import uuid +from fastapi import APIRouter, HTTPException, Request +from fastapi_pagination import Page +from fastapi_pagination.ext.sqlalchemy import paginate + +from src import crud, schemas +from src.dependencies import db + + +router = APIRouter( + prefix="/apps/{app_id}/users/{user_id}/sessions/{session_id}/metamessages", + tags=["messages"], +) + + +@router.post("", response_model=schemas.Metamessage) +async def create_metamessage( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + session_id: uuid.UUID, + metamessage: schemas.MetamessageCreate, + db=db, +): + """Adds a message to a session + + Args: + app_id (uuid.UUID): The ID of the app representing the client application using + honcho + user_id (str): The User ID representing the user, managed by the user + session_id (int): The ID of the Session to add the message to + message (schemas.MessageCreate): The Message object to add containing the + message content and type + + Returns: + schemas.Message: The Message object of the added message + + Raises: + HTTPException: If the session is not found + + """ + try: + return await crud.create_metamessage( + db, + metamessage=metamessage, + app_id=app_id, + user_id=user_id, + session_id=session_id, + ) + except ValueError: + raise HTTPException(status_code=404, detail="Session not found") from None + + +@router.get("", response_model=Page[schemas.Metamessage]) +async def get_metamessages( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + session_id: uuid.UUID, + message_id: Optional[uuid.UUID] = None, + metamessage_type: Optional[str] = None, + reverse: Optional[bool] = False, + filter: Optional[str] = None, + db=db, +): + """Get all messages for a session + + Args: + app_id (uuid.UUID): The ID of the app representing the client application using + honcho + user_id (str): The User ID representing the user, managed by the user + session_id (int): The ID of the Session to retrieve + reverse (bool): Whether to reverse the order of the metamessages + + Returns: + list[schemas.Message]: List of Message objects + + Raises: + HTTPException: If the session is not found + + """ + try: + data = None + if filter is not None: + data = json.loads(filter) + return await paginate( + db, + await crud.get_metamessages( + db, + app_id=app_id, + user_id=user_id, + session_id=session_id, + message_id=message_id, + metamessage_type=metamessage_type, + filter=data, + reverse=reverse, + ), + ) + except ValueError: + raise HTTPException(status_code=404, detail="Session not found") from None + + +@router.get( + "/{metamessage_id}", + response_model=schemas.Metamessage, +) +async def get_metamessage( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + session_id: uuid.UUID, + message_id: uuid.UUID, + metamessage_id: uuid.UUID, + db=db, +): + """Get a specific Metamessage by ID + + Args: + app_id (uuid.UUID): The ID of the app representing the client application using + honcho + user_id (str): The User ID representing the user, managed by the user + session_id (int): The ID of the Session to retrieve + + Returns: + schemas.Session: The Session object of the requested Session + + Raises: + HTTPException: If the session is not found + """ + honcho_metamessage = await crud.get_metamessage( + db, + app_id=app_id, + session_id=session_id, + user_id=user_id, + message_id=message_id, + metamessage_id=metamessage_id, + ) + if honcho_metamessage is None: + raise HTTPException(status_code=404, detail="Session not found") + return honcho_metamessage + + +@router.put( + "/{metamessage_id}", + response_model=schemas.Metamessage, +) +async def update_metamessage( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + session_id: uuid.UUID, + metamessage_id: uuid.UUID, + metamessage: schemas.MetamessageUpdate, + db=db, +): + """Update's the metadata of a metamessage""" + if metamessage.metadata is None: + raise HTTPException( + status_code=400, detail="Metamessage metadata cannot be empty" + ) + try: + return await crud.update_metamessage( + db, + metamessage=metamessage, + app_id=app_id, + user_id=user_id, + session_id=session_id, + metamessage_id=metamessage_id, + ) + except ValueError: + raise HTTPException(status_code=404, detail="Session not found") from None diff --git a/api/src/routers/sessions.py b/api/src/routers/sessions.py new file mode 100644 index 0000000..af17e72 --- /dev/null +++ b/api/src/routers/sessions.py @@ -0,0 +1,193 @@ +import json +import uuid +from typing import Optional + +from fastapi import APIRouter, HTTPException, Request +from fastapi_pagination import Page +from fastapi_pagination.ext.sqlalchemy import paginate + +from src import agent, crud, schemas +from src.dependencies import db + +router = APIRouter( + prefix="/apps/{app_id}/users/{user_id}/sessions", + tags=["sessions"], +) + + +@router.get("", response_model=Page[schemas.Session]) +async def get_sessions( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + location_id: Optional[str] = None, + is_active: Optional[bool] = False, + reverse: Optional[bool] = False, + filter: Optional[str] = None, + db=db, +): + """Get All Sessions for a User + + Args: + app_id (uuid.UUID): The ID of the app representing the client application using + honcho + user_id (uuid.UUID): The User ID representing the user, managed by the user + location_id (str, optional): Optional Location ID representing the location of a + session + + Returns: + list[schemas.Session]: List of Session objects + + """ + + data = None + if filter is not None: + data = json.loads(filter) + + return await paginate( + db, + await crud.get_sessions( + db, + app_id=app_id, + user_id=user_id, + location_id=location_id, + reverse=reverse, + is_active=is_active, + filter=data, + ), + ) + + +@router.post("", response_model=schemas.Session) +async def create_session( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + session: schemas.SessionCreate, + db=db, +): + """Create a Session for a User + + Args: + app_id (uuid.UUID): The ID of the app representing the client + application using honcho + user_id (uuid.UUID): The User ID representing the user, managed by the user + session (schemas.SessionCreate): The Session object containing any + metadata and a location ID + + Returns: + schemas.Session: The Session object of the new Session + + """ + value = await crud.create_session( + db, app_id=app_id, user_id=user_id, session=session + ) + return value + + +@router.put("/{session_id}", response_model=schemas.Session) +async def update_session( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + session_id: uuid.UUID, + session: schemas.SessionUpdate, + db=db, +): + """Update the metadata of a Session + + Args: + app_id (uuid.UUID): The ID of the app representing the client application using + honcho + user_id (uuid.UUID): The User ID representing the user, managed by the user + session_id (uuid.UUID): The ID of the Session to update + session (schemas.SessionUpdate): The Session object containing any new metadata + + Returns: + schemas.Session: The Session object of the updated Session + + """ + if session.metadata is None: + raise HTTPException(status_code=400, detail="Session metadata cannot be empty") + try: + return await crud.update_session( + db, app_id=app_id, user_id=user_id, session_id=session_id, session=session + ) + except ValueError: + raise HTTPException(status_code=404, detail="Session not found") from None + + +@router.delete("/{session_id}") +async def delete_session( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + session_id: uuid.UUID, + db=db, +): + """Delete a session by marking it as inactive + + Args: + app_id (uuid.UUID): The ID of the app representing the client application using + honcho + user_id (uuid.UUID): The User ID representing the user, managed by the user + session_id (uuid.UUID): The ID of the Session to delete + + Returns: + dict: A message indicating that the session was deleted + + Raises: + HTTPException: If the session is not found + + """ + response = await crud.delete_session( + db, app_id=app_id, user_id=user_id, session_id=session_id + ) + if response: + return {"message": "Session deleted successfully"} + else: + raise HTTPException(status_code=404, detail="Session not found") + + +@router.get("/{session_id}", response_model=schemas.Session) +async def get_session( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + session_id: uuid.UUID, + db=db, +): + """Get a specific session for a user by ID + + Args: + app_id (uuid.UUID): The ID of the app representing the client application using + honcho + user_id (uuid.UUID): The User ID representing the user, managed by the user + session_id (uuid.UUID): The ID of the Session to retrieve + + Returns: + schemas.Session: The Session object of the requested Session + + Raises: + HTTPException: If the session is not found + """ + honcho_session = await crud.get_session( + db, app_id=app_id, session_id=session_id, user_id=user_id + ) + if honcho_session is None: + raise HTTPException(status_code=404, detail="Session not found") + return honcho_session + + +@router.get("/{session_id}/chat", response_model=schemas.AgentChat) +async def get_chat( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + session_id: uuid.UUID, + query: str, + db=db, +): + return await agent.chat( + app_id=app_id, user_id=user_id, session_id=session_id, query=query, db=db + ) diff --git a/api/src/routers/users.py b/api/src/routers/users.py new file mode 100644 index 0000000..c79c234 --- /dev/null +++ b/api/src/routers/users.py @@ -0,0 +1,128 @@ +import json +from typing import Optional +import uuid +from fastapi import APIRouter, Request +from fastapi_pagination import Page +from fastapi_pagination.ext.sqlalchemy import paginate + +from src import crud, schemas +from src.dependencies import db + +router = APIRouter( + prefix="/apps/{app_id}/users", + tags=["users"], +) + + +@router.post("", response_model=schemas.User) +async def create_user( + request: Request, + app_id: uuid.UUID, + user: schemas.UserCreate, + db=db, +): + """Create a User + + Args: + app_id (uuid.UUID): The ID of the app representing the client application using + honcho + user (schemas.UserCreate): The User object containing any metadata + + Returns: + schemas.User: Created User object + + """ + print("running create_user") + return await crud.create_user(db, app_id=app_id, user=user) + + +@router.get("", response_model=Page[schemas.User]) +async def get_users( + request: Request, + app_id: uuid.UUID, + reverse: bool = False, + filter: Optional[str] = None, + db=db, +): + """Get All Users for an App + + Args: + app_id (uuid.UUID): The ID of the app representing the client + application using honcho + + Returns: + list[schemas.User]: List of User objects + + """ + data = None + if filter is not None: + data = json.loads(filter) + + return await paginate( + db, await crud.get_users(db, app_id=app_id, reverse=reverse, filter=data) + ) + + +@router.get("/{name}", response_model=schemas.User) +async def get_user_by_name( + request: Request, + app_id: uuid.UUID, + name: str, + db=db, +): + """Get a User + + Args: + app_id (uuid.UUID): The ID of the app representing the client application using + honcho + user_id (str): The User ID representing the user, managed by the user + + Returns: + schemas.User: User object + + """ + return await crud.get_user_by_name(db, app_id=app_id, name=name) + + +@router.get("/get_or_create/{name}", response_model=schemas.User) +async def get_or_create_user(request: Request, app_id: uuid.UUID, name: str, db=db): + """Get or Create a User + + Args: + app_id (uuid.UUID): The ID of the app representing the client application using + honcho + user_id (str): The User ID representing the user, managed by the user + + Returns: + schemas.User: User object + + """ + user = await crud.get_user_by_name(db, app_id=app_id, name=name) + if user is None: + user = await crud.create_user( + db, app_id=app_id, user=schemas.UserCreate(name=name) + ) + return user + + +@router.put("/{user_id}", response_model=schemas.User) +async def update_user( + request: Request, + app_id: uuid.UUID, + user_id: uuid.UUID, + user: schemas.UserUpdate, + db=db, +): + """Update a User + + Args: + app_id (uuid.UUID): The ID of the app representing the client application using + honcho + user_id (str): The User ID representing the user, managed by the user + user (schemas.UserCreate): The User object containing any metadata + + Returns: + schemas.User: Updated User object + + """ + return await crud.update_user(db, app_id=app_id, user_id=user_id, user=user) diff --git a/api/src/schemas.py b/api/src/schemas.py index e99e181..1f222d9 100644 --- a/api/src/schemas.py +++ b/api/src/schemas.py @@ -1,7 +1,7 @@ import datetime import uuid -from pydantic import BaseModel, validator +from pydantic import BaseModel, Field, validator class AppBase(BaseModel): @@ -21,7 +21,7 @@ class AppUpdate(AppBase): class App(AppBase): id: uuid.UUID name: str - h_metadata: dict + h_metadata: dict = Field(exclude=True) metadata: dict created_at: datetime.datetime @@ -33,7 +33,7 @@ def fetch_h_metadata(cls, value, values): class Config: from_attributes = True - schema_extra = {"exclude": ["h_metadata"]} + json_schema_extra = {"exclude": ["h_metadata"]} class UserBase(BaseModel): @@ -54,7 +54,7 @@ class User(UserBase): id: uuid.UUID app_id: uuid.UUID created_at: datetime.datetime - h_metadata: dict + h_metadata: dict = Field(exclude=True) metadata: dict @validator("metadata", pre=True, allow_reuse=True) @@ -65,7 +65,7 @@ def fetch_h_metadata(cls, value, values): class Config: from_attributes = True - schema_extra = {"exclude": ["h_metadata"]} + json_schema_extra = {"exclude": ["h_metadata"]} class MessageBase(BaseModel): @@ -87,7 +87,7 @@ class Message(MessageBase): is_user: bool session_id: uuid.UUID id: uuid.UUID - h_metadata: dict + h_metadata: dict = Field(exclude=True) metadata: dict created_at: datetime.datetime @@ -99,7 +99,7 @@ def fetch_h_metadata(cls, value, values): class Config: from_attributes = True - schema_extra = {"exclude": ["h_metadata"]} + json_schema_extra = {"exclude": ["h_metadata"]} class SessionBase(BaseModel): @@ -121,7 +121,7 @@ class Session(SessionBase): is_active: bool user_id: uuid.UUID location_id: str - h_metadata: dict + h_metadata: dict = Field(exclude=True) metadata: dict created_at: datetime.datetime @@ -133,7 +133,7 @@ def fetch_h_metadata(cls, value, values): class Config: from_attributes = True - schema_extra = {"exclude": ["h_metadata"]} + json_schema_extra = {"exclude": ["h_metadata"]} class MetamessageBase(BaseModel): @@ -158,7 +158,7 @@ class Metamessage(MetamessageBase): content: str id: uuid.UUID message_id: uuid.UUID - h_metadata: dict + h_metadata: dict = Field(exclude=True) metadata: dict created_at: datetime.datetime @@ -170,7 +170,7 @@ def fetch_h_metadata(cls, value, values): class Config: from_attributes = True - schema_extra = {"exclude": ["h_metadata"]} + json_schema_extra = {"exclude": ["h_metadata"]} class CollectionBase(BaseModel): @@ -191,7 +191,7 @@ class Collection(CollectionBase): id: uuid.UUID name: str user_id: uuid.UUID - h_metadata: dict + h_metadata: dict = Field(exclude=True) metadata: dict created_at: datetime.datetime @@ -203,7 +203,7 @@ def fetch_h_metadata(cls, value, values): class Config: from_attributes = True - schema_extra = {"exclude": ["h_metadata"]} + json_schema_extra = {"exclude": ["h_metadata"]} class DocumentBase(BaseModel): @@ -222,7 +222,7 @@ class DocumentUpdate(DocumentBase): class Document(DocumentBase): id: uuid.UUID content: str - h_metadata: dict + h_metadata: dict = Field(exclude=True) metadata: dict created_at: datetime.datetime collection_id: uuid.UUID @@ -235,7 +235,7 @@ def fetch_h_metadata(cls, value, values): class Config: from_attributes = True - schema_extra = {"exclude": ["h_metadata"]} + json_schema_extra = {"exclude": ["h_metadata"]} class AgentChat(BaseModel): diff --git a/example/cli/main.py b/example/cli/main.py index 56d048d..2e59878 100644 --- a/example/cli/main.py +++ b/example/cli/main.py @@ -7,7 +7,7 @@ from langchain_community.chat_models.fake import FakeListChatModel from honcho import Honcho -from honcho.ext.langchain import langchain_message_converter +from honcho.ext.langchain import _messages_to_langchain app_name = str(uuid4()) @@ -28,16 +28,6 @@ session = user.create_session() -# def langchain_message_converter(messages: List): -# new_messages = [] -# for message in messages: -# if message.is_user: -# new_messages.append(HumanMessage(content=message.content)) -# else: -# new_messages.append(AIMessage(content=message.content)) -# return new_messages - - def chat(): while True: user_input = input("User: ") @@ -46,7 +36,7 @@ def chat(): break user_message = HumanMessage(content=user_input) history = list(session.get_messages_generator()) - langchain_history = langchain_message_converter(history) + langchain_history = _messages_to_langchain(history) prompt = ChatPromptTemplate.from_messages( [system, *langchain_history, user_message] ) diff --git a/example/discord/honcho-dspy-personas/bot.py b/example/discord/honcho-dspy-personas/bot.py index ea91ec7..2e0ebfd 100644 --- a/example/discord/honcho-dspy-personas/bot.py +++ b/example/discord/honcho-dspy-personas/bot.py @@ -2,7 +2,7 @@ from uuid import uuid1 import discord from honcho import Honcho -from honcho.ext.langchain import langchain_message_converter +from honcho.ext.langchain import _messages_to_langchain from graph import chat from dspy import Example @@ -61,7 +61,7 @@ async def on_message(message): session = user.create_session(location_id) history = list(session.get_messages_generator())[:5] - chat_history = langchain_message_converter(history) + chat_history = _messages_to_langchain(history) inp = message.content user_message = session.create_message(is_user=True, content=inp) diff --git a/example/discord/honcho-fact-memory/bot.py b/example/discord/honcho-fact-memory/bot.py index aca2650..aba5099 100644 --- a/example/discord/honcho-fact-memory/bot.py +++ b/example/discord/honcho-fact-memory/bot.py @@ -2,7 +2,7 @@ from uuid import uuid1 import discord from honcho import Honcho -from honcho.ext.langchain import langchain_message_converter +from honcho.ext.langchain import _messages_to_langchain from chain import LMChain @@ -44,7 +44,7 @@ async def on_message(message): return user_id = f"discord_{str(message.author.id)}" - user = honcho.get_or_create(user_id) + user = honcho.get_or_create_user(user_id) location_id = str(message.channel.id) sessions = list(user.get_sessions_generator(location_id)) @@ -59,7 +59,7 @@ async def on_message(message): session = user.create_session(location_id) history = list(session.get_messages_generator()) - chat_history = langchain_message_converter(history) + chat_history = _messages_to_langchain(history) inp = message.content user_message = session.create_message(is_user=True, content=inp) diff --git a/example/discord/honcho-fact-memory/poetry.lock b/example/discord/honcho-fact-memory/poetry.lock index 46acc45..e81d8d9 100644 --- a/example/discord/honcho-fact-memory/poetry.lock +++ b/example/discord/honcho-fact-memory/poetry.lock @@ -1,117 +1,106 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.4.1 and should not be changed by hand. [[package]] name = "aiohttp" -version = "3.8.6" +version = "3.9.3" description = "Async http client/server framework (asyncio)" +category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "aiohttp-3.8.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:41d55fc043954cddbbd82503d9cc3f4814a40bcef30b3569bc7b5e34130718c1"}, - {file = "aiohttp-3.8.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1d84166673694841d8953f0a8d0c90e1087739d24632fe86b1a08819168b4566"}, - {file = "aiohttp-3.8.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:253bf92b744b3170eb4c4ca2fa58f9c4b87aeb1df42f71d4e78815e6e8b73c9e"}, - {file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fd194939b1f764d6bb05490987bfe104287bbf51b8d862261ccf66f48fb4096"}, - {file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c5f938d199a6fdbdc10bbb9447496561c3a9a565b43be564648d81e1102ac22"}, - {file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2817b2f66ca82ee699acd90e05c95e79bbf1dc986abb62b61ec8aaf851e81c93"}, - {file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fa375b3d34e71ccccf172cab401cd94a72de7a8cc01847a7b3386204093bb47"}, - {file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9de50a199b7710fa2904be5a4a9b51af587ab24c8e540a7243ab737b45844543"}, - {file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e1d8cb0b56b3587c5c01de3bf2f600f186da7e7b5f7353d1bf26a8ddca57f965"}, - {file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8e31e9db1bee8b4f407b77fd2507337a0a80665ad7b6c749d08df595d88f1cf5"}, - {file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7bc88fc494b1f0311d67f29fee6fd636606f4697e8cc793a2d912ac5b19aa38d"}, - {file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ec00c3305788e04bf6d29d42e504560e159ccaf0be30c09203b468a6c1ccd3b2"}, - {file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ad1407db8f2f49329729564f71685557157bfa42b48f4b93e53721a16eb813ed"}, - {file = "aiohttp-3.8.6-cp310-cp310-win32.whl", hash = "sha256:ccc360e87341ad47c777f5723f68adbb52b37ab450c8bc3ca9ca1f3e849e5fe2"}, - {file = "aiohttp-3.8.6-cp310-cp310-win_amd64.whl", hash = "sha256:93c15c8e48e5e7b89d5cb4613479d144fda8344e2d886cf694fd36db4cc86865"}, - {file = "aiohttp-3.8.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e2f9cc8e5328f829f6e1fb74a0a3a939b14e67e80832975e01929e320386b34"}, - {file = "aiohttp-3.8.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e6a00ffcc173e765e200ceefb06399ba09c06db97f401f920513a10c803604ca"}, - {file = "aiohttp-3.8.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:41bdc2ba359032e36c0e9de5a3bd00d6fb7ea558a6ce6b70acedf0da86458321"}, - {file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14cd52ccf40006c7a6cd34a0f8663734e5363fd981807173faf3a017e202fec9"}, - {file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2d5b785c792802e7b275c420d84f3397668e9d49ab1cb52bd916b3b3ffcf09ad"}, - {file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1bed815f3dc3d915c5c1e556c397c8667826fbc1b935d95b0ad680787896a358"}, - {file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96603a562b546632441926cd1293cfcb5b69f0b4159e6077f7c7dbdfb686af4d"}, - {file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d76e8b13161a202d14c9584590c4df4d068c9567c99506497bdd67eaedf36403"}, - {file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e3f1e3f1a1751bb62b4a1b7f4e435afcdade6c17a4fd9b9d43607cebd242924a"}, - {file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:76b36b3124f0223903609944a3c8bf28a599b2cc0ce0be60b45211c8e9be97f8"}, - {file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:a2ece4af1f3c967a4390c284797ab595a9f1bc1130ef8b01828915a05a6ae684"}, - {file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:16d330b3b9db87c3883e565340d292638a878236418b23cc8b9b11a054aaa887"}, - {file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:42c89579f82e49db436b69c938ab3e1559e5a4409eb8639eb4143989bc390f2f"}, - {file = "aiohttp-3.8.6-cp311-cp311-win32.whl", hash = "sha256:efd2fcf7e7b9d7ab16e6b7d54205beded0a9c8566cb30f09c1abe42b4e22bdcb"}, - {file = "aiohttp-3.8.6-cp311-cp311-win_amd64.whl", hash = "sha256:3b2ab182fc28e7a81f6c70bfbd829045d9480063f5ab06f6e601a3eddbbd49a0"}, - {file = "aiohttp-3.8.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:fdee8405931b0615220e5ddf8cd7edd8592c606a8e4ca2a00704883c396e4479"}, - {file = "aiohttp-3.8.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d25036d161c4fe2225d1abff2bd52c34ed0b1099f02c208cd34d8c05729882f0"}, - {file = "aiohttp-3.8.6-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d791245a894be071d5ab04bbb4850534261a7d4fd363b094a7b9963e8cdbd31"}, - {file = "aiohttp-3.8.6-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0cccd1de239afa866e4ce5c789b3032442f19c261c7d8a01183fd956b1935349"}, - {file = "aiohttp-3.8.6-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f13f60d78224f0dace220d8ab4ef1dbc37115eeeab8c06804fec11bec2bbd07"}, - {file = "aiohttp-3.8.6-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a9b5a0606faca4f6cc0d338359d6fa137104c337f489cd135bb7fbdbccb1e39"}, - {file = "aiohttp-3.8.6-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:13da35c9ceb847732bf5c6c5781dcf4780e14392e5d3b3c689f6d22f8e15ae31"}, - {file = "aiohttp-3.8.6-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:4d4cbe4ffa9d05f46a28252efc5941e0462792930caa370a6efaf491f412bc66"}, - {file = "aiohttp-3.8.6-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:229852e147f44da0241954fc6cb910ba074e597f06789c867cb7fb0621e0ba7a"}, - {file = "aiohttp-3.8.6-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:713103a8bdde61d13490adf47171a1039fd880113981e55401a0f7b42c37d071"}, - {file = "aiohttp-3.8.6-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:45ad816b2c8e3b60b510f30dbd37fe74fd4a772248a52bb021f6fd65dff809b6"}, - {file = "aiohttp-3.8.6-cp36-cp36m-win32.whl", hash = "sha256:2b8d4e166e600dcfbff51919c7a3789ff6ca8b3ecce16e1d9c96d95dd569eb4c"}, - {file = "aiohttp-3.8.6-cp36-cp36m-win_amd64.whl", hash = "sha256:0912ed87fee967940aacc5306d3aa8ba3a459fcd12add0b407081fbefc931e53"}, - {file = "aiohttp-3.8.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e2a988a0c673c2e12084f5e6ba3392d76c75ddb8ebc6c7e9ead68248101cd446"}, - {file = "aiohttp-3.8.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebf3fd9f141700b510d4b190094db0ce37ac6361a6806c153c161dc6c041ccda"}, - {file = "aiohttp-3.8.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3161ce82ab85acd267c8f4b14aa226047a6bee1e4e6adb74b798bd42c6ae1f80"}, - {file = "aiohttp-3.8.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d95fc1bf33a9a81469aa760617b5971331cdd74370d1214f0b3109272c0e1e3c"}, - {file = "aiohttp-3.8.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c43ecfef7deaf0617cee936836518e7424ee12cb709883f2c9a1adda63cc460"}, - {file = "aiohttp-3.8.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca80e1b90a05a4f476547f904992ae81eda5c2c85c66ee4195bb8f9c5fb47f28"}, - {file = "aiohttp-3.8.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:90c72ebb7cb3a08a7f40061079817133f502a160561d0675b0a6adf231382c92"}, - {file = "aiohttp-3.8.6-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bb54c54510e47a8c7c8e63454a6acc817519337b2b78606c4e840871a3e15349"}, - {file = "aiohttp-3.8.6-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:de6a1c9f6803b90e20869e6b99c2c18cef5cc691363954c93cb9adeb26d9f3ae"}, - {file = "aiohttp-3.8.6-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:a3628b6c7b880b181a3ae0a0683698513874df63783fd89de99b7b7539e3e8a8"}, - {file = "aiohttp-3.8.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:fc37e9aef10a696a5a4474802930079ccfc14d9f9c10b4662169671ff034b7df"}, - {file = "aiohttp-3.8.6-cp37-cp37m-win32.whl", hash = "sha256:f8ef51e459eb2ad8e7a66c1d6440c808485840ad55ecc3cafefadea47d1b1ba2"}, - {file = "aiohttp-3.8.6-cp37-cp37m-win_amd64.whl", hash = "sha256:b2fe42e523be344124c6c8ef32a011444e869dc5f883c591ed87f84339de5976"}, - {file = "aiohttp-3.8.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:9e2ee0ac5a1f5c7dd3197de309adfb99ac4617ff02b0603fd1e65b07dc772e4b"}, - {file = "aiohttp-3.8.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:01770d8c04bd8db568abb636c1fdd4f7140b284b8b3e0b4584f070180c1e5c62"}, - {file = "aiohttp-3.8.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3c68330a59506254b556b99a91857428cab98b2f84061260a67865f7f52899f5"}, - {file = "aiohttp-3.8.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:89341b2c19fb5eac30c341133ae2cc3544d40d9b1892749cdd25892bbc6ac951"}, - {file = "aiohttp-3.8.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:71783b0b6455ac8f34b5ec99d83e686892c50498d5d00b8e56d47f41b38fbe04"}, - {file = "aiohttp-3.8.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f628dbf3c91e12f4d6c8b3f092069567d8eb17814aebba3d7d60c149391aee3a"}, - {file = "aiohttp-3.8.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b04691bc6601ef47c88f0255043df6f570ada1a9ebef99c34bd0b72866c217ae"}, - {file = "aiohttp-3.8.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ee912f7e78287516df155f69da575a0ba33b02dd7c1d6614dbc9463f43066e3"}, - {file = "aiohttp-3.8.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9c19b26acdd08dd239e0d3669a3dddafd600902e37881f13fbd8a53943079dbc"}, - {file = "aiohttp-3.8.6-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:99c5ac4ad492b4a19fc132306cd57075c28446ec2ed970973bbf036bcda1bcc6"}, - {file = "aiohttp-3.8.6-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f0f03211fd14a6a0aed2997d4b1c013d49fb7b50eeb9ffdf5e51f23cfe2c77fa"}, - {file = "aiohttp-3.8.6-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:8d399dade330c53b4106160f75f55407e9ae7505263ea86f2ccca6bfcbdb4921"}, - {file = "aiohttp-3.8.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ec4fd86658c6a8964d75426517dc01cbf840bbf32d055ce64a9e63a40fd7b771"}, - {file = "aiohttp-3.8.6-cp38-cp38-win32.whl", hash = "sha256:33164093be11fcef3ce2571a0dccd9041c9a93fa3bde86569d7b03120d276c6f"}, - {file = "aiohttp-3.8.6-cp38-cp38-win_amd64.whl", hash = "sha256:bdf70bfe5a1414ba9afb9d49f0c912dc524cf60141102f3a11143ba3d291870f"}, - {file = "aiohttp-3.8.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d52d5dc7c6682b720280f9d9db41d36ebe4791622c842e258c9206232251ab2b"}, - {file = "aiohttp-3.8.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4ac39027011414dbd3d87f7edb31680e1f430834c8cef029f11c66dad0670aa5"}, - {file = "aiohttp-3.8.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3f5c7ce535a1d2429a634310e308fb7d718905487257060e5d4598e29dc17f0b"}, - {file = "aiohttp-3.8.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b30e963f9e0d52c28f284d554a9469af073030030cef8693106d918b2ca92f54"}, - {file = "aiohttp-3.8.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:918810ef188f84152af6b938254911055a72e0f935b5fbc4c1a4ed0b0584aed1"}, - {file = "aiohttp-3.8.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:002f23e6ea8d3dd8d149e569fd580c999232b5fbc601c48d55398fbc2e582e8c"}, - {file = "aiohttp-3.8.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4fcf3eabd3fd1a5e6092d1242295fa37d0354b2eb2077e6eb670accad78e40e1"}, - {file = "aiohttp-3.8.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:255ba9d6d5ff1a382bb9a578cd563605aa69bec845680e21c44afc2670607a95"}, - {file = "aiohttp-3.8.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d67f8baed00870aa390ea2590798766256f31dc5ed3ecc737debb6e97e2ede78"}, - {file = "aiohttp-3.8.6-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:86f20cee0f0a317c76573b627b954c412ea766d6ada1a9fcf1b805763ae7feeb"}, - {file = "aiohttp-3.8.6-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:39a312d0e991690ccc1a61f1e9e42daa519dcc34ad03eb6f826d94c1190190dd"}, - {file = "aiohttp-3.8.6-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:e827d48cf802de06d9c935088c2924e3c7e7533377d66b6f31ed175c1620e05e"}, - {file = "aiohttp-3.8.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bd111d7fc5591ddf377a408ed9067045259ff2770f37e2d94e6478d0f3fc0c17"}, - {file = "aiohttp-3.8.6-cp39-cp39-win32.whl", hash = "sha256:caf486ac1e689dda3502567eb89ffe02876546599bbf915ec94b1fa424eeffd4"}, - {file = "aiohttp-3.8.6-cp39-cp39-win_amd64.whl", hash = "sha256:3f0e27e5b733803333bb2371249f41cf42bae8884863e8e8965ec69bebe53132"}, - {file = "aiohttp-3.8.6.tar.gz", hash = "sha256:b0cf2a4501bff9330a8a5248b4ce951851e415bdcce9dc158e76cfd55e15085c"}, + {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54"}, + {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc"}, + {file = "aiohttp-3.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f56455b0c2c7cc3b0c584815264461d07b177f903a04481dfc33e08a89f0c26b"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bca77a198bb6e69795ef2f09a5f4c12758487f83f33d63acde5f0d4919815768"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e083c285857b78ee21a96ba1eb1b5339733c3563f72980728ca2b08b53826ca5"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29"}, + {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df822ee7feaaeffb99c1a9e5e608800bd8eda6e5f18f5cfb0dc7eeb2eaa6bbec"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cd73265a9e5ea618014802ab01babf1940cecb90c9762d8b9e7d2cc1e1969ec6"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf"}, + {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52"}, + {file = "aiohttp-3.9.3-cp310-cp310-win32.whl", hash = "sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b"}, + {file = "aiohttp-3.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5"}, + {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d"}, + {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c46956ed82961e31557b6857a5ca153c67e5476972e5f7190015018760938da2"}, + {file = "aiohttp-3.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad46e6f620574b3b4801c68255492e0159d1712271cc99d8bdf35f2043ec266"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b"}, + {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84871a243359bb42c12728f04d181a389718710129b36b6aad0fc4655a7647d4"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:f033d80bc6283092613882dfe40419c6a6a1527e04fc69350e87a9df02bbc283"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e"}, + {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4"}, + {file = "aiohttp-3.9.3-cp311-cp311-win32.whl", hash = "sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5"}, + {file = "aiohttp-3.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8"}, + {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:38a19bc3b686ad55804ae931012f78f7a534cce165d089a2059f658f6c91fa60"}, + {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:770d015888c2a598b377bd2f663adfd947d78c0124cfe7b959e1ef39f5b13869"}, + {file = "aiohttp-3.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee43080e75fc92bf36219926c8e6de497f9b247301bbf88c5c7593d931426679"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52df73f14ed99cee84865b95a3d9e044f226320a87af208f068ecc33e0c35b96"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc9b311743a78043b26ffaeeb9715dc360335e5517832f5a8e339f8a43581e4d"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b955ed993491f1a5da7f92e98d5dad3c1e14dc175f74517c4e610b1f2456fb11"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:504b6981675ace64c28bf4a05a508af5cde526e36492c98916127f5a02354d53"}, + {file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6fe5571784af92b6bc2fda8d1925cccdf24642d49546d3144948a6a1ed58ca5"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ba39e9c8627edc56544c8628cc180d88605df3892beeb2b94c9bc857774848ca"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e5e46b578c0e9db71d04c4b506a2121c0cb371dd89af17a0586ff6769d4c58c1"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:938a9653e1e0c592053f815f7028e41a3062e902095e5a7dc84617c87267ebd5"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:c3452ea726c76e92f3b9fae4b34a151981a9ec0a4847a627c43d71a15ac32aa6"}, + {file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ff30218887e62209942f91ac1be902cc80cddb86bf00fbc6783b7a43b2bea26f"}, + {file = "aiohttp-3.9.3-cp312-cp312-win32.whl", hash = "sha256:38f307b41e0bea3294a9a2a87833191e4bcf89bb0365e83a8be3a58b31fb7f38"}, + {file = "aiohttp-3.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:b791a3143681a520c0a17e26ae7465f1b6f99461a28019d1a2f425236e6eedb5"}, + {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0ed621426d961df79aa3b963ac7af0d40392956ffa9be022024cd16297b30c8c"}, + {file = "aiohttp-3.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:7f46acd6a194287b7e41e87957bfe2ad1ad88318d447caf5b090012f2c5bb528"}, + {file = "aiohttp-3.9.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:feeb18a801aacb098220e2c3eea59a512362eb408d4afd0c242044c33ad6d542"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f734e38fd8666f53da904c52a23ce517f1b07722118d750405af7e4123933511"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b40670ec7e2156d8e57f70aec34a7216407848dfe6c693ef131ddf6e76feb672"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fdd215b7b7fd4a53994f238d0f46b7ba4ac4c0adb12452beee724ddd0743ae5d"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:017a21b0df49039c8f46ca0971b3a7fdc1f56741ab1240cb90ca408049766168"}, + {file = "aiohttp-3.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e99abf0bba688259a496f966211c49a514e65afa9b3073a1fcee08856e04425b"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:648056db9a9fa565d3fa851880f99f45e3f9a771dd3ff3bb0c048ea83fb28194"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8aacb477dc26797ee089721536a292a664846489c49d3ef9725f992449eda5a8"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:522a11c934ea660ff8953eda090dcd2154d367dec1ae3c540aff9f8a5c109ab4"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:5bce0dc147ca85caa5d33debc4f4d65e8e8b5c97c7f9f660f215fa74fc49a321"}, + {file = "aiohttp-3.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:4b4af9f25b49a7be47c0972139e59ec0e8285c371049df1a63b6ca81fdd216a2"}, + {file = "aiohttp-3.9.3-cp38-cp38-win32.whl", hash = "sha256:298abd678033b8571995650ccee753d9458dfa0377be4dba91e4491da3f2be63"}, + {file = "aiohttp-3.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:69361bfdca5468c0488d7017b9b1e5ce769d40b46a9f4a2eed26b78619e9396c"}, + {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0fa43c32d1643f518491d9d3a730f85f5bbaedcbd7fbcae27435bb8b7a061b29"}, + {file = "aiohttp-3.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:835a55b7ca49468aaaac0b217092dfdff370e6c215c9224c52f30daaa735c1c1"}, + {file = "aiohttp-3.9.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06a9b2c8837d9a94fae16c6223acc14b4dfdff216ab9b7202e07a9a09541168f"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abf151955990d23f84205286938796c55ff11bbfb4ccfada8c9c83ae6b3c89a3"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59c26c95975f26e662ca78fdf543d4eeaef70e533a672b4113dd888bd2423caa"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f95511dd5d0e05fd9728bac4096319f80615aaef4acbecb35a990afebe953b0e"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:595f105710293e76b9dc09f52e0dd896bd064a79346234b521f6b968ffdd8e58"}, + {file = "aiohttp-3.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7c8b816c2b5af5c8a436df44ca08258fc1a13b449393a91484225fcb7545533"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f1088fa100bf46e7b398ffd9904f4808a0612e1d966b4aa43baa535d1b6341eb"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f59dfe57bb1ec82ac0698ebfcdb7bcd0e99c255bd637ff613760d5f33e7c81b3"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:361a1026c9dd4aba0109e4040e2aecf9884f5cfe1b1b1bd3d09419c205e2e53d"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:363afe77cfcbe3a36353d8ea133e904b108feea505aa4792dad6585a8192c55a"}, + {file = "aiohttp-3.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e2c45c208c62e955e8256949eb225bd8b66a4c9b6865729a786f2aa79b72e9d"}, + {file = "aiohttp-3.9.3-cp39-cp39-win32.whl", hash = "sha256:f7217af2e14da0856e082e96ff637f14ae45c10a5714b63c77f26d8884cf1051"}, + {file = "aiohttp-3.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:27468897f628c627230dba07ec65dc8d0db566923c48f29e084ce382119802bc"}, + {file = "aiohttp-3.9.3.tar.gz", hash = "sha256:90842933e5d1ff760fae6caca4b2b3edba53ba8f4b71e95dacf2818a2aca06f7"}, ] [package.dependencies] aiosignal = ">=1.1.2" -async-timeout = ">=4.0.0a3,<5.0" attrs = ">=17.3.0" -charset-normalizer = ">=2.0,<4.0" frozenlist = ">=1.1.1" multidict = ">=4.5,<7.0" yarl = ">=1.0,<2.0" [package.extras] -speedups = ["Brotli", "aiodns", "cchardet"] +speedups = ["Brotli", "aiodns", "brotlicffi"] [[package]] name = "aiosignal" version = "1.3.1" description = "aiosignal: a list of registered asynchronous callbacks" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -126,6 +115,7 @@ frozenlist = ">=1.1.0" name = "annotated-types" version = "0.6.0" description = "Reusable constraint types to use with typing.Annotated" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -135,13 +125,14 @@ files = [ [[package]] name = "anyio" -version = "4.2.0" +version = "4.3.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" +category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "anyio-4.2.0-py3-none-any.whl", hash = "sha256:745843b39e829e108e518c489b31dc757de7d2131d53fac32bd8df268227bfee"}, - {file = "anyio-4.2.0.tar.gz", hash = "sha256:e1875bb4b4e2de1669f4bc7869b6d3f54231cdced71605e6e64c9be77e3be50f"}, + {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"}, + {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"}, ] [package.dependencies] @@ -153,21 +144,11 @@ doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphin test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] trio = ["trio (>=0.23)"] -[[package]] -name = "async-timeout" -version = "4.0.3" -description = "Timeout context manager for asyncio programs" -optional = false -python-versions = ">=3.7" -files = [ - {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"}, - {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"}, -] - [[package]] name = "attrs" version = "23.2.0" description = "Classes Without Boilerplate" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -187,6 +168,7 @@ tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "p name = "certifi" version = "2024.2.2" description = "Python package for providing Mozilla's CA Bundle." +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -198,6 +180,7 @@ files = [ name = "charset-normalizer" version = "3.3.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" optional = false python-versions = ">=3.7.0" files = [ @@ -297,6 +280,7 @@ files = [ name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." +category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -308,6 +292,7 @@ files = [ name = "dataclasses-json" version = "0.6.4" description = "Easily serialize dataclasses to and from JSON." +category = "main" optional = false python-versions = ">=3.7,<4.0" files = [ @@ -323,6 +308,7 @@ typing-inspect = ">=0.4.0,<1" name = "distro" version = "1.9.0" description = "Distro - an OS platform information API" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -334,6 +320,7 @@ files = [ name = "frozenlist" version = "1.4.1" description = "A list-like structure which implements collections.abc.MutableSequence" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -420,6 +407,7 @@ files = [ name = "greenlet" version = "3.0.3" description = "Lightweight in-process concurrent programming" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -491,6 +479,7 @@ test = ["objgraph", "psutil"] name = "h11" version = "0.14.0" description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -500,13 +489,14 @@ files = [ [[package]] name = "honcho-ai" -version = "0.0.3" +version = "0.0.5" description = "Python Client SDK for Honcho" +category = "main" optional = false -python-versions = ">=3.10,<4.0" +python-versions = ">=3.9,<4.0" files = [ - {file = "honcho_ai-0.0.3-py3-none-any.whl", hash = "sha256:a817ec62c4fd8dad1d629927511ce98a3f626f4bc55474187b80010e208e61ba"}, - {file = "honcho_ai-0.0.3.tar.gz", hash = "sha256:ca52bb8c5036bfdbeee0c71ca754c580c672b28a4824240123b783f8679ca18e"}, + {file = "honcho_ai-0.0.5-py3-none-any.whl", hash = "sha256:3278aac9dd80cde10fa3216cc38e84eae90acc0b5c0fac986abb40973a8fe156"}, + {file = "honcho_ai-0.0.5.tar.gz", hash = "sha256:7283ae2ee3baa5f0429c9ea2eb9f1e74b3fb164d5a7448ee7872ba9847500ae6"}, ] [package.dependencies] @@ -514,13 +504,14 @@ httpx = ">=0.26.0,<0.27.0" [[package]] name = "httpcore" -version = "1.0.3" +version = "1.0.4" description = "A minimal low-level HTTP client." +category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "httpcore-1.0.3-py3-none-any.whl", hash = "sha256:9a6a501c3099307d9fd76ac244e08503427679b1e81ceb1d922485e2f2462ad2"}, - {file = "httpcore-1.0.3.tar.gz", hash = "sha256:5c0f9546ad17dac4d0772b0808856eb616eb8b48ce94f49ed819fd6982a8a544"}, + {file = "httpcore-1.0.4-py3-none-any.whl", hash = "sha256:ac418c1db41bade2ad53ae2f3834a3a0f5ae76b56cf5aa497d2d033384fc7d73"}, + {file = "httpcore-1.0.4.tar.gz", hash = "sha256:cb2839ccfcba0d2d3c1131d3c3e26dfc327326fbe7a5dc0dbfe9f6c9151bb022"}, ] [package.dependencies] @@ -530,13 +521,14 @@ h11 = ">=0.13,<0.15" [package.extras] asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.24.0)"] +socks = ["socksio (>=1.0.0,<2.0.0)"] +trio = ["trio (>=0.22.0,<0.25.0)"] [[package]] name = "httpx" version = "0.26.0" description = "The next generation HTTP client." +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -547,20 +539,21 @@ files = [ [package.dependencies] anyio = "*" certifi = "*" -httpcore = "==1.*" +httpcore = ">=1.0.0,<2.0.0" idna = "*" sniffio = "*" [package.extras] brotli = ["brotli", "brotlicffi"] -cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] -socks = ["socksio (==1.*)"] +socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "idna" version = "3.6" description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -572,6 +565,7 @@ files = [ name = "jsonpatch" version = "1.33" description = "Apply JSON-Patches (RFC 6902)" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" files = [ @@ -586,6 +580,7 @@ jsonpointer = ">=1.9" name = "jsonpointer" version = "2.4" description = "Identify specific nodes in a JSON document (RFC 6901)" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" files = [ @@ -597,6 +592,7 @@ files = [ name = "langchain-community" version = "0.0.20" description = "Community contributed LangChain integrations." +category = "main" optional = false python-versions = ">=3.8.1,<4.0" files = [ @@ -623,6 +619,7 @@ extended-testing = ["aiosqlite (>=0.19.0,<0.20.0)", "aleph-alpha-client (>=2.15. name = "langchain-core" version = "0.1.23" description = "Building applications with LLMs through composability" +category = "main" optional = false python-versions = ">=3.8.1,<4.0" files = [ @@ -647,6 +644,7 @@ extended-testing = ["jinja2 (>=3,<4)"] name = "langchain-openai" version = "0.0.6" description = "An integration package connecting OpenAI and LangChain" +category = "main" optional = false python-versions = ">=3.8.1,<4.0" files = [ @@ -664,6 +662,7 @@ tiktoken = ">=0.5.2,<1" name = "langsmith" version = "0.0.87" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." +category = "main" optional = false python-versions = ">=3.8.1,<4.0" files = [ @@ -677,28 +676,29 @@ requests = ">=2,<3" [[package]] name = "marshmallow" -version = "3.20.2" +version = "3.21.1" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." +category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "marshmallow-3.20.2-py3-none-any.whl", hash = "sha256:c21d4b98fee747c130e6bc8f45c4b3199ea66bc00c12ee1f639f0aeca034d5e9"}, - {file = "marshmallow-3.20.2.tar.gz", hash = "sha256:4c1daff273513dc5eb24b219a8035559dc573c8f322558ef85f5438ddd1236dd"}, + {file = "marshmallow-3.21.1-py3-none-any.whl", hash = "sha256:f085493f79efb0644f270a9bf2892843142d80d7174bbbd2f3713f2a589dc633"}, + {file = "marshmallow-3.21.1.tar.gz", hash = "sha256:4e65e9e0d80fc9e609574b9983cf32579f305c718afb30d7233ab818571768c3"}, ] [package.dependencies] packaging = ">=17.0" [package.extras] -dev = ["pre-commit (>=2.4,<4.0)", "pytest", "pytz", "simplejson", "tox"] -docs = ["alabaster (==0.7.15)", "autodocsumm (==0.2.12)", "sphinx (==7.2.6)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] -lint = ["pre-commit (>=2.4,<4.0)"] +dev = ["marshmallow[tests]", "pre-commit (>=3.5,<4.0)", "tox"] +docs = ["alabaster (==0.7.16)", "autodocsumm (==0.2.12)", "sphinx (==7.2.6)", "sphinx-issues (==4.0.0)", "sphinx-version-warning (==1.1.2)"] tests = ["pytest", "pytz", "simplejson"] [[package]] name = "multidict" version = "6.0.5" description = "multidict implementation" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -798,6 +798,7 @@ files = [ name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." +category = "main" optional = false python-versions = ">=3.5" files = [ @@ -809,6 +810,7 @@ files = [ name = "numpy" version = "1.26.4" description = "Fundamental package for array computing in Python" +category = "main" optional = false python-versions = ">=3.9" files = [ @@ -852,13 +854,14 @@ files = [ [[package]] name = "openai" -version = "1.12.0" +version = "1.14.1" description = "The official Python library for the openai API" +category = "main" optional = false python-versions = ">=3.7.1" files = [ - {file = "openai-1.12.0-py3-none-any.whl", hash = "sha256:a54002c814e05222e413664f651b5916714e4700d041d5cf5724d3ae1a3e3481"}, - {file = "openai-1.12.0.tar.gz", hash = "sha256:99c5d257d09ea6533d689d1cc77caa0ac679fa21efef8893d8b0832a86877f1b"}, + {file = "openai-1.14.1-py3-none-any.whl", hash = "sha256:f9322b0bf3b82bbd06930fad535369a023f35a3a96d3ef0b827644a15d7aae97"}, + {file = "openai-1.14.1.tar.gz", hash = "sha256:1fab5dd623cdc0c7c6e7da5d8d11fa6900f94191c2dfb6510d7eac33195fa175"}, ] [package.dependencies] @@ -877,6 +880,7 @@ datalib = ["numpy (>=1)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"] name = "packaging" version = "23.2" description = "Core utilities for Python packages" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -886,37 +890,39 @@ files = [ [[package]] name = "py-cord" -version = "2.4.1" +version = "2.5.0" description = "A Python wrapper for the Discord API" +category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "py-cord-2.4.1.tar.gz", hash = "sha256:0266c9d9a9d2397622a0e5ead09826690e688ba3cf14c470167b81e6cd2d8a56"}, - {file = "py_cord-2.4.1-py3-none-any.whl", hash = "sha256:862a372c364cd263e2c8e696c64887f969c02cbdf0fdd6b09f0283e9dd67a290"}, + {file = "py-cord-2.5.0.tar.gz", hash = "sha256:faf08af5da5eac2ed3d1c8a43d8307d5a1e3f01602def283330c9d2cde0b1162"}, + {file = "py_cord-2.5.0-py3-none-any.whl", hash = "sha256:9e5fc79feec5a48f53aa4c066b57dd75fe67d29021b042d12f378a513d308bbc"}, ] [package.dependencies] -aiohttp = ">=3.6.0,<3.9.0" +aiohttp = ">=3.6.0,<4.0" [package.extras] -docs = ["furo", "myst-parser (==0.18.1)", "sphinx (==5.3.0)", "sphinx-autodoc-typehints (==1.22)", "sphinx-copybutton (==0.5.1)", "sphinxcontrib-trio (==1.1.2)", "sphinxcontrib-websupport (==1.2.4)", "sphinxext-opengraph (==0.8.1)"] -speed = ["aiohttp[speedups]", "orjson (>=3.5.4)"] +docs = ["furo (==2023.3.23)", "myst-parser (==1.0.0)", "sphinx (==5.3.0)", "sphinx-autodoc-typehints (==1.23.0)", "sphinx-copybutton (==0.5.2)", "sphinxcontrib-trio (==1.1.2)", "sphinxcontrib-websupport (==1.2.4)", "sphinxext-opengraph (==0.9.1)"] +speed = ["aiohttp[speedups]", "msgspec (>=0.18.6,<0.19.0)"] voice = ["PyNaCl (>=1.3.0,<1.6)"] [[package]] name = "pydantic" -version = "2.6.1" +version = "2.6.4" description = "Data validation using Python type hints" +category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.6.1-py3-none-any.whl", hash = "sha256:0b6a909df3192245cb736509a92ff69e4fef76116feffec68e93a567347bae6f"}, - {file = "pydantic-2.6.1.tar.gz", hash = "sha256:4fd5c182a2488dc63e6d32737ff19937888001e2a6d86e94b3f233104a5d1fa9"}, + {file = "pydantic-2.6.4-py3-none-any.whl", hash = "sha256:cc46fce86607580867bdc3361ad462bab9c222ef042d3da86f2fb333e1d916c5"}, + {file = "pydantic-2.6.4.tar.gz", hash = "sha256:b1704e0847db01817624a6b86766967f552dd9dbf3afba4004409f908dcc84e6"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.16.2" +pydantic-core = "2.16.3" typing-extensions = ">=4.6.1" [package.extras] @@ -924,90 +930,91 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.16.2" +version = "2.16.3" description = "" +category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.16.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3fab4e75b8c525a4776e7630b9ee48aea50107fea6ca9f593c98da3f4d11bf7c"}, - {file = "pydantic_core-2.16.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8bde5b48c65b8e807409e6f20baee5d2cd880e0fad00b1a811ebc43e39a00ab2"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2924b89b16420712e9bb8192396026a8fbd6d8726224f918353ac19c4c043d2a"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:16aa02e7a0f539098e215fc193c8926c897175d64c7926d00a36188917717a05"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:936a787f83db1f2115ee829dd615c4f684ee48ac4de5779ab4300994d8af325b"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:459d6be6134ce3b38e0ef76f8a672924460c455d45f1ad8fdade36796df1ddc8"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9ee4febb249c591d07b2d4dd36ebcad0ccd128962aaa1801508320896575ef"}, - {file = "pydantic_core-2.16.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40a0bd0bed96dae5712dab2aba7d334a6c67cbcac2ddfca7dbcc4a8176445990"}, - {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:870dbfa94de9b8866b37b867a2cb37a60c401d9deb4a9ea392abf11a1f98037b"}, - {file = "pydantic_core-2.16.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:308974fdf98046db28440eb3377abba274808bf66262e042c412eb2adf852731"}, - {file = "pydantic_core-2.16.2-cp310-none-win32.whl", hash = "sha256:a477932664d9611d7a0816cc3c0eb1f8856f8a42435488280dfbf4395e141485"}, - {file = "pydantic_core-2.16.2-cp310-none-win_amd64.whl", hash = "sha256:8f9142a6ed83d90c94a3efd7af8873bf7cefed2d3d44387bf848888482e2d25f"}, - {file = "pydantic_core-2.16.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:406fac1d09edc613020ce9cf3f2ccf1a1b2f57ab00552b4c18e3d5276c67eb11"}, - {file = "pydantic_core-2.16.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ce232a6170dd6532096cadbf6185271e4e8c70fc9217ebe105923ac105da9978"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90fec23b4b05a09ad988e7a4f4e081711a90eb2a55b9c984d8b74597599180f"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8aafeedb6597a163a9c9727d8a8bd363a93277701b7bfd2749fbefee2396469e"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9957433c3a1b67bdd4c63717eaf174ebb749510d5ea612cd4e83f2d9142f3fc8"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0d7a9165167269758145756db43a133608a531b1e5bb6a626b9ee24bc38a8f7"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dffaf740fe2e147fedcb6b561353a16243e654f7fe8e701b1b9db148242e1272"}, - {file = "pydantic_core-2.16.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8ed79883b4328b7f0bd142733d99c8e6b22703e908ec63d930b06be3a0e7113"}, - {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:cf903310a34e14651c9de056fcc12ce090560864d5a2bb0174b971685684e1d8"}, - {file = "pydantic_core-2.16.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:46b0d5520dbcafea9a8645a8164658777686c5c524d381d983317d29687cce97"}, - {file = "pydantic_core-2.16.2-cp311-none-win32.whl", hash = "sha256:70651ff6e663428cea902dac297066d5c6e5423fda345a4ca62430575364d62b"}, - {file = "pydantic_core-2.16.2-cp311-none-win_amd64.whl", hash = "sha256:98dc6f4f2095fc7ad277782a7c2c88296badcad92316b5a6e530930b1d475ebc"}, - {file = "pydantic_core-2.16.2-cp311-none-win_arm64.whl", hash = "sha256:ef6113cd31411eaf9b39fc5a8848e71c72656fd418882488598758b2c8c6dfa0"}, - {file = "pydantic_core-2.16.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:88646cae28eb1dd5cd1e09605680c2b043b64d7481cdad7f5003ebef401a3039"}, - {file = "pydantic_core-2.16.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7b883af50eaa6bb3299780651e5be921e88050ccf00e3e583b1e92020333304b"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bf26c2e2ea59d32807081ad51968133af3025c4ba5753e6a794683d2c91bf6e"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:99af961d72ac731aae2a1b55ccbdae0733d816f8bfb97b41909e143de735f522"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02906e7306cb8c5901a1feb61f9ab5e5c690dbbeaa04d84c1b9ae2a01ebe9379"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5362d099c244a2d2f9659fb3c9db7c735f0004765bbe06b99be69fbd87c3f15"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ac426704840877a285d03a445e162eb258924f014e2f074e209d9b4ff7bf380"}, - {file = "pydantic_core-2.16.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b94cbda27267423411c928208e89adddf2ea5dd5f74b9528513f0358bba019cb"}, - {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6db58c22ac6c81aeac33912fb1af0e930bc9774166cdd56eade913d5f2fff35e"}, - {file = "pydantic_core-2.16.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396fdf88b1b503c9c59c84a08b6833ec0c3b5ad1a83230252a9e17b7dfb4cffc"}, - {file = "pydantic_core-2.16.2-cp312-none-win32.whl", hash = "sha256:7c31669e0c8cc68400ef0c730c3a1e11317ba76b892deeefaf52dcb41d56ed5d"}, - {file = "pydantic_core-2.16.2-cp312-none-win_amd64.whl", hash = "sha256:a3b7352b48fbc8b446b75f3069124e87f599d25afb8baa96a550256c031bb890"}, - {file = "pydantic_core-2.16.2-cp312-none-win_arm64.whl", hash = "sha256:a9e523474998fb33f7c1a4d55f5504c908d57add624599e095c20fa575b8d943"}, - {file = "pydantic_core-2.16.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ae34418b6b389d601b31153b84dce480351a352e0bb763684a1b993d6be30f17"}, - {file = "pydantic_core-2.16.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:732bd062c9e5d9582a30e8751461c1917dd1ccbdd6cafb032f02c86b20d2e7ec"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b52776a2e3230f4854907a1e0946eec04d41b1fc64069ee774876bbe0eab55"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ef551c053692b1e39e3f7950ce2296536728871110e7d75c4e7753fb30ca87f4"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ebb892ed8599b23fa8f1799e13a12c87a97a6c9d0f497525ce9858564c4575a4"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:aa6c8c582036275997a733427b88031a32ffa5dfc3124dc25a730658c47a572f"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ba0884a91f1aecce75202473ab138724aa4fb26d7707f2e1fa6c3e68c84fbf"}, - {file = "pydantic_core-2.16.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7924e54f7ce5d253d6160090ddc6df25ed2feea25bfb3339b424a9dd591688bc"}, - {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69a7b96b59322a81c2203be537957313b07dd333105b73db0b69212c7d867b4b"}, - {file = "pydantic_core-2.16.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7e6231aa5bdacda78e96ad7b07d0c312f34ba35d717115f4b4bff6cb87224f0f"}, - {file = "pydantic_core-2.16.2-cp38-none-win32.whl", hash = "sha256:41dac3b9fce187a25c6253ec79a3f9e2a7e761eb08690e90415069ea4a68ff7a"}, - {file = "pydantic_core-2.16.2-cp38-none-win_amd64.whl", hash = "sha256:f685dbc1fdadb1dcd5b5e51e0a378d4685a891b2ddaf8e2bba89bd3a7144e44a"}, - {file = "pydantic_core-2.16.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:55749f745ebf154c0d63d46c8c58594d8894b161928aa41adbb0709c1fe78b77"}, - {file = "pydantic_core-2.16.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b30b0dd58a4509c3bd7eefddf6338565c4905406aee0c6e4a5293841411a1286"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18de31781cdc7e7b28678df7c2d7882f9692ad060bc6ee3c94eb15a5d733f8f7"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5864b0242f74b9dd0b78fd39db1768bc3f00d1ffc14e596fd3e3f2ce43436a33"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8f9186ca45aee030dc8234118b9c0784ad91a0bb27fc4e7d9d6608a5e3d386c"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc6f6c9be0ab6da37bc77c2dda5f14b1d532d5dbef00311ee6e13357a418e646"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa057095f621dad24a1e906747179a69780ef45cc8f69e97463692adbcdae878"}, - {file = "pydantic_core-2.16.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6ad84731a26bcfb299f9eab56c7932d46f9cad51c52768cace09e92a19e4cf55"}, - {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3b052c753c4babf2d1edc034c97851f867c87d6f3ea63a12e2700f159f5c41c3"}, - {file = "pydantic_core-2.16.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:e0f686549e32ccdb02ae6f25eee40cc33900910085de6aa3790effd391ae10c2"}, - {file = "pydantic_core-2.16.2-cp39-none-win32.whl", hash = "sha256:7afb844041e707ac9ad9acad2188a90bffce2c770e6dc2318be0c9916aef1469"}, - {file = "pydantic_core-2.16.2-cp39-none-win_amd64.whl", hash = "sha256:9da90d393a8227d717c19f5397688a38635afec89f2e2d7af0df037f3249c39a"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5f60f920691a620b03082692c378661947d09415743e437a7478c309eb0e4f82"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:47924039e785a04d4a4fa49455e51b4eb3422d6eaacfde9fc9abf8fdef164e8a"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6294e76b0380bb7a61eb8a39273c40b20beb35e8c87ee101062834ced19c545"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe56851c3f1d6f5384b3051c536cc81b3a93a73faf931f404fef95217cf1e10d"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9d776d30cde7e541b8180103c3f294ef7c1862fd45d81738d156d00551005784"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:72f7919af5de5ecfaf1eba47bf9a5d8aa089a3340277276e5636d16ee97614d7"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:4bfcbde6e06c56b30668a0c872d75a7ef3025dc3c1823a13cf29a0e9b33f67e8"}, - {file = "pydantic_core-2.16.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ff7c97eb7a29aba230389a2661edf2e9e06ce616c7e35aa764879b6894a44b25"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:9b5f13857da99325dcabe1cc4e9e6a3d7b2e2c726248ba5dd4be3e8e4a0b6d0e"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a7e41e3ada4cca5f22b478c08e973c930e5e6c7ba3588fb8e35f2398cdcc1545"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:60eb8ceaa40a41540b9acae6ae7c1f0a67d233c40dc4359c256ad2ad85bdf5e5"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7beec26729d496a12fd23cf8da9944ee338c8b8a17035a560b585c36fe81af20"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:22c5f022799f3cd6741e24f0443ead92ef42be93ffda0d29b2597208c94c3753"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:eca58e319f4fd6df004762419612122b2c7e7d95ffafc37e890252f869f3fb2a"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed957db4c33bc99895f3a1672eca7e80e8cda8bd1e29a80536b4ec2153fa9804"}, - {file = "pydantic_core-2.16.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:459c0d338cc55d099798618f714b21b7ece17eb1a87879f2da20a3ff4c7628e2"}, - {file = "pydantic_core-2.16.2.tar.gz", hash = "sha256:0ba503850d8b8dcc18391f10de896ae51d37fe5fe43dbfb6a35c5c5cad271a06"}, + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:75b81e678d1c1ede0785c7f46690621e4c6e63ccd9192af1f0bd9d504bbb6bf4"}, + {file = "pydantic_core-2.16.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9c865a7ee6f93783bd5d781af5a4c43dadc37053a5b42f7d18dc019f8c9d2bd1"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:162e498303d2b1c036b957a1278fa0899d02b2842f1ff901b6395104c5554a45"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f583bd01bbfbff4eaee0868e6fc607efdfcc2b03c1c766b06a707abbc856187"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b926dd38db1519ed3043a4de50214e0d600d404099c3392f098a7f9d75029ff8"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:716b542728d4c742353448765aa7cdaa519a7b82f9564130e2b3f6766018c9ec"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc4ad7f7ee1a13d9cb49d8198cd7d7e3aa93e425f371a68235f784e99741561f"}, + {file = "pydantic_core-2.16.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bd87f48924f360e5d1c5f770d6155ce0e7d83f7b4e10c2f9ec001c73cf475c99"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0df446663464884297c793874573549229f9eca73b59360878f382a0fc085979"}, + {file = "pydantic_core-2.16.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4df8a199d9f6afc5ae9a65f8f95ee52cae389a8c6b20163762bde0426275b7db"}, + {file = "pydantic_core-2.16.3-cp310-none-win32.whl", hash = "sha256:456855f57b413f077dff513a5a28ed838dbbb15082ba00f80750377eed23d132"}, + {file = "pydantic_core-2.16.3-cp310-none-win_amd64.whl", hash = "sha256:732da3243e1b8d3eab8c6ae23ae6a58548849d2e4a4e03a1924c8ddf71a387cb"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:519ae0312616026bf4cedc0fe459e982734f3ca82ee8c7246c19b650b60a5ee4"}, + {file = "pydantic_core-2.16.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b3992a322a5617ded0a9f23fd06dbc1e4bd7cf39bc4ccf344b10f80af58beacd"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d62da299c6ecb04df729e4b5c52dc0d53f4f8430b4492b93aa8de1f541c4aac"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2acca2be4bb2f2147ada8cac612f8a98fc09f41c89f87add7256ad27332c2fda"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1b662180108c55dfbf1280d865b2d116633d436cfc0bba82323554873967b340"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e7c6ed0dc9d8e65f24f5824291550139fe6f37fac03788d4580da0d33bc00c97"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1bb0827f56654b4437955555dc3aeeebeddc47c2d7ed575477f082622c49e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e56f8186d6210ac7ece503193ec84104da7ceb98f68ce18c07282fcc2452e76f"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:936e5db01dd49476fa8f4383c259b8b1303d5dd5fb34c97de194560698cc2c5e"}, + {file = "pydantic_core-2.16.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:33809aebac276089b78db106ee692bdc9044710e26f24a9a2eaa35a0f9fa70ba"}, + {file = "pydantic_core-2.16.3-cp311-none-win32.whl", hash = "sha256:ded1c35f15c9dea16ead9bffcde9bb5c7c031bff076355dc58dcb1cb436c4721"}, + {file = "pydantic_core-2.16.3-cp311-none-win_amd64.whl", hash = "sha256:d89ca19cdd0dd5f31606a9329e309d4fcbb3df860960acec32630297d61820df"}, + {file = "pydantic_core-2.16.3-cp311-none-win_arm64.whl", hash = "sha256:6162f8d2dc27ba21027f261e4fa26f8bcb3cf9784b7f9499466a311ac284b5b9"}, + {file = "pydantic_core-2.16.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f56ae86b60ea987ae8bcd6654a887238fd53d1384f9b222ac457070b7ac4cff"}, + {file = "pydantic_core-2.16.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9bd22a2a639e26171068f8ebb5400ce2c1bc7d17959f60a3b753ae13c632975"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4204e773b4b408062960e65468d5346bdfe139247ee5f1ca2a378983e11388a2"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f651dd19363c632f4abe3480a7c87a9773be27cfe1341aef06e8759599454120"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aaf09e615a0bf98d406657e0008e4a8701b11481840be7d31755dc9f97c44053"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8e47755d8152c1ab5b55928ab422a76e2e7b22b5ed8e90a7d584268dd49e9c6b"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:500960cb3a0543a724a81ba859da816e8cf01b0e6aaeedf2c3775d12ee49cade"}, + {file = "pydantic_core-2.16.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf6204fe865da605285c34cf1172879d0314ff267b1c35ff59de7154f35fdc2e"}, + {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d33dd21f572545649f90c38c227cc8631268ba25c460b5569abebdd0ec5974ca"}, + {file = "pydantic_core-2.16.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:49d5d58abd4b83fb8ce763be7794d09b2f50f10aa65c0f0c1696c677edeb7cbf"}, + {file = "pydantic_core-2.16.3-cp312-none-win32.whl", hash = "sha256:f53aace168a2a10582e570b7736cc5bef12cae9cf21775e3eafac597e8551fbe"}, + {file = "pydantic_core-2.16.3-cp312-none-win_amd64.whl", hash = "sha256:0d32576b1de5a30d9a97f300cc6a3f4694c428d956adbc7e6e2f9cad279e45ed"}, + {file = "pydantic_core-2.16.3-cp312-none-win_arm64.whl", hash = "sha256:ec08be75bb268473677edb83ba71e7e74b43c008e4a7b1907c6d57e940bf34b6"}, + {file = "pydantic_core-2.16.3-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b1f6f5938d63c6139860f044e2538baeee6f0b251a1816e7adb6cbce106a1f01"}, + {file = "pydantic_core-2.16.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2a1ef6a36fdbf71538142ed604ad19b82f67b05749512e47f247a6ddd06afdc7"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:704d35ecc7e9c31d48926150afada60401c55efa3b46cd1ded5a01bdffaf1d48"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d937653a696465677ed583124b94a4b2d79f5e30b2c46115a68e482c6a591c8a"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c9803edf8e29bd825f43481f19c37f50d2b01899448273b3a7758441b512acf8"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72282ad4892a9fb2da25defeac8c2e84352c108705c972db82ab121d15f14e6d"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f752826b5b8361193df55afcdf8ca6a57d0232653494ba473630a83ba50d8c9"}, + {file = "pydantic_core-2.16.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4384a8f68ddb31a0b0c3deae88765f5868a1b9148939c3f4121233314ad5532c"}, + {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4b2bf78342c40b3dc830880106f54328928ff03e357935ad26c7128bbd66ce8"}, + {file = "pydantic_core-2.16.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:13dcc4802961b5f843a9385fc821a0b0135e8c07fc3d9949fd49627c1a5e6ae5"}, + {file = "pydantic_core-2.16.3-cp38-none-win32.whl", hash = "sha256:e3e70c94a0c3841e6aa831edab1619ad5c511199be94d0c11ba75fe06efe107a"}, + {file = "pydantic_core-2.16.3-cp38-none-win_amd64.whl", hash = "sha256:ecdf6bf5f578615f2e985a5e1f6572e23aa632c4bd1dc67f8f406d445ac115ed"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:bda1ee3e08252b8d41fa5537413ffdddd58fa73107171a126d3b9ff001b9b820"}, + {file = "pydantic_core-2.16.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:21b888c973e4f26b7a96491c0965a8a312e13be108022ee510248fe379a5fa23"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be0ec334369316fa73448cc8c982c01e5d2a81c95969d58b8f6e272884df0074"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b5b6079cc452a7c53dd378c6f881ac528246b3ac9aae0f8eef98498a75657805"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ee8d5f878dccb6d499ba4d30d757111847b6849ae07acdd1205fffa1fc1253c"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7233d65d9d651242a68801159763d09e9ec96e8a158dbf118dc090cd77a104c9"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6119dc90483a5cb50a1306adb8d52c66e447da88ea44f323e0ae1a5fcb14256"}, + {file = "pydantic_core-2.16.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:578114bc803a4c1ff9946d977c221e4376620a46cf78da267d946397dc9514a8"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d8f99b147ff3fcf6b3cc60cb0c39ea443884d5559a30b1481e92495f2310ff2b"}, + {file = "pydantic_core-2.16.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:4ac6b4ce1e7283d715c4b729d8f9dab9627586dafce81d9eaa009dd7f25dd972"}, + {file = "pydantic_core-2.16.3-cp39-none-win32.whl", hash = "sha256:e7774b570e61cb998490c5235740d475413a1f6de823169b4cf94e2fe9e9f6b2"}, + {file = "pydantic_core-2.16.3-cp39-none-win_amd64.whl", hash = "sha256:9091632a25b8b87b9a605ec0e61f241c456e9248bfdcf7abdf344fdb169c81cf"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:36fa178aacbc277bc6b62a2c3da95226520da4f4e9e206fdf076484363895d2c"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:dcca5d2bf65c6fb591fff92da03f94cd4f315972f97c21975398bd4bd046854a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a72fb9963cba4cd5793854fd12f4cfee731e86df140f59ff52a49b3552db241"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b60cc1a081f80a2105a59385b92d82278b15d80ebb3adb200542ae165cd7d183"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cbcc558401de90a746d02ef330c528f2e668c83350f045833543cd57ecead1ad"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:fee427241c2d9fb7192b658190f9f5fd6dfe41e02f3c1489d2ec1e6a5ab1e04a"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4cb85f693044e0f71f394ff76c98ddc1bc0953e48c061725e540396d5c8a2e1"}, + {file = "pydantic_core-2.16.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b29eeb887aa931c2fcef5aa515d9d176d25006794610c264ddc114c053bf96fe"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a425479ee40ff021f8216c9d07a6a3b54b31c8267c6e17aa88b70d7ebd0e5e5b"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5c5cbc703168d1b7a838668998308018a2718c2130595e8e190220238addc96f"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99b6add4c0b39a513d323d3b93bc173dac663c27b99860dd5bf491b240d26137"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75f76ee558751746d6a38f89d60b6228fa174e5172d143886af0f85aa306fd89"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:00ee1c97b5364b84cb0bd82e9bbf645d5e2871fb8c58059d158412fee2d33d8a"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:287073c66748f624be4cef893ef9174e3eb88fe0b8a78dc22e88eca4bc357ca6"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ed25e1835c00a332cb10c683cd39da96a719ab1dfc08427d476bce41b92531fc"}, + {file = "pydantic_core-2.16.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:86b3d0033580bd6bbe07590152007275bd7af95f98eaa5bd36f3da219dcd93da"}, + {file = "pydantic_core-2.16.3.tar.gz", hash = "sha256:1cac689f80a3abab2d3c0048b29eea5751114054f032a941a32de4c852c59cad"}, ] [package.dependencies] @@ -1017,6 +1024,7 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" name = "python-dotenv" version = "1.0.1" description = "Read key-value pairs from a .env file and set them as environment variables" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1031,6 +1039,7 @@ cli = ["click (>=5.0)"] name = "pyyaml" version = "6.0.1" description = "YAML parser and emitter for Python" +category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1039,7 +1048,6 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -1047,15 +1055,8 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -1072,7 +1073,6 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -1080,7 +1080,6 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -1090,6 +1089,7 @@ files = [ name = "regex" version = "2023.12.25" description = "Alternative regular expression module, to replace re." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1192,6 +1192,7 @@ files = [ name = "requests" version = "2.31.0" description = "Python HTTP for Humans." +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1211,71 +1212,73 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "sniffio" -version = "1.3.0" +version = "1.3.1" description = "Sniff out which async library your code is running under" +category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, - {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, + {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.27" +version = "2.0.28" description = "Database Abstraction Library" +category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "SQLAlchemy-2.0.27-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d04e579e911562f1055d26dab1868d3e0bb905db3bccf664ee8ad109f035618a"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fa67d821c1fd268a5a87922ef4940442513b4e6c377553506b9db3b83beebbd8"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c7a596d0be71b7baa037f4ac10d5e057d276f65a9a611c46970f012752ebf2d"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:954d9735ee9c3fa74874c830d089a815b7b48df6f6b6e357a74130e478dbd951"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5cd20f58c29bbf2680039ff9f569fa6d21453fbd2fa84dbdb4092f006424c2e6"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:03f448ffb731b48323bda68bcc93152f751436ad6037f18a42b7e16af9e91c07"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-win32.whl", hash = "sha256:d997c5938a08b5e172c30583ba6b8aad657ed9901fc24caf3a7152eeccb2f1b4"}, - {file = "SQLAlchemy-2.0.27-cp310-cp310-win_amd64.whl", hash = "sha256:eb15ef40b833f5b2f19eeae65d65e191f039e71790dd565c2af2a3783f72262f"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6c5bad7c60a392850d2f0fee8f355953abaec878c483dd7c3836e0089f046bf6"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3012ab65ea42de1be81fff5fb28d6db893ef978950afc8130ba707179b4284a"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbcd77c4d94b23e0753c5ed8deba8c69f331d4fd83f68bfc9db58bc8983f49cd"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d177b7e82f6dd5e1aebd24d9c3297c70ce09cd1d5d37b43e53f39514379c029c"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:680b9a36029b30cf063698755d277885d4a0eab70a2c7c6e71aab601323cba45"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1306102f6d9e625cebaca3d4c9c8f10588735ef877f0360b5cdb4fdfd3fd7131"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-win32.whl", hash = "sha256:5b78aa9f4f68212248aaf8943d84c0ff0f74efc65a661c2fc68b82d498311fd5"}, - {file = "SQLAlchemy-2.0.27-cp311-cp311-win_amd64.whl", hash = "sha256:15e19a84b84528f52a68143439d0c7a3a69befcd4f50b8ef9b7b69d2628ae7c4"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0de1263aac858f288a80b2071990f02082c51d88335a1db0d589237a3435fe71"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce850db091bf7d2a1f2fdb615220b968aeff3849007b1204bf6e3e50a57b3d32"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8dfc936870507da96aebb43e664ae3a71a7b96278382bcfe84d277b88e379b18"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4fbe6a766301f2e8a4519f4500fe74ef0a8509a59e07a4085458f26228cd7cc"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4535c49d961fe9a77392e3a630a626af5baa967172d42732b7a43496c8b28876"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0fb3bffc0ced37e5aa4ac2416f56d6d858f46d4da70c09bb731a246e70bff4d5"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-win32.whl", hash = "sha256:7f470327d06400a0aa7926b375b8e8c3c31d335e0884f509fe272b3c700a7254"}, - {file = "SQLAlchemy-2.0.27-cp312-cp312-win_amd64.whl", hash = "sha256:f9374e270e2553653d710ece397df67db9d19c60d2647bcd35bfc616f1622dcd"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e97cf143d74a7a5a0f143aa34039b4fecf11343eed66538610debc438685db4a"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7b5a3e2120982b8b6bd1d5d99e3025339f7fb8b8267551c679afb39e9c7c7f1"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e36aa62b765cf9f43a003233a8c2d7ffdeb55bc62eaa0a0380475b228663a38f"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5ada0438f5b74c3952d916c199367c29ee4d6858edff18eab783b3978d0db16d"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:b1d9d1bfd96eef3c3faedb73f486c89e44e64e40e5bfec304ee163de01cf996f"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-win32.whl", hash = "sha256:ca891af9f3289d24a490a5fde664ea04fe2f4984cd97e26de7442a4251bd4b7c"}, - {file = "SQLAlchemy-2.0.27-cp37-cp37m-win_amd64.whl", hash = "sha256:fd8aafda7cdff03b905d4426b714601c0978725a19efc39f5f207b86d188ba01"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ec1f5a328464daf7a1e4e385e4f5652dd9b1d12405075ccba1df842f7774b4fc"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ad862295ad3f644e3c2c0d8b10a988e1600d3123ecb48702d2c0f26771f1c396"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48217be1de7d29a5600b5c513f3f7664b21d32e596d69582be0a94e36b8309cb"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e56afce6431450442f3ab5973156289bd5ec33dd618941283847c9fd5ff06bf"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:611068511b5531304137bcd7fe8117c985d1b828eb86043bd944cebb7fae3910"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b86abba762ecfeea359112b2bb4490802b340850bbee1948f785141a5e020de8"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-win32.whl", hash = "sha256:30d81cc1192dc693d49d5671cd40cdec596b885b0ce3b72f323888ab1c3863d5"}, - {file = "SQLAlchemy-2.0.27-cp38-cp38-win_amd64.whl", hash = "sha256:120af1e49d614d2525ac247f6123841589b029c318b9afbfc9e2b70e22e1827d"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d07ee7793f2aeb9b80ec8ceb96bc8cc08a2aec8a1b152da1955d64e4825fcbac"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cb0845e934647232b6ff5150df37ceffd0b67b754b9fdbb095233deebcddbd4a"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fc19ae2e07a067663dd24fca55f8ed06a288384f0e6e3910420bf4b1270cc51"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b90053be91973a6fb6020a6e44382c97739736a5a9d74e08cc29b196639eb979"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2f5c9dfb0b9ab5e3a8a00249534bdd838d943ec4cfb9abe176a6c33408430230"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:33e8bde8fff203de50399b9039c4e14e42d4d227759155c21f8da4a47fc8053c"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-win32.whl", hash = "sha256:d873c21b356bfaf1589b89090a4011e6532582b3a8ea568a00e0c3aab09399dd"}, - {file = "SQLAlchemy-2.0.27-cp39-cp39-win_amd64.whl", hash = "sha256:ff2f1b7c963961d41403b650842dc2039175b906ab2093635d8319bef0b7d620"}, - {file = "SQLAlchemy-2.0.27-py3-none-any.whl", hash = "sha256:1ab4e0448018d01b142c916cc7119ca573803a4745cfe341b8f95657812700ac"}, - {file = "SQLAlchemy-2.0.27.tar.gz", hash = "sha256:86a6ed69a71fe6b88bf9331594fa390a2adda4a49b5c06f98e47bf0d392534f8"}, + {file = "SQLAlchemy-2.0.28-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0b148ab0438f72ad21cb004ce3bdaafd28465c4276af66df3b9ecd2037bf252"}, + {file = "SQLAlchemy-2.0.28-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bbda76961eb8f27e6ad3c84d1dc56d5bc61ba8f02bd20fcf3450bd421c2fcc9c"}, + {file = "SQLAlchemy-2.0.28-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feea693c452d85ea0015ebe3bb9cd15b6f49acc1a31c28b3c50f4db0f8fb1e71"}, + {file = "SQLAlchemy-2.0.28-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5da98815f82dce0cb31fd1e873a0cb30934971d15b74e0d78cf21f9e1b05953f"}, + {file = "SQLAlchemy-2.0.28-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4a5adf383c73f2d49ad15ff363a8748319ff84c371eed59ffd0127355d6ea1da"}, + {file = "SQLAlchemy-2.0.28-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:56856b871146bfead25fbcaed098269d90b744eea5cb32a952df00d542cdd368"}, + {file = "SQLAlchemy-2.0.28-cp310-cp310-win32.whl", hash = "sha256:943aa74a11f5806ab68278284a4ddd282d3fb348a0e96db9b42cb81bf731acdc"}, + {file = "SQLAlchemy-2.0.28-cp310-cp310-win_amd64.whl", hash = "sha256:c6c4da4843e0dabde41b8f2e8147438330924114f541949e6318358a56d1875a"}, + {file = "SQLAlchemy-2.0.28-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46a3d4e7a472bfff2d28db838669fc437964e8af8df8ee1e4548e92710929adc"}, + {file = "SQLAlchemy-2.0.28-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0d3dd67b5d69794cfe82862c002512683b3db038b99002171f624712fa71aeaa"}, + {file = "SQLAlchemy-2.0.28-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c61e2e41656a673b777e2f0cbbe545323dbe0d32312f590b1bc09da1de6c2a02"}, + {file = "SQLAlchemy-2.0.28-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0315d9125a38026227f559488fe7f7cee1bd2fbc19f9fd637739dc50bb6380b2"}, + {file = "SQLAlchemy-2.0.28-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:af8ce2d31679006e7b747d30a89cd3ac1ec304c3d4c20973f0f4ad58e2d1c4c9"}, + {file = "SQLAlchemy-2.0.28-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:81ba314a08c7ab701e621b7ad079c0c933c58cdef88593c59b90b996e8b58fa5"}, + {file = "SQLAlchemy-2.0.28-cp311-cp311-win32.whl", hash = "sha256:1ee8bd6d68578e517943f5ebff3afbd93fc65f7ef8f23becab9fa8fb315afb1d"}, + {file = "SQLAlchemy-2.0.28-cp311-cp311-win_amd64.whl", hash = "sha256:ad7acbe95bac70e4e687a4dc9ae3f7a2f467aa6597049eeb6d4a662ecd990bb6"}, + {file = "SQLAlchemy-2.0.28-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d3499008ddec83127ab286c6f6ec82a34f39c9817f020f75eca96155f9765097"}, + {file = "SQLAlchemy-2.0.28-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9b66fcd38659cab5d29e8de5409cdf91e9986817703e1078b2fdaad731ea66f5"}, + {file = "SQLAlchemy-2.0.28-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bea30da1e76cb1acc5b72e204a920a3a7678d9d52f688f087dc08e54e2754c67"}, + {file = "SQLAlchemy-2.0.28-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:124202b4e0edea7f08a4db8c81cc7859012f90a0d14ba2bf07c099aff6e96462"}, + {file = "SQLAlchemy-2.0.28-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:e23b88c69497a6322b5796c0781400692eca1ae5532821b39ce81a48c395aae9"}, + {file = "SQLAlchemy-2.0.28-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b6303bfd78fb3221847723104d152e5972c22367ff66edf09120fcde5ddc2e2"}, + {file = "SQLAlchemy-2.0.28-cp312-cp312-win32.whl", hash = "sha256:a921002be69ac3ab2cf0c3017c4e6a3377f800f1fca7f254c13b5f1a2f10022c"}, + {file = "SQLAlchemy-2.0.28-cp312-cp312-win_amd64.whl", hash = "sha256:b4a2cf92995635b64876dc141af0ef089c6eea7e05898d8d8865e71a326c0385"}, + {file = "SQLAlchemy-2.0.28-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e91b5e341f8c7f1e5020db8e5602f3ed045a29f8e27f7f565e0bdee3338f2c7"}, + {file = "SQLAlchemy-2.0.28-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45c7b78dfc7278329f27be02c44abc0d69fe235495bb8e16ec7ef1b1a17952db"}, + {file = "SQLAlchemy-2.0.28-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3eba73ef2c30695cb7eabcdb33bb3d0b878595737479e152468f3ba97a9c22a4"}, + {file = "SQLAlchemy-2.0.28-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5df5d1dafb8eee89384fb7a1f79128118bc0ba50ce0db27a40750f6f91aa99d5"}, + {file = "SQLAlchemy-2.0.28-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2858bbab1681ee5406650202950dc8f00e83b06a198741b7c656e63818633526"}, + {file = "SQLAlchemy-2.0.28-cp37-cp37m-win32.whl", hash = "sha256:9461802f2e965de5cff80c5a13bc945abea7edaa1d29360b485c3d2b56cdb075"}, + {file = "SQLAlchemy-2.0.28-cp37-cp37m-win_amd64.whl", hash = "sha256:a6bec1c010a6d65b3ed88c863d56b9ea5eeefdf62b5e39cafd08c65f5ce5198b"}, + {file = "SQLAlchemy-2.0.28-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:843a882cadebecc655a68bd9a5b8aa39b3c52f4a9a5572a3036fb1bb2ccdc197"}, + {file = "SQLAlchemy-2.0.28-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:dbb990612c36163c6072723523d2be7c3eb1517bbdd63fe50449f56afafd1133"}, + {file = "SQLAlchemy-2.0.28-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7e4baf9161d076b9a7e432fce06217b9bd90cfb8f1d543d6e8c4595627edb9"}, + {file = "SQLAlchemy-2.0.28-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0a5354cb4de9b64bccb6ea33162cb83e03dbefa0d892db88a672f5aad638a75"}, + {file = "SQLAlchemy-2.0.28-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:fffcc8edc508801ed2e6a4e7b0d150a62196fd28b4e16ab9f65192e8186102b6"}, + {file = "SQLAlchemy-2.0.28-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aca7b6d99a4541b2ebab4494f6c8c2f947e0df4ac859ced575238e1d6ca5716b"}, + {file = "SQLAlchemy-2.0.28-cp38-cp38-win32.whl", hash = "sha256:8c7f10720fc34d14abad5b647bc8202202f4948498927d9f1b4df0fb1cf391b7"}, + {file = "SQLAlchemy-2.0.28-cp38-cp38-win_amd64.whl", hash = "sha256:243feb6882b06a2af68ecf4bec8813d99452a1b62ba2be917ce6283852cf701b"}, + {file = "SQLAlchemy-2.0.28-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fc4974d3684f28b61b9a90fcb4c41fb340fd4b6a50c04365704a4da5a9603b05"}, + {file = "SQLAlchemy-2.0.28-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87724e7ed2a936fdda2c05dbd99d395c91ea3c96f029a033a4a20e008dd876bf"}, + {file = "SQLAlchemy-2.0.28-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68722e6a550f5de2e3cfe9da6afb9a7dd15ef7032afa5651b0f0c6b3adb8815d"}, + {file = "SQLAlchemy-2.0.28-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:328529f7c7f90adcd65aed06a161851f83f475c2f664a898af574893f55d9e53"}, + {file = "SQLAlchemy-2.0.28-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:df40c16a7e8be7413b885c9bf900d402918cc848be08a59b022478804ea076b8"}, + {file = "SQLAlchemy-2.0.28-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:426f2fa71331a64f5132369ede5171c52fd1df1bd9727ce621f38b5b24f48750"}, + {file = "SQLAlchemy-2.0.28-cp39-cp39-win32.whl", hash = "sha256:33157920b233bc542ce497a81a2e1452e685a11834c5763933b440fedd1d8e2d"}, + {file = "SQLAlchemy-2.0.28-cp39-cp39-win_amd64.whl", hash = "sha256:2f60843068e432311c886c5f03c4664acaef507cf716f6c60d5fde7265be9d7b"}, + {file = "SQLAlchemy-2.0.28-py3-none-any.whl", hash = "sha256:78bb7e8da0183a8301352d569900d9d3594c48ac21dc1c2ec6b3121ed8b6c986"}, + {file = "SQLAlchemy-2.0.28.tar.gz", hash = "sha256:dd53b6c4e6d960600fd6532b79ee28e2da489322fcf6648738134587faf767b6"}, ] [package.dependencies] @@ -1311,6 +1314,7 @@ sqlcipher = ["sqlcipher3_binary"] name = "tenacity" version = "8.2.3" description = "Retry code until it succeeds" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1325,6 +1329,7 @@ doc = ["reno", "sphinx", "tornado (>=4.5)"] name = "tiktoken" version = "0.6.0" description = "tiktoken is a fast BPE tokeniser for use with OpenAI's models" +category = "main" optional = false python-versions = ">=3.8" files = [ @@ -1377,6 +1382,7 @@ blobfile = ["blobfile (>=2)"] name = "tqdm" version = "4.66.2" description = "Fast, Extensible Progress Meter" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1395,19 +1401,21 @@ telegram = ["requests"] [[package]] name = "typing-extensions" -version = "4.9.0" +version = "4.10.0" description = "Backported and Experimental Type Hints for Python 3.8+" +category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, + {file = "typing_extensions-4.10.0-py3-none-any.whl", hash = "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475"}, + {file = "typing_extensions-4.10.0.tar.gz", hash = "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb"}, ] [[package]] name = "typing-inspect" version = "0.9.0" description = "Runtime inspection utilities for typing module." +category = "main" optional = false python-versions = "*" files = [ @@ -1421,13 +1429,14 @@ typing-extensions = ">=3.7.4" [[package]] name = "urllib3" -version = "2.2.0" +version = "2.2.1" description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.0-py3-none-any.whl", hash = "sha256:ce3711610ddce217e6d113a2732fafad960a03fd0318c91faa79481e35c11224"}, - {file = "urllib3-2.2.0.tar.gz", hash = "sha256:051d961ad0c62a94e50ecf1af379c3aba230c66c710493493560c0c223c49f20"}, + {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, + {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, ] [package.extras] @@ -1440,6 +1449,7 @@ zstd = ["zstandard (>=0.18.0)"] name = "yarl" version = "1.9.4" description = "Yet another URL library" +category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1542,4 +1552,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "ec01ccebabbdd1053e6dc7778ff629842adeff8e97200636460028a1338d656f" +content-hash = "3f4ec2cb731a6b5b3cd11481853b12565c08a6b48f9602977a1bececec308720" diff --git a/example/discord/honcho-fact-memory/pyproject.toml b/example/discord/honcho-fact-memory/pyproject.toml index f4c093e..d9d2aa7 100644 --- a/example/discord/honcho-fact-memory/pyproject.toml +++ b/example/discord/honcho-fact-memory/pyproject.toml @@ -13,7 +13,8 @@ openai = "^1.12.0" py-cord = "^2.4.1" python-dotenv = "^1.0.1" langchain-openai = "^0.0.6" -honcho-ai = "0.0.3" +honcho-ai = "0.0.5" +aiohttp = "^3.9.3" [build-system] diff --git a/example/discord/simple-roast-bot/main.py b/example/discord/simple-roast-bot/main.py index 9948eac..281f07d 100644 --- a/example/discord/simple-roast-bot/main.py +++ b/example/discord/simple-roast-bot/main.py @@ -11,7 +11,8 @@ from langchain_core.messages import AIMessage, HumanMessage from honcho import Honcho -from honcho.ext.langchain import langchain_message_converter +from honcho.ext.langchain import _messages_to_langchain +>>>>>>> main load_dotenv() @@ -67,7 +68,7 @@ async def on_message(message): session = user.create_session(location_id) history = list(session.get_messages_generator()) - chat_history = langchain_message_converter(history) + chat_history = _messages_to_langchain(history) inp = message.content session.create_message(is_user=True, content=inp) diff --git a/scripts/syncronizer.py b/scripts/syncronizer.py index 0740bb4..830f02c 100755 --- a/scripts/syncronizer.py +++ b/scripts/syncronizer.py @@ -13,6 +13,7 @@ sync_code = re.sub(r"async\s", "", source_code) sync_code = re.sub(r"await\s", "", sync_code) sync_code = re.sub(r"Async", "", sync_code) +sync_code = re.sub(r"asynchronous", "synchronous", sync_code) # Write the modified code to the destination file destination_file_path = os.path.join(this_dir, "../sdk/honcho/sync_client.py") diff --git a/sdk/CHANGELOG.md b/sdk/CHANGELOG.md index 112e65b..397baf0 100644 --- a/sdk/CHANGELOG.md +++ b/sdk/CHANGELOG.md @@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [0.0.6] — 2024-03-21 + +### Added + +* Full docstring coverage +* Code coverage tests +* Add LangChain to Honcho message converter in both directions +* Synonym `init` function that acts the same as `initialize` + ## [0.0.5] — 2024-03-14 ### Added diff --git a/sdk/docs/_static/favicon.svg b/sdk/docs/_static/favicon.svg new file mode 100644 index 0000000..6bcb833 --- /dev/null +++ b/sdk/docs/_static/favicon.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sdk/docs/conf.py b/sdk/docs/conf.py index 3798508..ecdee16 100644 --- a/sdk/docs/conf.py +++ b/sdk/docs/conf.py @@ -39,3 +39,5 @@ html_theme = "furo" html_static_path = ["_static"] + +html_favicon = "_static/favicon.svg" diff --git a/sdk/honcho/__init__.py b/sdk/honcho/__init__.py index 6ab9451..61da0ff 100644 --- a/sdk/honcho/__init__.py +++ b/sdk/honcho/__init__.py @@ -1,3 +1,5 @@ +"""Honcho is a Python client for the Honcho API.""" + from .client import ( AsyncHoncho, AsyncUser, diff --git a/sdk/honcho/cache.py b/sdk/honcho/cache.py index f9488a0..f8e6b5e 100644 --- a/sdk/honcho/cache.py +++ b/sdk/honcho/cache.py @@ -1,11 +1,18 @@ +""" +This module provides an LRU (Least Recently Used) cache implementation as part of the Honcho SDK's caching mechanisms. +""" + from collections import OrderedDict + class LRUCache: """ An implementation of a basic LRUcache that utilizes the built in OrderedDict data structure. """ + def __init__(self, capacity: int): + """Initialize the cache""" self.capacity = capacity self.cache = OrderedDict() diff --git a/sdk/honcho/client.py b/sdk/honcho/client.py index b35ec1e..268ce54 100644 --- a/sdk/honcho/client.py +++ b/sdk/honcho/client.py @@ -1,3 +1,7 @@ +""" +This module provides asynchronous client functionality for interacting with the Honcho API. +""" + from __future__ import annotations import datetime @@ -45,6 +49,7 @@ def __init__( Args: response (dict): Response from API with pagination information honcho (AsyncHoncho): Honcho Client + filter (dict, optional): Key value filter to apply to the results reverse (bool): Whether to reverse the order of the results or not """ super().__init__(response) @@ -62,6 +67,11 @@ def __init__( ] async def next(self): + """Get the next page of results + + Returns: + AsyncGetUserPage | None: Next Page of Results or None if there are no more users to retreive from a query + """ if self.page >= self.pages: return None return await self.honcho.get_users( @@ -90,7 +100,10 @@ def __init__( response (dict): Response from API with pagination information user (AsyncUser): Honcho User associated with the session reverse (bool): Whether to reverse the order of the results or not - location_id (str): ID of the location associated with the session + filter (dict, optional): Key value filter to apply to the results + location_id (str, optional): ID of the location associated with the session + is_active (bool): boolean filter for restricint results to only active + sessions """ super().__init__(response) self.user = user @@ -143,6 +156,7 @@ def __init__( Args: response (dict): Response from API with pagination information session (AsyncSession): Session the returned messages are associated with + filter (dict, optional): Key value filter to apply to the results reverse (bool): Whether to reverse the order of the results or not """ super().__init__(response) @@ -176,6 +190,8 @@ async def next(self): class AsyncGetMetamessagePage(AsyncGetPage): + """Paginated Results for Get Metamessage Requests""" + def __init__( self, response: dict, @@ -191,9 +207,10 @@ def __init__( response (dict): Response from API with pagination information session (AsyncSession): Session the returned messages are associated with + filter (dict, optional): Key value filter to apply to the results reverse (bool): Whether to reverse the order of the results - message_id (Optional[str]): ID of the message associated with the - metamessage_type (Optional[str]): Type of the metamessage + message_id (str, optional): ID of the message associated with the + metamessage_type (str, optional): Type of the metamessage """ super().__init__(response) self.session = session @@ -244,6 +261,7 @@ def __init__( response (dict): Response from API with pagination information collection (AsyncCollection): Collection the returned documents are associated with + filter (dict, optional): Key value filter to apply to the results reverse (bool): Whether to reverse the order of the results or not """ super().__init__(response) @@ -289,6 +307,7 @@ def __init__( Args: response (dict): Response from API with pagination information user (AsyncUser): Honcho Client + filter (dict, optional): Key value filter to apply to the results reverse (bool): Whether to reverse the order of the results or not """ super().__init__(response) @@ -327,7 +346,13 @@ class AsyncHoncho: """Honcho API Client Object""" def __init__(self, app_name: str, base_url: str = "https://demo.honcho.dev"): - """Constructor for Client""" + """Constructor for Client + + Args: + app_name (str): Name of the application + base_url (str): Base URL for the instance of the Honcho API defaults to + https://demo.honcho.dev + """ self.server_url: str = base_url # Base URL for the instance of the Honcho API self.client: httpx.AsyncClient = httpx.AsyncClient() self.app_name: str = app_name # Representing name of the client application @@ -335,6 +360,7 @@ def __init__(self, app_name: str, base_url: str = "https://demo.honcho.dev"): self.metadata: dict async def initialize(self): + """Run initialization tasks for the Honcho client""" res = await self.client.get( f"{self.server_url}/apps/get_or_create/{self.app_name}" ) @@ -343,9 +369,13 @@ async def initialize(self): self.app_id: uuid.UUID = data["id"] self.metadata: dict = data["metadata"] + async def init(self): + """Synonym for initialize""" + await self.initialize() + @property def base_url(self): - """Shorcut for common API prefix. made a property to prevent tampering""" + """Shortcut for common API prefix. made a property to prevent tampering""" return f"{self.server_url}/apps/{self.app_id}" async def update(self, metadata: dict): @@ -440,9 +470,11 @@ async def get_users( """Get Paginated list of users Args: - page (int, optional): The page of results to return - page_size (int, optional): The number of results to return - reverse (bool): Whether to reverse the order of the results + filter (dict, optional): The key value filter to apply + page (int): The page of results to return. Defaults to 1 + page_size (int): The number of results to return. Defaults to 50 + reverse (bool): Whether to pull from the beginning or end of the list — + latest or earliest. Defaults to False Returns: AsyncGetUserPage: Paginated list of users @@ -471,7 +503,9 @@ async def get_users_generator( all users in an app Args: - reverse (bool): Whether to reverse the order of the results + filter (dict, optional): The key value filter to apply. Defaults to None + reverse (bool): Whether to pull from the beginning or end of the list — + latest or earliest. Defaults to False Yields: AsyncUser: The User object @@ -507,7 +541,7 @@ async def get_users_generator( class AsyncUser: - """Represents a single user in an app""" + """Represents a single user in an app and associated methods""" def __init__( self, @@ -516,7 +550,18 @@ def __init__( metadata: dict, created_at: datetime.datetime, ): - """Constructor for User""" + """Constructor for User + + Args: + honcho (AsyncHoncho): The honcho object + id (uuid.UUID): The id of the user + metadata (dict): The metadata for the user + created_at (datetime.datetime): The time the user was created + + Returns: + AsyncUser: The created User object + + """ # self.base_url: str = honcho.base_url self.honcho: AsyncHoncho = honcho self.id: uuid.UUID = id @@ -530,7 +575,7 @@ def base_url(self): def __str__(self): """String representation of User""" - return f"AsyncUser(id={self.id}, app_id={self.honcho.app_id}, metadata={self.metadata})" # noqa: E501 + return f"AsyncUser(id={self.id}, app_id={self.honcho.app_id}, metadata={self.metadata})" async def update(self, metadata: dict): """Updates a user's metadata @@ -588,11 +633,13 @@ async def get_sessions( Args: location_id (str, optional): Optional Location ID representing the - location of a session - page (int, optional): The page of results to return - page_size (int, optional): The number of results to return - reverse (bool): Whether to reverse the order of the results - is_active (bool): Whether to only return active sessions + location of a session. Defaults to None + filter (dict, optional): The key value filter to apply. Defaults to None + page (int, optional): The page of results to return. Defaults to 1 + page_size (int, optional): The number of results to return. Defaults to 50 + reverse (bool): Whether to reverse the order of the results. Defaults to + False + is_active (bool): Whether to only return active sessions. Defaults to False Returns: AsyncGetSessionPage: Page or results for get_sessions query @@ -632,8 +679,10 @@ async def get_sessions_generator( Args: location_id (str, optional): Optional Location ID representing the location of a session - reverse (bool): Whether to reverse the order of the results - is_active (bool): Whether to only return active sessions + reverse (bool): Whether to reverse the order of the results. Defaults to + False + is_active (bool): Whether to only return active sessions. Defaults to False + filter (dict, optional): The key value filter to apply. Defaults to None Yields: AsyncSession: The Session object of the requested Session @@ -661,8 +710,8 @@ async def create_session( Args: location_id (str, optional): Optional Location ID representing the - location of a session - metadata (dict, optional): Optional session metadata + location of a session. Defaults to "default" + metadata (dict, optional): Optional session metadata. Defaults to None Returns: AsyncSession: The Session object of the new Session @@ -693,6 +742,7 @@ async def create_collection( Args: name (str): unique name for the collection for the user + metadata (dict, optional): Optional metadata. Defaults to None Returns: AsyncCollection: The Collection object of the new Collection @@ -745,15 +795,15 @@ async def get_collections( """Return collections associated with a user paginated Args: - page (int, optional): The page of results to return - page_size (int, optional): The number of results to return + filter (dict, optional): The key value filter to apply. Defaults to None + page (int): The page of results to return. Defaults to 1 + page_size (int): The number of results to return reverse (bool): Whether to reverse the order of the results Returns: AsyncGetCollectionPage: Page or results for get_collections query """ - # url = f"{self.base_url}/collections?page={page}&size={page_size}&reverse={reverse}" # noqa: E501 url = f"{self.base_url}/collections" params = { "page": page, @@ -775,7 +825,9 @@ async def get_collections_generator( all sessions for a user in an app Args: - reverse (bool): Whether to reverse the order of the results + filter (dict, optional): The key value filter to apply. Defaults to None + reverse (bool): Whether to reverse the order of the results. Defaults to + False Yields: AsyncCollection: The Session object of the requested Session @@ -809,7 +861,20 @@ def __init__( is_active: bool, created_at: datetime.datetime, ): - """Constructor for Session""" + """Constructor for Session + + Args: + user (AsyncUser): The user object + id (uuid.UUID): The id of the session + location_id (str): The id of the location associated with the session + metadata (dict): The metadata associated with the session + is_active (bool): Whether the session is active + created_at (datetime.datetime): When the session was created + + Returns: + AsyncSession: The Session object + + """ self.user: AsyncUser = user self.id: uuid.UUID = id self.location_id: str = location_id @@ -824,7 +889,7 @@ def base_url(self): def __str__(self): """String representation of Session""" - return f"AsyncSession(id={self.id}, location_id={self.location_id}, metadata={self.metadata}, is_active={self.is_active})" # noqa: E501 + return f"AsyncSession(id={self.id}, location_id={self.location_id}, metadata={self.metadata}, is_active={self.is_active})" @property def is_active(self): @@ -839,6 +904,7 @@ async def create_message( Args: is_user (bool): Whether the message is from the user content (str): The content of the message + metadata (dict, optional): The metadata of the message. Defaults to None Returns: Message: The Message object of the added message @@ -895,9 +961,11 @@ async def get_messages( """Get all messages for a session Args: - page (int, optional): The page of results to return - page_size (int, optional): The number of results to return per page - reverse (bool): Whether to reverse the order of the results + filter (dict, optional): The key value filter to apply. Defaults to None + page (int): The page of results to return. Defaults to 1 + page_size (int): The number of results to return per page. Defaults to 50 + reverse (bool): Whether to reverse the order of the results. Defaults to + False Returns: AsyncGetMessagePage: Page of Message objects @@ -923,6 +991,11 @@ async def get_messages_generator( """Shortcut Generator for get_messages. Generator to iterate through all messages for a session in an app + Args: + filter (dict, optional): The key value filter to apply. Defaults to None + reverse (bool): Whether to reverse the order of the results. Defaults to + False + Yields: Message: The Message object of the next Message @@ -953,6 +1026,7 @@ async def create_metamessage( message (Message): A message to associate the metamessage with metamessage_type (str): The type of the metamessage arbitrary identifier content (str): The content of the metamessage + metadata (dict, optional): The metadata of the metamessage. Defaults to None Returns: Metamessage: The Metamessage object of the added metamessage @@ -985,7 +1059,7 @@ async def get_metamessage(self, metamessage_id: uuid.UUID) -> Metamessage: """Get a specific metamessage Args: - message_id (uuid.UUID): The ID of the Message to retrieve + metamessage_id (uuid.UUID): The ID of the Metamessage to retrieve Returns: Message: The Message object @@ -1016,17 +1090,21 @@ async def get_metamessages( """Get all messages for a session Args: - metamessage_type (str, optional): The type of the metamessage - message (Message, optional): The message to associate the metamessage with - page (int, optional): The page of results to return - page_size (int, optional): The number of results to return per page - reverse (bool): Whether to reverse the order of the results + metamessage_type (str, optional): The type of the metamessage. Defaults to + None + message (Message, optional): The message to associate the metamessage with. + Defaults to None + filter (dict, optional): The key value filter to apply. Defaults to None + page (int): The page of results to return. Defaults to 1 + page_size (int): The number of results to return per page. Defaults to 50 + reverse (bool): Whether to reverse the order of the results. Defaults to + False Returns: list[dict]: List of Message objects """ - # url = f"{self.base_url}/metamessages?page={page}&size={page_size}&reverse={reverse}" # noqa: E501 + # url = f"{self.base_url}/metamessages?page={page}&size={page_size}&reverse={reverse}" url = f"{self.base_url}/metamessages" params = { "page": page, @@ -1061,8 +1139,12 @@ async def get_metamessages_generator( through all metamessages for a session in an app Args: - metamessage_type (str, optional): Optional Metamessage type to filter by - message (Message, optional): Optional Message to filter by + metamessage_type (str, optional): Optional Metamessage type to filter by. + Defaults to None + message (Message, optional): Optional Message to filter by. Defaults to None + filter (dict, optional): Optional key value filter. Defaults to None + reverse (bool): Whether to reverse the order of the results. Defaults to + False Yields: Metamessage: The next Metamessage object of the requested query @@ -1131,7 +1213,8 @@ async def update_metamessage( Args: metamessage (Metamessage): The metamessage to update - metadata (dict): The new metadata for the metamessage + metamessage_type (str, optional): The new type of the metamessage + metadata (dict, optional): The new metadata for the metamessage Returns: boolean: Whether the metamessage was successfully updated @@ -1149,13 +1232,23 @@ async def update_metamessage( return success async def close(self): - """Closes a session by marking it as inactive""" + """Closes a session by marking it as inactive. An inactive session can no longer + create new messages""" url = f"{self.base_url}" response = await self.user.honcho.client.delete(url) response.raise_for_status() self._is_active = False async def chat(self, query) -> str: + """Chat with the dialectic Honcho Agent that asynchonously reasons about users + + Args: + query (str): The query to send to the agent + + Returns: + str: The response from the agent + + """ url = f"{self.base_url}/chat" params = {"query": query} response = await self.user.honcho.client.get(url, params=params) @@ -1189,13 +1282,14 @@ def base_url(self): def __str__(self): """String representation of Collection""" - return f"AsyncCollection(id={self.id}, name={self.name}, created_at={self.created_at})" # noqa: E501 + return f"AsyncCollection(id={self.id}, name={self.name}, created_at={self.created_at})" async def update(self, name: Optional[str] = None, metadata: Optional[dict] = None): - """Update the name of the collection + """Update the name of the collection. Atleast one argument is required Args: - name (str): The new name of the document + name (str, optional): The new name of the document + metadata (dict, optional): The new metadata of the document Returns: boolean: Whether the session was successfully updated @@ -1224,7 +1318,7 @@ async def create_document(self, content: str, metadata: Optional[dict] = None): Args: content (str): The content of the document - metadata (dict): The metadata of the document + metadata (dict, optional): The metadata of the document Returns: Document: The Document object of the added document @@ -1277,14 +1371,17 @@ async def get_documents( """Get all documents for a collection Args: + filter (dict, optional): The key value filter to apply page (int, optional): The page of results to return page_size (int, optional): The number of results to return per page + reverse (bool): Whether to pull from the beginning or end of the list — + latest or earliest. Defaults to None Returns: AsyncGetDocumentPage: Page of Document objects """ - # url = f"{self.base_url}/documents?page={page}&size={page_size}&reverse={reverse}" # noqa: E501 + # url = f"{self.base_url}/documents?page={page}&size={page_size}&reverse={reverse}" url = f"{self.base_url}/documents" params = { "page": page, @@ -1305,6 +1402,11 @@ async def get_documents_generator( """Shortcut Generator for get_documents. Generator to iterate through all documents for a collection in an app + Args: + filter (dict, optional): The key value filter to apply + reverse (bool): Whether to pull from the beginning or end of the list — + latest or earliest. Defaults to None + Yields: Document: The Document object of the next Document @@ -1358,8 +1460,8 @@ async def update_document( Args: document (Document): The Document to update - metadata (dict): The metadata of the document - content (str): The content of the document + content (str, optional): The content of the document + metadata (dict, optional): The metadata of the document Returns: Document: The newly updated Document diff --git a/sdk/honcho/ext/__init__.py b/sdk/honcho/ext/__init__.py index e69de29..bd84b90 100644 --- a/sdk/honcho/ext/__init__.py +++ b/sdk/honcho/ext/__init__.py @@ -0,0 +1 @@ +"""Extensions/utilities for the Honcho Ecosystem""" diff --git a/sdk/honcho/ext/langchain.py b/sdk/honcho/ext/langchain.py index c84a0be..a27a9fb 100644 --- a/sdk/honcho/ext/langchain.py +++ b/sdk/honcho/ext/langchain.py @@ -1,14 +1,23 @@ +""" +Utilities to integrate Honcho with Langchain projects +""" + import functools import importlib -from typing import List +from typing import List, Union +from honcho import AsyncSession, Session from honcho.schemas import Message def requires_langchain(func): + """A utility to check if langchain is installed before running a function""" + @functools.wraps(func) def wrapper(*args, **kwargs): - if importlib.util.find_spec("langchain") is None: + """Check if langchain is installed before running a function""" + + if importlib.util.find_spec("langchain") is None: # type: ignore raise ImportError("Langchain must be installed to use this feature") # raise RuntimeError("langchain is not installed") return func(*args, **kwargs) @@ -17,8 +26,17 @@ def wrapper(*args, **kwargs): @requires_langchain -def langchain_message_converter(messages: List[Message]): - from langchain_core.messages import AIMessage, HumanMessage +def _messages_to_langchain(messages: List[Message]): + """Converts Honcho messages to Langchain messages + + Args: + messages (List[Message]): The list of messages to convert + + Returns: + List: The list of converted LangChain messages + + """ + from langchain_core.messages import AIMessage, HumanMessage # type: ignore new_messages = [] for message in messages: @@ -27,3 +45,34 @@ def langchain_message_converter(messages: List[Message]): else: new_messages.append(AIMessage(content=message.content)) return new_messages + + +@requires_langchain +def _langchain_to_messages( + messages, session: Union[Session, AsyncSession] +) -> List[Message]: + """Converts Langchain messages to Honcho messages and adds to appropriate session + + Args: + messages: The LangChain messages to convert + session: The session to add the messages to + + Returns: + List[Message]: The list of converted messages + + """ + from langchain_core.messages import HumanMessage # type: ignore + + messages = [] + for message in messages: + if isinstance(message, HumanMessage): + message = session.create_message( + is_user=True, content=message.content, metadata=message.metadata + ) + messages.append(message) + else: + message = session.create_message( + is_user=False, content=message.content, metadata=message.metadata + ) + messages.append(message) + return messages diff --git a/sdk/honcho/schemas.py b/sdk/honcho/schemas.py index 1a0a2fe..fba4fa0 100644 --- a/sdk/honcho/schemas.py +++ b/sdk/honcho/schemas.py @@ -1,8 +1,14 @@ -import uuid +""" +This module defines the schema classes for various entities such as Message, Metamessage, and Document. +""" + import datetime +import uuid class Message: + """Class representing a Message""" + def __init__( self, session_id: uuid.UUID, @@ -21,10 +27,13 @@ def __init__( self.created_at = created_at def __str__(self): + """String representation of Message object""" return f"Message(id={self.id}, is_user={self.is_user}, content={self.content})" class Metamessage: + """Class representing a Metamessage""" + def __init__( self, id: uuid.UUID, @@ -43,10 +52,13 @@ def __init__( self.created_at = created_at def __str__(self): + """String representation of Metamessage object""" return f"Metamessage(id={self.id}, message_id={self.message_id}, metamessage_type={self.metamessage_type}, content={self.content})" class Document: + """Class representing a Document""" + def __init__( self, id: uuid.UUID, @@ -63,4 +75,5 @@ def __init__( self.created_at = created_at def __str__(self) -> str: + """String representation of Document object""" return f"Document(id={self.id}, metadata={self.metadata}, content={self.content}, created_at={self.created_at})" diff --git a/sdk/honcho/sync_client.py b/sdk/honcho/sync_client.py index 5322812..205df5b 100644 --- a/sdk/honcho/sync_client.py +++ b/sdk/honcho/sync_client.py @@ -1,3 +1,7 @@ +""" +This module provides synchronous client functionality for interacting with the Honcho API. +""" + from __future__ import annotations import datetime @@ -45,6 +49,7 @@ def __init__( Args: response (dict): Response from API with pagination information honcho (Honcho): Honcho Client + filter (dict, optional): Key value filter to apply to the results reverse (bool): Whether to reverse the order of the results or not """ super().__init__(response) @@ -62,6 +67,11 @@ def __init__( ] def next(self): + """Get the next page of results + + Returns: + GetUserPage | None: Next Page of Results or None if there are no more users to retreive from a query + """ if self.page >= self.pages: return None return self.honcho.get_users( @@ -90,7 +100,10 @@ def __init__( response (dict): Response from API with pagination information user (User): Honcho User associated with the session reverse (bool): Whether to reverse the order of the results or not - location_id (str): ID of the location associated with the session + filter (dict, optional): Key value filter to apply to the results + location_id (str, optional): ID of the location associated with the session + is_active (bool): boolean filter for restricint results to only active + sessions """ super().__init__(response) self.user = user @@ -143,6 +156,7 @@ def __init__( Args: response (dict): Response from API with pagination information session (Session): Session the returned messages are associated with + filter (dict, optional): Key value filter to apply to the results reverse (bool): Whether to reverse the order of the results or not """ super().__init__(response) @@ -176,6 +190,8 @@ def next(self): class GetMetamessagePage(GetPage): + """Paginated Results for Get Metamessage Requests""" + def __init__( self, response: dict, @@ -191,9 +207,10 @@ def __init__( response (dict): Response from API with pagination information session (Session): Session the returned messages are associated with + filter (dict, optional): Key value filter to apply to the results reverse (bool): Whether to reverse the order of the results - message_id (Optional[str]): ID of the message associated with the - metamessage_type (Optional[str]): Type of the metamessage + message_id (str, optional): ID of the message associated with the + metamessage_type (str, optional): Type of the metamessage """ super().__init__(response) self.session = session @@ -244,6 +261,7 @@ def __init__( response (dict): Response from API with pagination information collection (Collection): Collection the returned documents are associated with + filter (dict, optional): Key value filter to apply to the results reverse (bool): Whether to reverse the order of the results or not """ super().__init__(response) @@ -289,6 +307,7 @@ def __init__( Args: response (dict): Response from API with pagination information user (User): Honcho Client + filter (dict, optional): Key value filter to apply to the results reverse (bool): Whether to reverse the order of the results or not """ super().__init__(response) @@ -327,7 +346,13 @@ class Honcho: """Honcho API Client Object""" def __init__(self, app_name: str, base_url: str = "https://demo.honcho.dev"): - """Constructor for Client""" + """Constructor for Client + + Args: + app_name (str): Name of the application + base_url (str): Base URL for the instance of the Honcho API defaults to + https://demo.honcho.dev + """ self.server_url: str = base_url # Base URL for the instance of the Honcho API self.client: httpx.Client = httpx.Client() self.app_name: str = app_name # Representing name of the client application @@ -335,6 +360,7 @@ def __init__(self, app_name: str, base_url: str = "https://demo.honcho.dev"): self.metadata: dict def initialize(self): + """Run initialization tasks for the Honcho client""" res = self.client.get( f"{self.server_url}/apps/get_or_create/{self.app_name}" ) @@ -343,9 +369,13 @@ def initialize(self): self.app_id: uuid.UUID = data["id"] self.metadata: dict = data["metadata"] + def init(self): + """Synonym for initialize""" + self.initialize() + @property def base_url(self): - """Shorcut for common API prefix. made a property to prevent tampering""" + """Shortcut for common API prefix. made a property to prevent tampering""" return f"{self.server_url}/apps/{self.app_id}" def update(self, metadata: dict): @@ -440,9 +470,11 @@ def get_users( """Get Paginated list of users Args: - page (int, optional): The page of results to return - page_size (int, optional): The number of results to return - reverse (bool): Whether to reverse the order of the results + filter (dict, optional): The key value filter to apply + page (int): The page of results to return. Defaults to 1 + page_size (int): The number of results to return. Defaults to 50 + reverse (bool): Whether to pull from the beginning or end of the list — + latest or earliest. Defaults to False Returns: GetUserPage: Paginated list of users @@ -471,7 +503,9 @@ def get_users_generator( all users in an app Args: - reverse (bool): Whether to reverse the order of the results + filter (dict, optional): The key value filter to apply. Defaults to None + reverse (bool): Whether to pull from the beginning or end of the list — + latest or earliest. Defaults to False Yields: User: The User object @@ -507,7 +541,7 @@ def get_users_generator( class User: - """Represents a single user in an app""" + """Represents a single user in an app and associated methods""" def __init__( self, @@ -516,7 +550,18 @@ def __init__( metadata: dict, created_at: datetime.datetime, ): - """Constructor for User""" + """Constructor for User + + Args: + honcho (Honcho): The honcho object + id (uuid.UUID): The id of the user + metadata (dict): The metadata for the user + created_at (datetime.datetime): The time the user was created + + Returns: + User: The created User object + + """ # self.base_url: str = honcho.base_url self.honcho: Honcho = honcho self.id: uuid.UUID = id @@ -530,7 +575,7 @@ def base_url(self): def __str__(self): """String representation of User""" - return f"User(id={self.id}, app_id={self.honcho.app_id}, metadata={self.metadata})" # noqa: E501 + return f"User(id={self.id}, app_id={self.honcho.app_id}, metadata={self.metadata})" def update(self, metadata: dict): """Updates a user's metadata @@ -588,11 +633,13 @@ def get_sessions( Args: location_id (str, optional): Optional Location ID representing the - location of a session - page (int, optional): The page of results to return - page_size (int, optional): The number of results to return - reverse (bool): Whether to reverse the order of the results - is_active (bool): Whether to only return active sessions + location of a session. Defaults to None + filter (dict, optional): The key value filter to apply. Defaults to None + page (int, optional): The page of results to return. Defaults to 1 + page_size (int, optional): The number of results to return. Defaults to 50 + reverse (bool): Whether to reverse the order of the results. Defaults to + False + is_active (bool): Whether to only return active sessions. Defaults to False Returns: GetSessionPage: Page or results for get_sessions query @@ -632,8 +679,10 @@ def get_sessions_generator( Args: location_id (str, optional): Optional Location ID representing the location of a session - reverse (bool): Whether to reverse the order of the results - is_active (bool): Whether to only return active sessions + reverse (bool): Whether to reverse the order of the results. Defaults to + False + is_active (bool): Whether to only return active sessions. Defaults to False + filter (dict, optional): The key value filter to apply. Defaults to None Yields: Session: The Session object of the requested Session @@ -661,8 +710,8 @@ def create_session( Args: location_id (str, optional): Optional Location ID representing the - location of a session - metadata (dict, optional): Optional session metadata + location of a session. Defaults to "default" + metadata (dict, optional): Optional session metadata. Defaults to None Returns: Session: The Session object of the new Session @@ -693,6 +742,7 @@ def create_collection( Args: name (str): unique name for the collection for the user + metadata (dict, optional): Optional metadata. Defaults to None Returns: Collection: The Collection object of the new Collection @@ -745,15 +795,15 @@ def get_collections( """Return collections associated with a user paginated Args: - page (int, optional): The page of results to return - page_size (int, optional): The number of results to return + filter (dict, optional): The key value filter to apply. Defaults to None + page (int): The page of results to return. Defaults to 1 + page_size (int): The number of results to return reverse (bool): Whether to reverse the order of the results Returns: GetCollectionPage: Page or results for get_collections query """ - # url = f"{self.base_url}/collections?page={page}&size={page_size}&reverse={reverse}" # noqa: E501 url = f"{self.base_url}/collections" params = { "page": page, @@ -775,7 +825,9 @@ def get_collections_generator( all sessions for a user in an app Args: - reverse (bool): Whether to reverse the order of the results + filter (dict, optional): The key value filter to apply. Defaults to None + reverse (bool): Whether to reverse the order of the results. Defaults to + False Yields: Collection: The Session object of the requested Session @@ -809,7 +861,20 @@ def __init__( is_active: bool, created_at: datetime.datetime, ): - """Constructor for Session""" + """Constructor for Session + + Args: + user (User): The user object + id (uuid.UUID): The id of the session + location_id (str): The id of the location associated with the session + metadata (dict): The metadata associated with the session + is_active (bool): Whether the session is active + created_at (datetime.datetime): When the session was created + + Returns: + Session: The Session object + + """ self.user: User = user self.id: uuid.UUID = id self.location_id: str = location_id @@ -824,7 +889,7 @@ def base_url(self): def __str__(self): """String representation of Session""" - return f"Session(id={self.id}, location_id={self.location_id}, metadata={self.metadata}, is_active={self.is_active})" # noqa: E501 + return f"Session(id={self.id}, location_id={self.location_id}, metadata={self.metadata}, is_active={self.is_active})" @property def is_active(self): @@ -839,6 +904,7 @@ def create_message( Args: is_user (bool): Whether the message is from the user content (str): The content of the message + metadata (dict, optional): The metadata of the message. Defaults to None Returns: Message: The Message object of the added message @@ -895,9 +961,11 @@ def get_messages( """Get all messages for a session Args: - page (int, optional): The page of results to return - page_size (int, optional): The number of results to return per page - reverse (bool): Whether to reverse the order of the results + filter (dict, optional): The key value filter to apply. Defaults to None + page (int): The page of results to return. Defaults to 1 + page_size (int): The number of results to return per page. Defaults to 50 + reverse (bool): Whether to reverse the order of the results. Defaults to + False Returns: GetMessagePage: Page of Message objects @@ -923,6 +991,11 @@ def get_messages_generator( """Shortcut Generator for get_messages. Generator to iterate through all messages for a session in an app + Args: + filter (dict, optional): The key value filter to apply. Defaults to None + reverse (bool): Whether to reverse the order of the results. Defaults to + False + Yields: Message: The Message object of the next Message @@ -953,6 +1026,7 @@ def create_metamessage( message (Message): A message to associate the metamessage with metamessage_type (str): The type of the metamessage arbitrary identifier content (str): The content of the metamessage + metadata (dict, optional): The metadata of the metamessage. Defaults to None Returns: Metamessage: The Metamessage object of the added metamessage @@ -985,7 +1059,7 @@ def get_metamessage(self, metamessage_id: uuid.UUID) -> Metamessage: """Get a specific metamessage Args: - message_id (uuid.UUID): The ID of the Message to retrieve + metamessage_id (uuid.UUID): The ID of the Metamessage to retrieve Returns: Message: The Message object @@ -1016,17 +1090,21 @@ def get_metamessages( """Get all messages for a session Args: - metamessage_type (str, optional): The type of the metamessage - message (Message, optional): The message to associate the metamessage with - page (int, optional): The page of results to return - page_size (int, optional): The number of results to return per page - reverse (bool): Whether to reverse the order of the results + metamessage_type (str, optional): The type of the metamessage. Defaults to + None + message (Message, optional): The message to associate the metamessage with. + Defaults to None + filter (dict, optional): The key value filter to apply. Defaults to None + page (int): The page of results to return. Defaults to 1 + page_size (int): The number of results to return per page. Defaults to 50 + reverse (bool): Whether to reverse the order of the results. Defaults to + False Returns: list[dict]: List of Message objects """ - # url = f"{self.base_url}/metamessages?page={page}&size={page_size}&reverse={reverse}" # noqa: E501 + # url = f"{self.base_url}/metamessages?page={page}&size={page_size}&reverse={reverse}" url = f"{self.base_url}/metamessages" params = { "page": page, @@ -1061,8 +1139,12 @@ def get_metamessages_generator( through all metamessages for a session in an app Args: - metamessage_type (str, optional): Optional Metamessage type to filter by - message (Message, optional): Optional Message to filter by + metamessage_type (str, optional): Optional Metamessage type to filter by. + Defaults to None + message (Message, optional): Optional Message to filter by. Defaults to None + filter (dict, optional): Optional key value filter. Defaults to None + reverse (bool): Whether to reverse the order of the results. Defaults to + False Yields: Metamessage: The next Metamessage object of the requested query @@ -1131,7 +1213,8 @@ def update_metamessage( Args: metamessage (Metamessage): The metamessage to update - metadata (dict): The new metadata for the metamessage + metamessage_type (str, optional): The new type of the metamessage + metadata (dict, optional): The new metadata for the metamessage Returns: boolean: Whether the metamessage was successfully updated @@ -1149,13 +1232,23 @@ def update_metamessage( return success def close(self): - """Closes a session by marking it as inactive""" + """Closes a session by marking it as inactive. An inactive session can no longer + create new messages""" url = f"{self.base_url}" response = self.user.honcho.client.delete(url) response.raise_for_status() self._is_active = False def chat(self, query) -> str: + """Chat with the dialectic Honcho Agent that asynchonously reasons about users + + Args: + query (str): The query to send to the agent + + Returns: + str: The response from the agent + + """ url = f"{self.base_url}/chat" params = {"query": query} response = self.user.honcho.client.get(url, params=params) @@ -1189,13 +1282,14 @@ def base_url(self): def __str__(self): """String representation of Collection""" - return f"Collection(id={self.id}, name={self.name}, created_at={self.created_at})" # noqa: E501 + return f"Collection(id={self.id}, name={self.name}, created_at={self.created_at})" def update(self, name: Optional[str] = None, metadata: Optional[dict] = None): - """Update the name of the collection + """Update the name of the collection. Atleast one argument is required Args: - name (str): The new name of the document + name (str, optional): The new name of the document + metadata (dict, optional): The new metadata of the document Returns: boolean: Whether the session was successfully updated @@ -1224,7 +1318,7 @@ def create_document(self, content: str, metadata: Optional[dict] = None): Args: content (str): The content of the document - metadata (dict): The metadata of the document + metadata (dict, optional): The metadata of the document Returns: Document: The Document object of the added document @@ -1277,14 +1371,17 @@ def get_documents( """Get all documents for a collection Args: + filter (dict, optional): The key value filter to apply page (int, optional): The page of results to return page_size (int, optional): The number of results to return per page + reverse (bool): Whether to pull from the beginning or end of the list — + latest or earliest. Defaults to None Returns: GetDocumentPage: Page of Document objects """ - # url = f"{self.base_url}/documents?page={page}&size={page_size}&reverse={reverse}" # noqa: E501 + # url = f"{self.base_url}/documents?page={page}&size={page_size}&reverse={reverse}" url = f"{self.base_url}/documents" params = { "page": page, @@ -1305,6 +1402,11 @@ def get_documents_generator( """Shortcut Generator for get_documents. Generator to iterate through all documents for a collection in an app + Args: + filter (dict, optional): The key value filter to apply + reverse (bool): Whether to pull from the beginning or end of the list — + latest or earliest. Defaults to None + Yields: Document: The Document object of the next Document @@ -1358,8 +1460,8 @@ def update_document( Args: document (Document): The Document to update - metadata (dict): The metadata of the document - content (str): The content of the document + content (str, optional): The content of the document + metadata (dict, optional): The metadata of the document Returns: Document: The newly updated Document diff --git a/sdk/poetry.lock b/sdk/poetry.lock index 61c46e2..a2c2b7c 100644 --- a/sdk/poetry.lock +++ b/sdk/poetry.lock @@ -35,6 +35,26 @@ doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphin test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"] trio = ["trio (>=0.23)"] +[[package]] +name = "attrs" +version = "23.2.0" +description = "Classes Without Boilerplate" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] + [[package]] name = "babel" version = "2.14.0" @@ -184,6 +204,21 @@ files = [ {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, ] +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +category = "dev" +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" @@ -198,64 +233,64 @@ files = [ [[package]] name = "coverage" -version = "7.4.3" +version = "7.4.4" description = "Code coverage measurement for Python" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "coverage-7.4.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8580b827d4746d47294c0e0b92854c85a92c2227927433998f0d3320ae8a71b6"}, - {file = "coverage-7.4.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:718187eeb9849fc6cc23e0d9b092bc2348821c5e1a901c9f8975df0bc785bfd4"}, - {file = "coverage-7.4.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:767b35c3a246bcb55b8044fd3a43b8cd553dd1f9f2c1eeb87a302b1f8daa0524"}, - {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae7f19afe0cce50039e2c782bff379c7e347cba335429678450b8fe81c4ef96d"}, - {file = "coverage-7.4.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba3a8aaed13770e970b3df46980cb068d1c24af1a1968b7818b69af8c4347efb"}, - {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ee866acc0861caebb4f2ab79f0b94dbfbdbfadc19f82e6e9c93930f74e11d7a0"}, - {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:506edb1dd49e13a2d4cac6a5173317b82a23c9d6e8df63efb4f0380de0fbccbc"}, - {file = "coverage-7.4.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd6545d97c98a192c5ac995d21c894b581f1fd14cf389be90724d21808b657e2"}, - {file = "coverage-7.4.3-cp310-cp310-win32.whl", hash = "sha256:f6a09b360d67e589236a44f0c39218a8efba2593b6abdccc300a8862cffc2f94"}, - {file = "coverage-7.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:18d90523ce7553dd0b7e23cbb28865db23cddfd683a38fb224115f7826de78d0"}, - {file = "coverage-7.4.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cbbe5e739d45a52f3200a771c6d2c7acf89eb2524890a4a3aa1a7fa0695d2a47"}, - {file = "coverage-7.4.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:489763b2d037b164846ebac0cbd368b8a4ca56385c4090807ff9fad817de4113"}, - {file = "coverage-7.4.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:451f433ad901b3bb00184d83fd83d135fb682d780b38af7944c9faeecb1e0bfe"}, - {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fcc66e222cf4c719fe7722a403888b1f5e1682d1679bd780e2b26c18bb648cdc"}, - {file = "coverage-7.4.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3ec74cfef2d985e145baae90d9b1b32f85e1741b04cd967aaf9cfa84c1334f3"}, - {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:abbbd8093c5229c72d4c2926afaee0e6e3140de69d5dcd918b2921f2f0c8baba"}, - {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:35eb581efdacf7b7422af677b92170da4ef34500467381e805944a3201df2079"}, - {file = "coverage-7.4.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8249b1c7334be8f8c3abcaaa996e1e4927b0e5a23b65f5bf6cfe3180d8ca7840"}, - {file = "coverage-7.4.3-cp311-cp311-win32.whl", hash = "sha256:cf30900aa1ba595312ae41978b95e256e419d8a823af79ce670835409fc02ad3"}, - {file = "coverage-7.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:18c7320695c949de11a351742ee001849912fd57e62a706d83dfc1581897fa2e"}, - {file = "coverage-7.4.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b51bfc348925e92a9bd9b2e48dad13431b57011fd1038f08316e6bf1df107d10"}, - {file = "coverage-7.4.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d6cdecaedea1ea9e033d8adf6a0ab11107b49571bbb9737175444cea6eb72328"}, - {file = "coverage-7.4.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3b2eccb883368f9e972e216c7b4c7c06cabda925b5f06dde0650281cb7666a30"}, - {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c00cdc8fa4e50e1cc1f941a7f2e3e0f26cb2a1233c9696f26963ff58445bac7"}, - {file = "coverage-7.4.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a4a8dd3dcf4cbd3165737358e4d7dfbd9d59902ad11e3b15eebb6393b0446e"}, - {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:062b0a75d9261e2f9c6d071753f7eef0fc9caf3a2c82d36d76667ba7b6470003"}, - {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:ebe7c9e67a2d15fa97b77ea6571ce5e1e1f6b0db71d1d5e96f8d2bf134303c1d"}, - {file = "coverage-7.4.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c0a120238dd71c68484f02562f6d446d736adcc6ca0993712289b102705a9a3a"}, - {file = "coverage-7.4.3-cp312-cp312-win32.whl", hash = "sha256:37389611ba54fd6d278fde86eb2c013c8e50232e38f5c68235d09d0a3f8aa352"}, - {file = "coverage-7.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:d25b937a5d9ffa857d41be042b4238dd61db888533b53bc76dc082cb5a15e914"}, - {file = "coverage-7.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:28ca2098939eabab044ad68850aac8f8db6bf0b29bc7f2887d05889b17346454"}, - {file = "coverage-7.4.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:280459f0a03cecbe8800786cdc23067a8fc64c0bd51dc614008d9c36e1659d7e"}, - {file = "coverage-7.4.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c0cdedd3500e0511eac1517bf560149764b7d8e65cb800d8bf1c63ebf39edd2"}, - {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a9babb9466fe1da12417a4aed923e90124a534736de6201794a3aea9d98484e"}, - {file = "coverage-7.4.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dec9de46a33cf2dd87a5254af095a409ea3bf952d85ad339751e7de6d962cde6"}, - {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:16bae383a9cc5abab9bb05c10a3e5a52e0a788325dc9ba8499e821885928968c"}, - {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:2c854ce44e1ee31bda4e318af1dbcfc929026d12c5ed030095ad98197eeeaed0"}, - {file = "coverage-7.4.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ce8c50520f57ec57aa21a63ea4f325c7b657386b3f02ccaedeccf9ebe27686e1"}, - {file = "coverage-7.4.3-cp38-cp38-win32.whl", hash = "sha256:708a3369dcf055c00ddeeaa2b20f0dd1ce664eeabde6623e516c5228b753654f"}, - {file = "coverage-7.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:1bf25fbca0c8d121a3e92a2a0555c7e5bc981aee5c3fdaf4bb7809f410f696b9"}, - {file = "coverage-7.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b253094dbe1b431d3a4ac2f053b6d7ede2664ac559705a704f621742e034f1f"}, - {file = "coverage-7.4.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:77fbfc5720cceac9c200054b9fab50cb2a7d79660609200ab83f5db96162d20c"}, - {file = "coverage-7.4.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6679060424faa9c11808598504c3ab472de4531c571ab2befa32f4971835788e"}, - {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4af154d617c875b52651dd8dd17a31270c495082f3d55f6128e7629658d63765"}, - {file = "coverage-7.4.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8640f1fde5e1b8e3439fe482cdc2b0bb6c329f4bb161927c28d2e8879c6029ee"}, - {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:69b9f6f66c0af29642e73a520b6fed25ff9fd69a25975ebe6acb297234eda501"}, - {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:0842571634f39016a6c03e9d4aba502be652a6e4455fadb73cd3a3a49173e38f"}, - {file = "coverage-7.4.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a78ed23b08e8ab524551f52953a8a05d61c3a760781762aac49f8de6eede8c45"}, - {file = "coverage-7.4.3-cp39-cp39-win32.whl", hash = "sha256:c0524de3ff096e15fcbfe8f056fdb4ea0bf497d584454f344d59fce069d3e6e9"}, - {file = "coverage-7.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:0209a6369ccce576b43bb227dc8322d8ef9e323d089c6f3f26a597b09cb4d2aa"}, - {file = "coverage-7.4.3-pp38.pp39.pp310-none-any.whl", hash = "sha256:7cbde573904625509a3f37b6fecea974e363460b556a627c60dc2f47e2fffa51"}, - {file = "coverage-7.4.3.tar.gz", hash = "sha256:276f6077a5c61447a48d133ed13e759c09e62aff0dc84274a68dc18660104d52"}, + {file = "coverage-7.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0be5efd5127542ef31f165de269f77560d6cdef525fffa446de6f7e9186cfb2"}, + {file = "coverage-7.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ccd341521be3d1b3daeb41960ae94a5e87abe2f46f17224ba5d6f2b8398016cf"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fa497a8ab37784fbb20ab699c246053ac294d13fc7eb40ec007a5043ec91f8"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b1a93009cb80730c9bca5d6d4665494b725b6e8e157c1cb7f2db5b4b122ea562"}, + {file = "coverage-7.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:690db6517f09336559dc0b5f55342df62370a48f5469fabf502db2c6d1cffcd2"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:09c3255458533cb76ef55da8cc49ffab9e33f083739c8bd4f58e79fecfe288f7"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8ce1415194b4a6bd0cdcc3a1dfbf58b63f910dcb7330fe15bdff542c56949f87"}, + {file = "coverage-7.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b91cbc4b195444e7e258ba27ac33769c41b94967919f10037e6355e998af255c"}, + {file = "coverage-7.4.4-cp310-cp310-win32.whl", hash = "sha256:598825b51b81c808cb6f078dcb972f96af96b078faa47af7dfcdf282835baa8d"}, + {file = "coverage-7.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:09ef9199ed6653989ebbcaacc9b62b514bb63ea2f90256e71fea3ed74bd8ff6f"}, + {file = "coverage-7.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0f9f50e7ef2a71e2fae92774c99170eb8304e3fdf9c8c3c7ae9bab3e7229c5cf"}, + {file = "coverage-7.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:623512f8ba53c422fcfb2ce68362c97945095b864cda94a92edbaf5994201083"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0513b9508b93da4e1716744ef6ebc507aff016ba115ffe8ecff744d1322a7b63"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40209e141059b9370a2657c9b15607815359ab3ef9918f0196b6fccce8d3230f"}, + {file = "coverage-7.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a2b2b78c78293782fd3767d53e6474582f62443d0504b1554370bde86cc8227"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:73bfb9c09951125d06ee473bed216e2c3742f530fc5acc1383883125de76d9cd"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1f384c3cc76aeedce208643697fb3e8437604b512255de6d18dae3f27655a384"}, + {file = "coverage-7.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:54eb8d1bf7cacfbf2a3186019bcf01d11c666bd495ed18717162f7eb1e9dd00b"}, + {file = "coverage-7.4.4-cp311-cp311-win32.whl", hash = "sha256:cac99918c7bba15302a2d81f0312c08054a3359eaa1929c7e4b26ebe41e9b286"}, + {file = "coverage-7.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:b14706df8b2de49869ae03a5ccbc211f4041750cd4a66f698df89d44f4bd30ec"}, + {file = "coverage-7.4.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:201bef2eea65e0e9c56343115ba3814e896afe6d36ffd37bab783261db430f76"}, + {file = "coverage-7.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:41c9c5f3de16b903b610d09650e5e27adbfa7f500302718c9ffd1c12cf9d6818"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d898fe162d26929b5960e4e138651f7427048e72c853607f2b200909794ed978"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ea79bb50e805cd6ac058dfa3b5c8f6c040cb87fe83de10845857f5535d1db70"}, + {file = "coverage-7.4.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce4b94265ca988c3f8e479e741693d143026632672e3ff924f25fab50518dd51"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:00838a35b882694afda09f85e469c96367daa3f3f2b097d846a7216993d37f4c"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:fdfafb32984684eb03c2d83e1e51f64f0906b11e64482df3c5db936ce3839d48"}, + {file = "coverage-7.4.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:69eb372f7e2ece89f14751fbcbe470295d73ed41ecd37ca36ed2eb47512a6ab9"}, + {file = "coverage-7.4.4-cp312-cp312-win32.whl", hash = "sha256:137eb07173141545e07403cca94ab625cc1cc6bc4c1e97b6e3846270e7e1fea0"}, + {file = "coverage-7.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:d71eec7d83298f1af3326ce0ff1d0ea83c7cb98f72b577097f9083b20bdaf05e"}, + {file = "coverage-7.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d5ae728ff3b5401cc320d792866987e7e7e880e6ebd24433b70a33b643bb0384"}, + {file = "coverage-7.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cc4f1358cb0c78edef3ed237ef2c86056206bb8d9140e73b6b89fbcfcbdd40e1"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8130a2aa2acb8788e0b56938786c33c7c98562697bf9f4c7d6e8e5e3a0501e4a"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf271892d13e43bc2b51e6908ec9a6a5094a4df1d8af0bfc360088ee6c684409"}, + {file = "coverage-7.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4cdc86d54b5da0df6d3d3a2f0b710949286094c3a6700c21e9015932b81447e"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ae71e7ddb7a413dd60052e90528f2f65270aad4b509563af6d03d53e979feafd"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:38dd60d7bf242c4ed5b38e094baf6401faa114fc09e9e6632374388a404f98e7"}, + {file = "coverage-7.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:aa5b1c1bfc28384f1f53b69a023d789f72b2e0ab1b3787aae16992a7ca21056c"}, + {file = "coverage-7.4.4-cp38-cp38-win32.whl", hash = "sha256:dfa8fe35a0bb90382837b238fff375de15f0dcdb9ae68ff85f7a63649c98527e"}, + {file = "coverage-7.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:b2991665420a803495e0b90a79233c1433d6ed77ef282e8e152a324bbbc5e0c8"}, + {file = "coverage-7.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3b799445b9f7ee8bf299cfaed6f5b226c0037b74886a4e11515e569b36fe310d"}, + {file = "coverage-7.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b4d33f418f46362995f1e9d4f3a35a1b6322cb959c31d88ae56b0298e1c22357"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aadacf9a2f407a4688d700e4ebab33a7e2e408f2ca04dbf4aef17585389eff3e"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c95949560050d04d46b919301826525597f07b33beba6187d04fa64d47ac82e"}, + {file = "coverage-7.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ff7687ca3d7028d8a5f0ebae95a6e4827c5616b31a4ee1192bdfde697db110d4"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5fc1de20b2d4a061b3df27ab9b7c7111e9a710f10dc2b84d33a4ab25065994ec"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c74880fc64d4958159fbd537a091d2a585448a8f8508bf248d72112723974cbd"}, + {file = "coverage-7.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:742a76a12aa45b44d236815d282b03cfb1de3b4323f3e4ec933acfae08e54ade"}, + {file = "coverage-7.4.4-cp39-cp39-win32.whl", hash = "sha256:d89d7b2974cae412400e88f35d86af72208e1ede1a541954af5d944a8ba46c57"}, + {file = "coverage-7.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:9ca28a302acb19b6af89e90f33ee3e1906961f94b54ea37de6737b7ca9d8827c"}, + {file = "coverage-7.4.4-pp38.pp39.pp310-none-any.whl", hash = "sha256:b2c5edc4ac10a7ef6605a966c58929ec6c1bd0917fb8c15cb3363f65aa40e677"}, + {file = "coverage-7.4.4.tar.gz", hash = "sha256:c901df83d097649e257e803be22592aedfd5182f07b3cc87d640bbb9afd50f49"}, ] [package.extras] @@ -391,14 +426,14 @@ files = [ [[package]] name = "importlib-metadata" -version = "7.0.2" +version = "7.1.0" description = "Read metadata from Python packages" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-7.0.2-py3-none-any.whl", hash = "sha256:f4bc4c0c070c490abf4ce96d715f68e95923320370efb66143df00199bb6c100"}, - {file = "importlib_metadata-7.0.2.tar.gz", hash = "sha256:198f568f3230878cb1b44fbd7975f87906c22336dba2e4a7f05278c281fbd792"}, + {file = "importlib_metadata-7.1.0-py3-none-any.whl", hash = "sha256:30962b96c0c223483ed6cc7280e7f0199feb01a0e40cfae4d4450fc6fab1f570"}, + {file = "importlib_metadata-7.1.0.tar.gz", hash = "sha256:b78938b926ee8d5f020fc4772d487045805a55ddbad2ecf21c6d60938dc7fcd2"}, ] [package.dependencies] @@ -407,7 +442,7 @@ zipp = ">=0.5" [package.extras] docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] [[package]] name = "iniconfig" @@ -421,6 +456,32 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "interrogate" +version = "1.5.0" +description = "Interrogate a codebase for docstring coverage." +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "interrogate-1.5.0-py3-none-any.whl", hash = "sha256:a4ccc5cbd727c74acc98dee6f5e79ef264c0bcfa66b68d4e123069b2af89091a"}, + {file = "interrogate-1.5.0.tar.gz", hash = "sha256:b6f325f0aa84ac3ac6779d8708264d366102226c5af7d69058cecffcff7a6d6c"}, +] + +[package.dependencies] +attrs = "*" +click = ">=7.1" +colorama = "*" +py = "*" +tabulate = "*" +toml = "*" + +[package.extras] +dev = ["cairosvg", "pre-commit", "pytest", "pytest-cov", "pytest-mock", "sphinx", "sphinx-autobuild", "wheel"] +docs = ["sphinx", "sphinx-autobuild"] +png = ["cairosvg"] +tests = ["pytest", "pytest-cov", "pytest-mock"] + [[package]] name = "jinja2" version = "3.1.3" @@ -537,6 +598,18 @@ files = [ dev = ["pre-commit", "tox"] testing = ["pytest", "pytest-benchmark"] +[[package]] +name = "py" +version = "1.11.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, + {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, +] + [[package]] name = "pygments" version = "2.17.2" @@ -578,14 +651,14 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "pytest-asyncio" -version = "0.23.5.post1" +version = "0.23.6" description = "Pytest support for asyncio" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-asyncio-0.23.5.post1.tar.gz", hash = "sha256:b9a8806bea78c21276bc34321bbf234ba1b2ea5b30d9f0ce0f2dea45e4685813"}, - {file = "pytest_asyncio-0.23.5.post1-py3-none-any.whl", hash = "sha256:30f54d27774e79ac409778889880242b0403d09cabd65b727ce90fe92dd5d80e"}, + {file = "pytest-asyncio-0.23.6.tar.gz", hash = "sha256:ffe523a89c1c222598c76856e76852b787504ddb72dd5d9b6617ffa8aa2cde5f"}, + {file = "pytest_asyncio-0.23.6-py3-none-any.whl", hash = "sha256:68516fdd1018ac57b846c9846b954f0393b26f094764a28c955eabb0536a4e8a"}, ] [package.dependencies] @@ -807,6 +880,33 @@ lint = ["docutils-stubs", "flake8", "mypy"] standalone = ["Sphinx (>=5)"] test = ["pytest"] +[[package]] +name = "tabulate" +version = "0.9.0" +description = "Pretty-print tabular data" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tabulate-0.9.0-py3-none-any.whl", hash = "sha256:024ca478df22e9340661486f85298cff5f6dcdba14f3813e8830015b9ed1948f"}, + {file = "tabulate-0.9.0.tar.gz", hash = "sha256:0095b12bf5966de529c0feb1fa08671671b3368eec77d7ef7ab114be2c068b3c"}, +] + +[package.extras] +widechars = ["wcwidth"] + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] + [[package]] name = "tomli" version = "2.0.1" @@ -851,14 +951,14 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "zipp" -version = "3.18.0" +version = "3.18.1" description = "Backport of pathlib-compatible object wrapper for zip files" category = "dev" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.18.0-py3-none-any.whl", hash = "sha256:c1bb803ed69d2cce2373152797064f7e79bc43f0a3748eb494096a867e0ebf79"}, - {file = "zipp-3.18.0.tar.gz", hash = "sha256:df8d042b02765029a09b157efd8e820451045890acc30f8e37dd2f94a060221f"}, + {file = "zipp-3.18.1-py3-none-any.whl", hash = "sha256:206f5a15f2af3dbaee80769fb7dc6f249695e940acca08dfb2a4769fe61e538b"}, + {file = "zipp-3.18.1.tar.gz", hash = "sha256:2884ed22e7d8961de1c9a05142eb69a247f120291bc0206a00a7642f09b5b715"}, ] [package.extras] @@ -868,4 +968,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p [metadata] lock-version = "2.0" python-versions = "^3.9" -content-hash = "bf46c7a976758553f5f41e0d73766388e5b93ccf383d7870106286c5c570cedf" +content-hash = "3265d992168555f7d9d60f6f03c18dc515b32de3b975290158b086d82247fefc" diff --git a/sdk/pyproject.toml b/sdk/pyproject.toml index 523bb42..a4eb01c 100644 --- a/sdk/pyproject.toml +++ b/sdk/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "honcho-ai" -version = "0.0.5" +version = "0.0.6" description = "Python Client SDK for Honcho" authors = ["Plastic Labs "] license = "AGPL-3.0" @@ -15,6 +15,7 @@ httpx = "^0.26.0" pytest = "^7.4.4" pytest-asyncio = "^0.23.4" coverage = "^7.4.3" +interrogate = "^1.5.0" [tool.poetry.group.docs.dependencies] sphinx = "^7.2.6" @@ -23,20 +24,19 @@ furo = "^2024.1.29" [tool.ruff.lint] # from https://docs.astral.sh/ruff/linter/#rule-selection example select = [ - # pycodestyle - "E", - # Pyflakes - "F", - # pyupgrade - "UP", - # flake8-bugbear - "B", - # flake8-simplify - "SIM", - # isort - "I", + "E", # pycodestyle + "F", # Pyflakes + "UP", # pyupgrade + "B", # flake8-bugbear + "SIM", # flake8-simplify + "S", # flake8-bandit + "I", # isort + "RUF", # ruff +] +ignore = [ + "UP007", # https://docs.astral.sh/ruff/rules/non-pep604-annotation/ + "E501", # line too long ] -ignore = ["UP007"] [build-system] diff --git a/sdk/tests/test_sync.py b/sdk/tests/test_sync.py index 0077ff0..fc20b11 100644 --- a/sdk/tests/test_sync.py +++ b/sdk/tests/test_sync.py @@ -251,9 +251,7 @@ def test_paginated_messages(): created_session.create_message(is_user=False, content="Hi") page_size = 7 - get_message_response = created_session.get_messages( - page=1, page_size=page_size - ) + get_message_response = created_session.get_messages(page=1, page_size=page_size) assert get_message_response is not None assert isinstance(get_message_response, GetMessagePage) @@ -448,9 +446,7 @@ def test_collection_query(): collection = user.create_collection(col_name) # Add documents - doc1 = collection.create_document( - content="The user loves puppies", metadata={} - ) + doc1 = collection.create_document(content="The user loves puppies", metadata={}) doc2 = collection.create_document(content="The user owns a dog", metadata={}) doc3 = collection.create_document(content="The user is a doctor", metadata={})