From 54fa6b5effd82516cf135ad5666066c97d9fe21b Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Fri, 25 Oct 2024 22:56:52 +0000 Subject: [PATCH 01/14] Adds function routine runner to skill library. --- .../skill-library/.vscode/settings.json | 6 +- .../skills/skill-library/pyproject.toml | 17 +- .../python/skills/skill-library/pytest.ini | 13 + .../skill-library/skill_library/__init__.py | 7 +- .../skill-library/skill_library/assistant.py | 119 +++++-- .../skill-library/skill_library/routine.py | 42 ++- .../skill_library/routine_runners/__init__.py | 3 +- .../function_routine_runner.py | 20 ++ .../instruction_routine_runner.py | 28 +- .../routine_runners/program_routine_runner.py | 22 +- .../skill_library/routine_stack.py | 101 ++++++ .../skill_library/run_context.py | 74 +++++ .../skill-library/skill_library/skill.py | 8 +- .../skill_library/skill_registry.py | 79 ++++- .../skill_library/tests/test_routine_stack.py | 56 ++++ libraries/python/skills/skill-library/uv.lock | 306 ++++++------------ 16 files changed, 607 insertions(+), 294 deletions(-) create mode 100644 libraries/python/skills/skill-library/pytest.ini create mode 100644 libraries/python/skills/skill-library/skill_library/routine_runners/function_routine_runner.py create mode 100644 libraries/python/skills/skill-library/skill_library/routine_stack.py create mode 100644 libraries/python/skills/skill-library/skill_library/run_context.py create mode 100644 libraries/python/skills/skill-library/skill_library/tests/test_routine_stack.py diff --git a/libraries/python/skills/skill-library/.vscode/settings.json b/libraries/python/skills/skill-library/.vscode/settings.json index 29b600d7..1d907497 100644 --- a/libraries/python/skills/skill-library/.vscode/settings.json +++ b/libraries/python/skills/skill-library/.vscode/settings.json @@ -20,7 +20,7 @@ "python.analysis.inlayHints.functionReturnTypes": true, "python.analysis.typeCheckingMode": "basic", "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python", - "python.testing.pytestEnabled": false, + "python.testing.pytestEnabled": true, "search.exclude": { "**/.venv": true, "**/data": true @@ -52,5 +52,7 @@ "pypdf", "runtimes", "tiktoken" - ] + ], + "python.testing.pytestArgs": ["skill_library"], + "python.testing.unittestEnabled": false } diff --git a/libraries/python/skills/skill-library/pyproject.toml b/libraries/python/skills/skill-library/pyproject.toml index 5765b75a..d3db0f91 100644 --- a/libraries/python/skills/skill-library/pyproject.toml +++ b/libraries/python/skills/skill-library/pyproject.toml @@ -6,22 +6,29 @@ authors = [{name="MADE:Explorers"}] readme = "README.md" requires-python = ">=3.11" dependencies = [ + "assistant-drive>=0.1.0", + "chat-driver>=0.1.0", + "context>=0.1.0", + "events>=0.1.0", + "function-registry>=0.1.0", "openai>=1.16.1", - "pydantic>=2.6.1", "pydantic-settings>=2.3.4", + "pydantic>=2.6.1", "python-dotenv>=1.0.1", "requests>=2.32.0", "tiktoken>=0.7.0", - "chat-driver>=0.1.0", - "context>=0.1.0", - "events>=0.1.0", - "function-registry>=0.1.0", ] [tool.uv] package = true +dev-dependencies = [ + "pytest>=8.3.1", + "pytest-asyncio>=0.23.8", + "pytest-repeat>=0.9.3", +] [tool.uv.sources] +assistant-drive = { path = "../../assistant-drive", editable = true } chat-driver = { path = "../../chat-driver", editable = true } context = { path = "../../context", editable = true } events = { path = "../../events", editable = true } diff --git a/libraries/python/skills/skill-library/pytest.ini b/libraries/python/skills/skill-library/pytest.ini new file mode 100644 index 00000000..02bae23f --- /dev/null +++ b/libraries/python/skills/skill-library/pytest.ini @@ -0,0 +1,13 @@ +# pytest.ini +[pytest] +minversion = 6.0 +addopts = -vv -rP +pythonpath = . +testpaths = **/tests +filterwarnings = + ignore::DeprecationWarning + ignore::PendingDeprecationWarning +asyncio_mode = auto +log_cli = true +log_cli_level = INFO +log_cli_format = %(asctime)s | %(levelname)-7s | %(name)s | %(message)s diff --git a/libraries/python/skills/skill-library/skill_library/__init__.py b/libraries/python/skills/skill-library/skill_library/__init__.py index 3a5fe8f8..c2538675 100644 --- a/libraries/python/skills/skill-library/skill_library/__init__.py +++ b/libraries/python/skills/skill-library/skill_library/__init__.py @@ -1,12 +1,15 @@ -from .assistant import Assistant from context import Context -from .routine import InstructionRoutine, RoutineTypes + +from .assistant import Assistant +from .routine import FunctionRoutine, InstructionRoutine, ProgramRoutine, RoutineTypes from .skill import Skill __all__ = [ "Assistant", "Context", + "FunctionRoutine", "InstructionRoutine", + "ProgramRoutine", "RoutineTypes", "Skill", ] diff --git a/libraries/python/skills/skill-library/skill_library/assistant.py b/libraries/python/skills/skill-library/skill_library/assistant.py index dae7fb53..c62aa0bb 100644 --- a/libraries/python/skills/skill-library/skill_library/assistant.py +++ b/libraries/python/skills/skill-library/skill_library/assistant.py @@ -1,12 +1,18 @@ import asyncio +from os import PathLike from typing import Any, AsyncIterator - -from chat_driver import TEXT_RESPONSE_FORMAT, ChatDriver, ChatDriverConfig, ResponseFormat -from context import Context +from uuid import uuid4 + +from assistant_drive import Drive, DriveConfig, IfDriveFileExistsBehavior +from chat_driver import ( + TEXT_RESPONSE_FORMAT, + ChatDriver, + ChatDriverConfig, + ResponseFormat, +) from events import BaseEvent, EventProtocol -from .routine import InstructionRoutine, ProgramRoutine -from .routine_runners import InstructionRoutineRunner, ProgramRoutineRunner +from .run_context import RunContext from .skill import Skill from .skill_registry import SkillRegistry @@ -17,20 +23,48 @@ def __init__( name, chat_driver_config: ChatDriverConfig, session_id: str | None = None, + skills: list[Skill] = [], + drive_root: PathLike | None = None, + metadrive_root: PathLike | None = None, ) -> None: + self.skill_registry: SkillRegistry = SkillRegistry() + self.name = name - self.skill_registry = SkillRegistry() self.chat_driver = self._register_chat_driver(chat_driver_config) + self._event_queue = asyncio.Queue() # Async queue for events self._stopped = asyncio.Event() # Event to signal when the assistant has stopped - self._running_routines = {} - self.context = Context(session_id=session_id, emit=self._emit) + if skills: + self.register_skills(skills) + + # The assistant drive can be used to read and write files to a + # particular location. The assistant drive should be used for + # assistant-specific data and not for general data storage. + self.drive: Drive = Drive( + DriveConfig( + root=drive_root or f".data/{session_id}/assistant", + default_if_exists_behavior=IfDriveFileExistsBehavior.OVERWRITE, + ) + ) + + # The assistant run context identifies the assistant session (session) + # and provides necessary utilities to be used for this particular + # assistant session. The run context is passed to the assistant's chat + # driver commands and functions and all skill actions and routines that + # are run by the assistant. + self.run_context = RunContext( + session_id=session_id or str(uuid4()), + assistant_drive=self.drive, + emit=self._emit, + run_routine=self.skill_registry.run_routine_by_name, + drive_root=metadrive_root, + ) ###################################### # Lifecycle and event handling ###################################### - async def wait(self) -> Context: + async def wait(self) -> RunContext: """ After initializing an assistant, call this method to wait for assistant events. While running, any events produced by the assistant can be @@ -39,7 +73,7 @@ async def wait(self) -> Context: """ await self._stopped.wait() - return self.context + return self.run_context def stop(self) -> None: self._stopped.set() # Signal that we are stopping @@ -59,13 +93,35 @@ async def events(self) -> AsyncIterator[EventProtocol]: await asyncio.sleep(0.005) def _emit(self, event: EventProtocol) -> None: - event.session_id = self.context.session_id + event.session_id = self.run_context.session_id self._event_queue.put_nowait(event) async def put_message(self, message: str) -> None: - """Exposed externally for sending messages to the assistant.""" - response = await self.chat_driver.respond(message) - self._emit(response) + """ + Exposed externally for sending messages to the assistant. + + If a routine is currently running, send the message to the routine. + + This is a simple way to handle conversation flows. In the future, we + would like to keep track of multiple topics and allow the assistant to + switch between them. The current idea is that we might treat a topic + like multi-tasking on a Linux system with one topic at a time being + "foreground" and the others being "background". The assistant would + decide when to switch topics based on the content of the messages. A + topic might include a subset of the conversation history, only specific + skills, etc. + + For now, though, we track only a single topic at a time. If a routine is + currently running, we send the message to the routine. Otherwise, we + send the message to the chat driver. + """ + # If a routine is running, send the message to the routine. + if self.run_context.routine_stack.peek(): + await self.step_active_routine(message) + else: + # Otherwise, send the message to the chat driver. + response = await self.chat_driver.respond(message) + self._emit(response) ###################################### # Chat interface @@ -82,6 +138,11 @@ def _register_chat_driver(self, chat_driver_config: ChatDriverConfig) -> ChatDri "These vars are like the routines' input.\n\n" "Available routines and their available vars: {routines}. " ) + + # Overwrite whatever run context was passed in with this assistant's + # actual context. + config.context = self.run_context + chat_functions = ChatFunctions(self) functions = [chat_functions.list_routines, chat_functions.run_routine] config.commands = functions @@ -136,27 +197,13 @@ def list_routines(self) -> list[str]: async def run_routine(self, name: str, vars: dict[str, Any] | None = None) -> Any: """ - Run an assistant routine. This is going to be much of the - magic of the assistant. Currently, is just runs through the - steps of a routine, but this will get much more sophisticated. - It will need to handle configuration, managing results of steps, - handling errors and retries, etc. ALso, this is where we will put - meta-cognitive functions such as having the assistant create a plan - from the routine and executing it dynamically while monitoring progress. + Run an assistant routine by name (e.g. .). """ - skill, routine = self.skill_registry.get_routine(name) - if not skill: - raise ValueError(f"Skill {name} not found.") - if not routine: - raise ValueError(f"Routine {name} not found.") + await self.skill_registry.run_routine_by_name(self.run_context, name, vars) - match routine: - case InstructionRoutine(): - runner = InstructionRoutineRunner(self) - return await runner.run(skill, routine, vars) - case ProgramRoutine(): - runner = ProgramRoutineRunner(self) - return await runner.run(skill, routine, vars) + async def step_active_routine(self, message: str) -> None: + """Run another step in the current routine.""" + await self.skill_registry.step_active_routine(self.run_context, message) class ChatFunctions: @@ -168,11 +215,13 @@ class ChatFunctions: def __init__(self, assistant: Assistant) -> None: self.assistant = assistant - def list_routines(self, context: Context) -> list[str]: + def list_routines(self, context: RunContext) -> list[str]: """Lists all the routines available in the assistant.""" return self.assistant.list_routines() - async def run_routine(self, context: Context, name: str, vars: dict[str, Any] | None = None) -> Any: + async def run_routine( + self, context: RunContext, name: str, vars: dict[str, Any] | None = None + ) -> Any: """ Run an assistant routine. """ diff --git a/libraries/python/skills/skill-library/skill_library/routine.py b/libraries/python/skills/skill-library/skill_library/routine.py index 541fa249..2c5ad675 100644 --- a/libraries/python/skills/skill-library/skill_library/routine.py +++ b/libraries/python/skills/skill-library/skill_library/routine.py @@ -1,5 +1,10 @@ -from typing import Union import re +from typing import TYPE_CHECKING, Any, Awaitable, Callable, Dict, Optional, Union + +from skill_library.run_context import RunContext + +if TYPE_CHECKING: + from skill_library.skill import Skill def find_template_vars(text: str) -> list[str]: @@ -15,9 +20,17 @@ def __init__( self, name: str, description: str, + skill: "Skill", ) -> None: self.name = name self.description = description + self.skill = skill + + def fullname(self) -> str: + return f"{self.skill.name}.{self.name}" + + def __str__(self) -> str: + return self.fullname() class InstructionRoutine(Routine): @@ -26,10 +39,12 @@ def __init__( name: str, description: str, routine: str, + skill: "Skill", ) -> None: super().__init__( name=name, description=description, + skill=skill, ) self.routine = routine @@ -44,10 +59,12 @@ def __init__( name: str, description: str, program: str, + skill: "Skill", ) -> None: super().__init__( name=name, description=description, + skill=skill, ) self.program = program @@ -56,4 +73,25 @@ def __str__(self) -> str: return f"{self.name}(vars: {template_vars}): {self.description}" -RoutineTypes = Union[InstructionRoutine, ProgramRoutine] +class FunctionRoutine(Routine): + def __init__( + self, + name: str, + description: str, + init_function: Callable[[RunContext, Optional[Dict[str, Any]]], Awaitable[None]], + step_function: Callable[[RunContext, Optional[str]], Awaitable[Optional[str]]], + skill: "Skill", + ) -> None: + super().__init__( + name=name, + description=description, + skill=skill, + ) + self.init_function = init_function + self.step_function = step_function + + def __str__(self) -> str: + return f"{self.name}: {self.description}" + + +RoutineTypes = Union[InstructionRoutine, ProgramRoutine, FunctionRoutine] diff --git a/libraries/python/skills/skill-library/skill_library/routine_runners/__init__.py b/libraries/python/skills/skill-library/skill_library/routine_runners/__init__.py index 927ef360..72a64325 100644 --- a/libraries/python/skills/skill-library/skill_library/routine_runners/__init__.py +++ b/libraries/python/skills/skill-library/skill_library/routine_runners/__init__.py @@ -1,8 +1,9 @@ from typing import Union +from .function_routine_runner import FunctionRoutineRunner from .instruction_routine_runner import InstructionRoutineRunner from .program_routine_runner import ProgramRoutineRunner -RunnerTypes = Union[InstructionRoutineRunner, ProgramRoutineRunner] +RunnerTypes = Union[InstructionRoutineRunner, ProgramRoutineRunner, FunctionRoutineRunner] __all__ = ["InstructionRoutineRunner", "RunnerTypes"] diff --git a/libraries/python/skills/skill-library/skill_library/routine_runners/function_routine_runner.py b/libraries/python/skills/skill-library/skill_library/routine_runners/function_routine_runner.py new file mode 100644 index 00000000..f57e09a1 --- /dev/null +++ b/libraries/python/skills/skill-library/skill_library/routine_runners/function_routine_runner.py @@ -0,0 +1,20 @@ +from typing import Any + +from ..routine import FunctionRoutine +from ..run_context import RunContext + + +class FunctionRoutineRunner: + def __init__(self) -> None: + pass + + async def run( + self, context: RunContext, routine: FunctionRoutine, vars: dict[str, Any] | None = None + ) -> Any: + routine.init_function(context, vars) + + async def next(self, context: RunContext, routine: FunctionRoutine, message: str) -> Any: + """ + Run the next step in the current routine. + """ + routine.step_function(context, message) diff --git a/libraries/python/skills/skill-library/skill_library/routine_runners/instruction_routine_runner.py b/libraries/python/skills/skill-library/skill_library/routine_runners/instruction_routine_runner.py index 995f2b59..49aa53dd 100644 --- a/libraries/python/skills/skill-library/skill_library/routine_runners/instruction_routine_runner.py +++ b/libraries/python/skills/skill-library/skill_library/routine_runners/instruction_routine_runner.py @@ -1,20 +1,18 @@ -from typing import TYPE_CHECKING, Any +from typing import Any from events import BaseEvent, InformationEvent from ..routine import InstructionRoutine -from ..skill import Skill - -if TYPE_CHECKING: - from ..assistant import Assistant +from ..run_context import RunContext class InstructionRoutineRunner: - def __init__(self, assistant: "Assistant") -> None: - self.skill_registry = assistant.skill_registry - self.context = assistant.context + def __init__(self) -> None: + pass - async def run(self, skill: Skill, routine: InstructionRoutine, vars: dict[str, Any] | None = None) -> Any: + async def run( + self, context: RunContext, routine: InstructionRoutine, vars: dict[str, Any] | None = None + ) -> Any: """ Run an Instruction routine. This just runs through the steps of a routine, sending each one to a skill's response endpoint. Note, this @@ -34,9 +32,15 @@ async def run(self, skill: Skill, routine: InstructionRoutine, vars: dict[str, A steps = routine.routine.split("\n") for step in steps: - self.context.emit(InformationEvent(message=f"Running step: {step}")) - response: BaseEvent = await skill.respond(message=step) + context.emit(InformationEvent(message=f"Running step: {step}")) + response: BaseEvent = await routine.skill.respond(message=step) informationEvent = InformationEvent(**response.model_dump()) - self.context.emit(informationEvent) + context.emit(informationEvent) return + + async def next(self, context: RunContext, routine: InstructionRoutine, message: str) -> Any: + """ + Run the next step in the current routine. + """ + pass diff --git a/libraries/python/skills/skill-library/skill_library/routine_runners/program_routine_runner.py b/libraries/python/skills/skill-library/skill_library/routine_runners/program_routine_runner.py index 6941daf3..4a842828 100644 --- a/libraries/python/skills/skill-library/skill_library/routine_runners/program_routine_runner.py +++ b/libraries/python/skills/skill-library/skill_library/routine_runners/program_routine_runner.py @@ -1,18 +1,16 @@ -from typing import TYPE_CHECKING, Any +from typing import Any from ..routine import ProgramRoutine -from ..skill import Skill - -if TYPE_CHECKING: - from ..assistant import Assistant +from ..run_context import RunContext class ProgramRoutineRunner: - def __init__(self, assistant: "Assistant") -> None: - self.skill_registry = assistant.skill_registry - self.context = assistant.context + def __init__(self) -> None: + pass - async def run(self, skill: Skill, routine: ProgramRoutine, vars: dict[str, Any] | None = None) -> Any: + async def run( + self, context: RunContext, routine: ProgramRoutine, vars: dict[str, Any] | None = None + ) -> Any: """ This implementation is not yet working. It is a placeholder for the future implementation of running a program routine. A program routine @@ -28,3 +26,9 @@ async def run(self, skill: Skill, routine: ProgramRoutine, vars: dict[str, Any] # TODO: execute the program. return + + async def next(self, context: RunContext, routine: ProgramRoutine, message: str) -> Any: + """ + Run the next step in the current routine. + """ + pass diff --git a/libraries/python/skills/skill-library/skill_library/routine_stack.py b/libraries/python/skills/skill-library/skill_library/routine_stack.py new file mode 100644 index 00000000..d3de4002 --- /dev/null +++ b/libraries/python/skills/skill-library/skill_library/routine_stack.py @@ -0,0 +1,101 @@ +from typing import Any, List +from uuid import uuid4 + +from assistant_drive import Drive, IfDriveFileExistsBehavior +from pydantic import BaseModel, Field + + +class RoutineFrame(BaseModel): + name: str + id: str = Field(default_factory=lambda: str(uuid4())) + state: dict[str, Any] = Field(default_factory=dict) + + +class RoutineStackData(BaseModel): + frames: List[RoutineFrame] + model_config = { + "arbitrary_types_allowed": True, + } + + +STACK_FILENAME = "routine_stack.json" + + +class RoutineStack: + def __init__(self, drive: Drive): + self.drive = drive + + async def get(self) -> List[RoutineFrame]: + try: + stack = self.drive.read_model(RoutineStackData, STACK_FILENAME) + except FileNotFoundError: + stack = RoutineStackData(frames=[]) + await self.set(stack.frames) + return stack.frames + + async def push(self, name: str) -> str: + stack = await self.get() + frame = RoutineFrame(name=name) + stack.append(frame) + await self.set(stack) + return frame.id + + async def pop(self) -> RoutineFrame | None: + stack = await self.get() + if not stack: + return None + frame = stack.pop() + await self.set(stack) + return frame + + async def peek(self) -> RoutineFrame | None: + stack = await self.get() + if not stack: + return None + return stack[-1] + + async def update(self, frame: RoutineFrame) -> None: + """Updates the top frame in the stack.""" + stack = await self.get() + stack[-1] = frame + await self.set(stack) + + async def set(self, frames: List[RoutineFrame]) -> None: + """Replaces the stack with the given list of frames.""" + self.drive.write_model( + RoutineStackData(frames=frames), + STACK_FILENAME, + if_exists=IfDriveFileExistsBehavior.OVERWRITE, + ) + + async def get_current_state(self) -> dict[str, Any]: + """Returns the state of the current routine.""" + frame = await self.peek() + if frame: + return frame.state + return {} + + async def set_current_state(self, state: dict[str, Any]) -> None: + """Updates the state of the current routine.""" + frame = await self.peek() + if frame: + frame.state = state + await self.update(frame) + + async def get_current_state_key(self, key: str) -> Any: + state = await self.get_current_state() + return state.get(key) + + async def set_current_state_key(self, key: str, value: Any) -> None: + state = await self.get_current_state() + state[key] = value + await self.set_current_state(state) + + async def clear(self) -> None: + await self.set([]) + + async def length(self) -> int: + return len(await self.get()) + + async def string(self) -> str: + return str([f"{frame.name}.{frame.id}" for frame in await self.get()]) diff --git a/libraries/python/skills/skill-library/skill_library/run_context.py b/libraries/python/skills/skill-library/skill_library/run_context.py new file mode 100644 index 00000000..f407ff10 --- /dev/null +++ b/libraries/python/skills/skill-library/skill_library/run_context.py @@ -0,0 +1,74 @@ +import logging +from os import PathLike +from typing import Any, Callable, Coroutine, Optional +from uuid import uuid4 + +from assistant_drive import Drive, DriveConfig, IfDriveFileExistsBehavior +from context import ContextProtocol +from events.events import EventProtocol + +from .routine_stack import RoutineStack + + +class LogEmitter: + """A simple event emitter that logs the event to the console. This will be + what is used unless a different emitter is provided.""" + + def emit(self, event: EventProtocol) -> None: + logging.info(event.to_json()) + + +class RunContext(ContextProtocol): + def __init__( + self, + session_id: str, + assistant_drive: Drive, + emit: Callable[[EventProtocol], None], + run_routine: Callable[ + ["RunContext", str, Optional[dict[str, Any]]], Coroutine[Any, Any, Any] + ], + drive_root: PathLike | None = None, + ) -> None: + # A session id is useful for maintaining consistent session state across all + # consumers of this context. For example, a session id can be set in an + # assistant and all functions called by that assistant can should receive + # this same context object to know which session is being used. + self.session_id: str = session_id or str(uuid4()) + + # The assistant drive is a drive object that can be used to read and + # write files to a particular location. The assistant drive should be + # used for assistant-specific data and not for general data storage. + self.assistant_drive: Drive = assistant_drive + + # A "run" is a particular series of calls within a session. The initial call will + # set the run id and all subsequent calls will use the same run id. This is useful + # for logging, metrics, and debugging. + self.run_id: str = str(uuid4()) + + # The emit function is used to send events to the event bus. The component + # that creates this context object will be responsible for instantiating an + # event bus and handling the events sent to it with this function. + self.emit = emit + + # A metadrive to be used for managing assistant metadata. This can be + # useful for storing session data, logs, and other information that + # needs to be persisted across different calls to the assistant. + self.metadrive: Drive = Drive( + DriveConfig( + root=drive_root or f".data/{session_id}/.assistant", + default_if_exists_behavior=IfDriveFileExistsBehavior.OVERWRITE, + ) + ) + + # Functions for running routines. + self.run_routine = run_routine + + # The routine stack is used to keep track of the current routine being + # run by the assistant. + self.routine_stack: RoutineStack = RoutineStack(self.metadrive) + + # Helper functions for managing state of the current routine being run. + self.state = self.routine_stack.get_current_state + self.state_key = self.routine_stack.get_current_state_key + self.update_state = self.routine_stack.set_current_state + self.update_state_key = self.routine_stack.set_current_state_key diff --git a/libraries/python/skills/skill-library/skill_library/skill.py b/libraries/python/skills/skill-library/skill_library/skill.py index b6de3da1..ac6283cc 100644 --- a/libraries/python/skills/skill-library/skill_library/skill.py +++ b/libraries/python/skills/skill-library/skill_library/skill.py @@ -1,7 +1,6 @@ from typing import Any, Callable from chat_driver import TEXT_RESPONSE_FORMAT, ChatDriver, ChatDriverConfig -from context import Context from events import BaseEvent from function_registry import FunctionRegistry from openai.types.chat.completion_create_params import ResponseFormat @@ -19,7 +18,6 @@ def __init__( self, name: str, description: str, - context: Context, chat_driver_config: ChatDriverConfig | None = None, skill_actions: list[Callable] = [], # Functions to be registered as skill actions. routines: list[RoutineTypes] = [], @@ -28,7 +26,6 @@ def __init__( # to them efficiently. self.name = name self.description = description - self.context = context self.routines: dict[str, RoutineTypes] = {routine.name: routine for routine in routines} # The routines in this skill might use actions from other skills. The dependency on @@ -44,8 +41,11 @@ def __init__( # skill subclass). self.chat_driver = ChatDriver(chat_driver_config) if chat_driver_config else None + # TODO: Configure up one of these separate from the chat driver. + self.openai_client = chat_driver_config.openai_client if chat_driver_config else None + # Register all provided actions with the action registry. - self.action_registry = FunctionRegistry(context, skill_actions) + self.action_registry = FunctionRegistry(skill_actions) # Also, register any commands provided by the chat driver. All # commands will be available to the skill. diff --git a/libraries/python/skills/skill-library/skill_library/skill_registry.py b/libraries/python/skills/skill-library/skill_library/skill_registry.py index 04d9d948..01caeffd 100644 --- a/libraries/python/skills/skill-library/skill_library/skill_registry.py +++ b/libraries/python/skills/skill-library/skill_library/skill_registry.py @@ -1,9 +1,12 @@ -from .routine import RoutineTypes -from .skill import Skill -import os import importlib +import os from typing import Any +from .routine import FunctionRoutine, InstructionRoutine, ProgramRoutine, RoutineTypes +from .routine_runners import FunctionRoutineRunner, InstructionRoutineRunner, ProgramRoutineRunner +from .run_context import RunContext +from .skill import Skill + class SkillRegistry: """ @@ -82,15 +85,79 @@ def has_routine(self, routine_name: str) -> bool: return False return skill.has_routine(routine) - def get_routine(self, routine_name: str) -> tuple[Skill | None, RoutineTypes | None]: + def get_routine(self, routine_name: str) -> RoutineTypes | None: """ Get a routine by name. """ skill_name, routine = routine_name.split(".") skill = self.get_skill(skill_name) if not skill: - return None, None - return skill, skill.get_routine(routine) + return None + return skill.get_routine(routine) + + async def run_routine_by_name( + self, context: RunContext, name: str, vars: dict[str, Any] | None = None + ) -> Any: + """ + Run an assistant routine by name (.). + """ + routine = self.get_routine(name) + if not routine: + raise ValueError(f"Routine {name} not found.") + response = await self.run_routine(context, routine, vars) + return response + + async def run_routine( + self, context: RunContext, routine: RoutineTypes, vars: dict[str, Any] | None = None + ) -> Any: + """ + Run an assistant routine. This is going to be much of the + magic of the assistant. Currently, is just runs through the + steps of a routine, but this will get much more sophisticated. + It will need to handle configuration, managing results of steps, + handling errors and retries, etc. ALso, this is where we will put + meta-cognitive functions such as having the assistant create a plan + from the routine and executing it dynamically while monitoring progress. + name = . + """ + await context.routine_stack.push(routine.fullname()) + match routine: + case InstructionRoutine(): + runner = InstructionRoutineRunner() + done = await runner.run(context, routine, vars) + case ProgramRoutine(): + runner = ProgramRoutineRunner() + done = await runner.run(context, routine, vars) + case FunctionRoutine(): + runner = FunctionRoutineRunner() + done = await runner.run(context, routine, vars) + if done: + _ = await context.routine_stack.pop() + + async def step_active_routine(self, context: RunContext, message: str) -> None: + """Run another step in the current routine.""" + routine_frame = await context.routine_stack.peek() + if not routine_frame: + raise ValueError("No routine to run.") + + routine = self.get_routine(routine_frame.name) + if not routine: + raise ValueError(f"Routine {routine_frame.name} not found.") + + match routine: + case InstructionRoutine(): + runner = InstructionRoutineRunner() + done = await runner.next(context, routine, message) + case ProgramRoutine(): + runner = ProgramRoutineRunner() + done = await runner.next(context, routine, message) + case FunctionRoutine(): + runner = FunctionRoutineRunner() + done = await runner.next(context, routine, message) + + if done: + await context.routine_stack.pop() + # TODO: Manage return state for composition in parent steps. SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) diff --git a/libraries/python/skills/skill-library/skill_library/tests/test_routine_stack.py b/libraries/python/skills/skill-library/skill_library/tests/test_routine_stack.py new file mode 100644 index 00000000..9dee2302 --- /dev/null +++ b/libraries/python/skills/skill-library/skill_library/tests/test_routine_stack.py @@ -0,0 +1,56 @@ +from assistant_drive import Drive, DriveConfig, IfDriveFileExistsBehavior +from skill_library.routine_stack import RoutineStack + + +async def test_routine_stack(): + drive = Drive( + DriveConfig( + root=".data/test", default_if_exists_behavior=IfDriveFileExistsBehavior.OVERWRITE + ) + ) + stack = RoutineStack(drive) + + await stack.clear() + + # Test push + frame_id = await stack.push("test") + assert frame_id + + # Get + frames = await stack.get() + assert frames + assert len(frames) == 1 + assert frames[0].id == frame_id + + # Test peek + frame = await stack.peek() + assert frame + assert frame.id == frame_id + assert frame.state == {} + + # Test set_current_state_key + await stack.set_current_state_key("test", "value") + value = await stack.get_current_state_key("test") + assert value == "value" + + # Test get_current_state + state = await stack.get_current_state() + assert state + assert state["test"] == "value" + + # Test set_current_state + new_state = {"new": "state"} + await stack.set_current_state(new_state) + state = await stack.get_current_state() + assert state + assert state == new_state + + # Test pop + frame = await stack.pop() + assert frame + assert frame.id == frame_id + assert await stack.length() == 0 + + # Test pop empty + frame = await stack.pop() + assert not frame diff --git a/libraries/python/skills/skill-library/uv.lock b/libraries/python/skills/skill-library/uv.lock index 845d7696..f5883a95 100644 --- a/libraries/python/skills/skill-library/uv.lock +++ b/libraries/python/skills/skill-library/uv.lock @@ -6,85 +6,12 @@ resolution-markers = [ ] [[package]] -name = "aiohappyeyeballs" -version = "2.4.3" +name = "aiofiles" +version = "24.1.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bc/69/2f6d5a019bd02e920a3417689a89887b39ad1e350b562f9955693d900c40/aiohappyeyeballs-2.4.3.tar.gz", hash = "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586", size = 21809 } +sdist = { url = "https://files.pythonhosted.org/packages/0b/03/a88171e277e8caa88a4c77808c20ebb04ba74cc4681bf1e9416c862de237/aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c", size = 30247 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/d8/120cd0fe3e8530df0539e71ba9683eade12cae103dd7543e50d15f737917/aiohappyeyeballs-2.4.3-py3-none-any.whl", hash = "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572", size = 14742 }, -] - -[[package]] -name = "aiohttp" -version = "3.10.10" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohappyeyeballs" }, - { name = "aiosignal" }, - { name = "attrs" }, - { name = "frozenlist" }, - { name = "multidict" }, - { name = "yarl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/17/7e/16e57e6cf20eb62481a2f9ce8674328407187950ccc602ad07c685279141/aiohttp-3.10.10.tar.gz", hash = "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a", size = 7542993 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/72/31/3c351d17596194e5a38ef169a4da76458952b2497b4b54645b9d483cbbb0/aiohttp-3.10.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c30a0eafc89d28e7f959281b58198a9fa5e99405f716c0289b7892ca345fe45f", size = 586501 }, - { url = "https://files.pythonhosted.org/packages/a4/a8/a559d09eb08478cdead6b7ce05b0c4a133ba27fcdfa91e05d2e62867300d/aiohttp-3.10.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:258c5dd01afc10015866114e210fb7365f0d02d9d059c3c3415382ab633fcbcb", size = 398993 }, - { url = "https://files.pythonhosted.org/packages/c5/47/7736d4174613feef61d25332c3bd1a4f8ff5591fbd7331988238a7299485/aiohttp-3.10.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:15ecd889a709b0080f02721255b3f80bb261c2293d3c748151274dfea93ac871", size = 390647 }, - { url = "https://files.pythonhosted.org/packages/27/21/e9ba192a04b7160f5a8952c98a1de7cf8072ad150fa3abd454ead1ab1d7f/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3935f82f6f4a3820270842e90456ebad3af15810cf65932bd24da4463bc0a4c", size = 1306481 }, - { url = "https://files.pythonhosted.org/packages/cf/50/f364c01c8d0def1dc34747b2470969e216f5a37c7ece00fe558810f37013/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:413251f6fcf552a33c981c4709a6bba37b12710982fec8e558ae944bfb2abd38", size = 1344652 }, - { url = "https://files.pythonhosted.org/packages/1d/c2/74f608e984e9b585649e2e83883facad6fa3fc1d021de87b20cc67e8e5ae/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1720b4f14c78a3089562b8875b53e36b51c97c51adc53325a69b79b4b48ebcb", size = 1378498 }, - { url = "https://files.pythonhosted.org/packages/9f/a7/05a48c7c0a7a80a5591b1203bf1b64ca2ed6a2050af918d09c05852dc42b/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:679abe5d3858b33c2cf74faec299fda60ea9de62916e8b67e625d65bf069a3b7", size = 1292718 }, - { url = "https://files.pythonhosted.org/packages/7d/78/a925655018747e9790350180330032e27d6e0d7ed30bde545fae42f8c49c/aiohttp-3.10.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79019094f87c9fb44f8d769e41dbb664d6e8fcfd62f665ccce36762deaa0e911", size = 1251776 }, - { url = "https://files.pythonhosted.org/packages/47/9d/85c6b69f702351d1236594745a4fdc042fc43f494c247a98dac17e004026/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe2fb38c2ed905a2582948e2de560675e9dfbee94c6d5ccdb1301c6d0a5bf092", size = 1271716 }, - { url = "https://files.pythonhosted.org/packages/7f/a7/55fc805ff9b14af818903882ece08e2235b12b73b867b521b92994c52b14/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a3f00003de6eba42d6e94fabb4125600d6e484846dbf90ea8e48a800430cc142", size = 1266263 }, - { url = "https://files.pythonhosted.org/packages/1f/ec/d2be2ca7b063e4f91519d550dbc9c1cb43040174a322470deed90b3d3333/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1bbb122c557a16fafc10354b9d99ebf2f2808a660d78202f10ba9d50786384b9", size = 1321617 }, - { url = "https://files.pythonhosted.org/packages/c9/a3/b29f7920e1cd0a9a68a45dd3eb16140074d2efb1518d2e1f3e140357dc37/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:30ca7c3b94708a9d7ae76ff281b2f47d8eaf2579cd05971b5dc681db8caac6e1", size = 1339227 }, - { url = "https://files.pythonhosted.org/packages/8a/81/34b67235c47e232d807b4bbc42ba9b927c7ce9476872372fddcfd1e41b3d/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:df9270660711670e68803107d55c2b5949c2e0f2e4896da176e1ecfc068b974a", size = 1299068 }, - { url = "https://files.pythonhosted.org/packages/04/1f/26a7fe11b6ad3184f214733428353c89ae9fe3e4f605a657f5245c5e720c/aiohttp-3.10.10-cp311-cp311-win32.whl", hash = "sha256:aafc8ee9b742ce75044ae9a4d3e60e3d918d15a4c2e08a6c3c3e38fa59b92d94", size = 362223 }, - { url = "https://files.pythonhosted.org/packages/10/91/85dcd93f64011434359ce2666bece981f08d31bc49df33261e625b28595d/aiohttp-3.10.10-cp311-cp311-win_amd64.whl", hash = "sha256:362f641f9071e5f3ee6f8e7d37d5ed0d95aae656adf4ef578313ee585b585959", size = 381576 }, - { url = "https://files.pythonhosted.org/packages/ae/99/4c5aefe5ad06a1baf206aed6598c7cdcbc7c044c46801cd0d1ecb758cae3/aiohttp-3.10.10-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9294bbb581f92770e6ed5c19559e1e99255e4ca604a22c5c6397b2f9dd3ee42c", size = 583536 }, - { url = "https://files.pythonhosted.org/packages/a9/36/8b3bc49b49cb6d2da40ee61ff15dbcc44fd345a3e6ab5bb20844df929821/aiohttp-3.10.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a8fa23fe62c436ccf23ff930149c047f060c7126eae3ccea005f0483f27b2e28", size = 395693 }, - { url = "https://files.pythonhosted.org/packages/e1/77/0aa8660dcf11fa65d61712dbb458c4989de220a844bd69778dff25f2d50b/aiohttp-3.10.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c6a5b8c7926ba5d8545c7dd22961a107526562da31a7a32fa2456baf040939f", size = 390898 }, - { url = "https://files.pythonhosted.org/packages/38/d2/b833d95deb48c75db85bf6646de0a697e7fb5d87bd27cbade4f9746b48b1/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:007ec22fbc573e5eb2fb7dec4198ef8f6bf2fe4ce20020798b2eb5d0abda6138", size = 1312060 }, - { url = "https://files.pythonhosted.org/packages/aa/5f/29fd5113165a0893de8efedf9b4737e0ba92dfcd791415a528f947d10299/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9627cc1a10c8c409b5822a92d57a77f383b554463d1884008e051c32ab1b3742", size = 1350553 }, - { url = "https://files.pythonhosted.org/packages/ad/cc/f835f74b7d344428469200105236d44606cfa448be1e7c95ca52880d9bac/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:50edbcad60d8f0e3eccc68da67f37268b5144ecc34d59f27a02f9611c1d4eec7", size = 1392646 }, - { url = "https://files.pythonhosted.org/packages/bf/fe/1332409d845ca601893bbf2d76935e0b93d41686e5f333841c7d7a4a770d/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a45d85cf20b5e0d0aa5a8dca27cce8eddef3292bc29d72dcad1641f4ed50aa16", size = 1306310 }, - { url = "https://files.pythonhosted.org/packages/e4/a1/25a7633a5a513278a9892e333501e2e69c83e50be4b57a62285fb7a008c3/aiohttp-3.10.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b00807e2605f16e1e198f33a53ce3c4523114059b0c09c337209ae55e3823a8", size = 1260255 }, - { url = "https://files.pythonhosted.org/packages/f2/39/30eafe89e0e2a06c25e4762844c8214c0c0cd0fd9ffc3471694a7986f421/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f2d4324a98062be0525d16f768a03e0bbb3b9fe301ceee99611dc9a7953124e6", size = 1271141 }, - { url = "https://files.pythonhosted.org/packages/5b/fc/33125df728b48391ef1fcb512dfb02072158cc10d041414fb79803463020/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:438cd072f75bb6612f2aca29f8bd7cdf6e35e8f160bc312e49fbecab77c99e3a", size = 1280244 }, - { url = "https://files.pythonhosted.org/packages/3b/61/e42bf2c2934b5caa4e2ec0b5e5fd86989adb022b5ee60c2572a9d77cf6fe/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:baa42524a82f75303f714108fea528ccacf0386af429b69fff141ffef1c534f9", size = 1316805 }, - { url = "https://files.pythonhosted.org/packages/18/32/f52a5e2ae9ad3bba10e026a63a7a23abfa37c7d97aeeb9004eaa98df3ce3/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a7d8d14fe962153fc681f6366bdec33d4356f98a3e3567782aac1b6e0e40109a", size = 1343930 }, - { url = "https://files.pythonhosted.org/packages/05/be/6a403b464dcab3631fe8e27b0f1d906d9e45c5e92aca97ee007e5a895560/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205", size = 1306186 }, - { url = "https://files.pythonhosted.org/packages/8e/fd/bb50fe781068a736a02bf5c7ad5f3ab53e39f1d1e63110da6d30f7605edc/aiohttp-3.10.10-cp312-cp312-win32.whl", hash = "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628", size = 359289 }, - { url = "https://files.pythonhosted.org/packages/70/9e/5add7e240f77ef67c275c82cc1d08afbca57b77593118c1f6e920ae8ad3f/aiohttp-3.10.10-cp312-cp312-win_amd64.whl", hash = "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf", size = 379313 }, - { url = "https://files.pythonhosted.org/packages/b1/eb/618b1b76c7fe8082a71c9d62e3fe84c5b9af6703078caa9ec57850a12080/aiohttp-3.10.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28", size = 576114 }, - { url = "https://files.pythonhosted.org/packages/aa/37/3126995d7869f8b30d05381b81a2d4fb4ec6ad313db788e009bc6d39c211/aiohttp-3.10.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d", size = 391901 }, - { url = "https://files.pythonhosted.org/packages/3e/f2/8fdfc845be1f811c31ceb797968523813f8e1263ee3e9120d61253f6848f/aiohttp-3.10.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79", size = 387418 }, - { url = "https://files.pythonhosted.org/packages/60/d5/33d2061d36bf07e80286e04b7e0a4de37ce04b5ebfed72dba67659a05250/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e", size = 1287073 }, - { url = "https://files.pythonhosted.org/packages/00/52/affb55be16a4747740bd630b4c002dac6c5eac42f9bb64202fc3cf3f1930/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6", size = 1323612 }, - { url = "https://files.pythonhosted.org/packages/94/f2/cddb69b975387daa2182a8442566971d6410b8a0179bb4540d81c97b1611/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42", size = 1368406 }, - { url = "https://files.pythonhosted.org/packages/c1/e4/afba7327da4d932da8c6e29aecaf855f9d52dace53ac15bfc8030a246f1b/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e", size = 1282761 }, - { url = "https://files.pythonhosted.org/packages/9f/6b/364856faa0c9031ea76e24ef0f7fef79cddd9fa8e7dba9a1771c6acc56b5/aiohttp-3.10.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc", size = 1236518 }, - { url = "https://files.pythonhosted.org/packages/46/af/c382846f8356fe64a7b5908bb9b477457aa23b71be7ed551013b7b7d4d87/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a", size = 1250344 }, - { url = "https://files.pythonhosted.org/packages/87/53/294f87fc086fd0772d0ab82497beb9df67f0f27a8b3dd5742a2656db2bc6/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414", size = 1248956 }, - { url = "https://files.pythonhosted.org/packages/86/30/7d746717fe11bdfefb88bb6c09c5fc985d85c4632da8bb6018e273899254/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3", size = 1293379 }, - { url = "https://files.pythonhosted.org/packages/48/b9/45d670a834458db67a24258e9139ba61fa3bd7d69b98ecf3650c22806f8f/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67", size = 1320108 }, - { url = "https://files.pythonhosted.org/packages/72/8c/804bb2e837a175635d2000a0659eafc15b2e9d92d3d81c8f69e141ecd0b0/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b", size = 1281546 }, - { url = "https://files.pythonhosted.org/packages/89/c0/862e6a9de3d6eeb126cd9d9ea388243b70df9b871ce1a42b193b7a4a77fc/aiohttp-3.10.10-cp313-cp313-win32.whl", hash = "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8", size = 357516 }, - { url = "https://files.pythonhosted.org/packages/ae/63/3e1aee3e554263f3f1011cca50d78a4894ae16ce99bf78101ac3a2f0ef74/aiohttp-3.10.10-cp313-cp313-win_amd64.whl", hash = "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151", size = 376785 }, -] - -[[package]] -name = "aiosignal" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "frozenlist" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ae/67/0952ed97a9793b4958e5736f6d2b346b414a2cd63e82d05940032f45b32f/aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", size = 19422 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17", size = 7617 }, + { url = "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5", size = 15896 }, ] [[package]] @@ -110,38 +37,30 @@ wheels = [ ] [[package]] -name = "asgi-correlation-id" -version = "4.3.4" -source = { registry = "https://pypi.org/simple" } +name = "assistant-drive" +version = "0.1.0" +source = { editable = "../../assistant-drive" } dependencies = [ - { name = "packaging" }, - { name = "starlette" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/ff/a6538245ac1eaa7733ec6740774e9d5add019e2c63caa29e758c16c0afdd/asgi_correlation_id-4.3.4.tar.gz", hash = "sha256:ea6bc310380373cb9f731dc2e8b2b6fb978a76afe33f7a2384f697b8d6cd811d", size = 20075 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/ab/6936e2663c47a926e0659437b9333ad87d1ff49b1375d239026e0a268eba/asgi_correlation_id-4.3.4-py3-none-any.whl", hash = "sha256:36ce69b06c7d96b4acb89c7556a4c4f01a972463d3d49c675026cbbd08e9a0a2", size = 15262 }, + { name = "aiofiles" }, + { name = "context" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, ] -[[package]] -name = "attrs" -version = "24.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fc/0f/aafca9af9315aee06a89ffde799a10a582fe8de76c563ee80bbcdc08b3fb/attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", size = 792678 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2", size = 63001 }, +[package.metadata] +requires-dist = [ + { name = "aiofiles", specifier = ">=24.1.0" }, + { name = "context", editable = "../../context" }, + { name = "pydantic", specifier = ">=2.6.1" }, + { name = "pydantic-settings", specifier = ">=2.5.2" }, ] -[[package]] -name = "azure-ai-contentsafety" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "azure-core" }, - { name = "isodate" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/08/e9/c069efade0e4976d96208306f1cf0803838cdb0b60e00a2a96bd20806bff/azure-ai-contentsafety-1.0.0.tar.gz", hash = "sha256:052731bd1419a720fa00910f46bf3428c4e5bd05280da7393d0c8106d46cc6d7", size = 63806 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/36/39/cbb3ff28ad09434a1be7803b2846077bc3b23a8232beb489962fc818fe21/azure_ai_contentsafety-1.0.0-py3-none-any.whl", hash = "sha256:e1c5574a541f9290fdd071d23535e14b1f463af231a6f0ac0f917e125f0463cf", size = 61328 }, +[package.metadata.requires-dev] +dev = [ + { name = "ipykernel", specifier = ">=6.29.5" }, + { name = "pytest", specifier = ">=8.3.1" }, + { name = "pytest-asyncio", specifier = ">=0.23.8" }, + { name = "pytest-repeat", specifier = ">=0.9.3" }, ] [[package]] @@ -295,6 +214,7 @@ dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, + { name = "python-liquid" }, { name = "requests" }, { name = "tiktoken" }, ] @@ -310,6 +230,7 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, + { name = "python-liquid", specifier = ">=1.12.1" }, { name = "requests", specifier = ">=2.32.0" }, { name = "tiktoken", specifier = ">=0.7.0" }, ] @@ -649,24 +570,12 @@ wheels = [ ] [[package]] -name = "isodate" -version = "0.7.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/4d/e940025e2ce31a8ce1202635910747e5a87cc3a6a6bb2d00973375014749/isodate-0.7.2.tar.gz", hash = "sha256:4cd1aa0f43ca76f4a6c6c0292a85f40b35ec2e43e315b59f06e6d32171a953e6", size = 29705 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/15/aa/0aca39a37d3c7eb941ba736ede56d689e7be91cab5d9ca846bde3999eba6/isodate-0.7.2-py3-none-any.whl", hash = "sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15", size = 22320 }, -] - -[[package]] -name = "jinja2" -version = "3.1.4" +name = "iniconfig" +version = "2.0.0" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ed/55/39036716d19cab0747a5020fc7e907f362fbf48c984b14e62127f7e68e5d/jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", size = 240245 } +sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } wheels = [ - { url = "https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d", size = 133271 }, + { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, ] [[package]] @@ -870,38 +779,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/08/9f22356d4fbd273f734db1e6663b7ca6987943080567f5580471022e57ca/openai-1.51.0-py3-none-any.whl", hash = "sha256:d9affafb7e51e5a27dce78589d4964ce4d6f6d560307265933a94b2e3f3c5d2c", size = 383533 }, ] -[[package]] -name = "openai-client" -version = "0.1.0" -source = { editable = "../../openai-client" } -dependencies = [ - { name = "azure-ai-contentsafety" }, - { name = "azure-core", extra = ["aio"] }, - { name = "azure-identity" }, - { name = "function-registry" }, - { name = "openai" }, - { name = "pillow" }, - { name = "python-liquid" }, - { name = "semantic-workbench-assistant" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, - { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "function-registry", editable = "../../function-registry" }, - { name = "openai", specifier = ">=1.3.9" }, - { name = "pillow", specifier = ">=11.0.0" }, - { name = "python-liquid", specifier = ">=1.12.1" }, - { name = "semantic-workbench-assistant", editable = "../../semantic-workbench-assistant" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[package.metadata.requires-dev] -dev = [{ name = "pytest", specifier = ">=8.3.3" }] - [[package]] name = "packaging" version = "24.1" @@ -912,52 +789,12 @@ wheels = [ ] [[package]] -name = "pillow" -version = "11.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/26/0d95c04c868f6bdb0c447e3ee2de5564411845e36a858cfd63766bc7b563/pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739", size = 46737780 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f0/eb/f7e21b113dd48a9c97d364e0915b3988c6a0b6207652f5a92372871b7aa4/pillow-11.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1c1d72714f429a521d8d2d018badc42414c3077eb187a59579f28e4270b4b0fc", size = 3154705 }, - { url = "https://files.pythonhosted.org/packages/25/b3/2b54a1d541accebe6bd8b1358b34ceb2c509f51cb7dcda8687362490da5b/pillow-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:499c3a1b0d6fc8213519e193796eb1a86a1be4b1877d678b30f83fd979811d1a", size = 2979222 }, - { url = "https://files.pythonhosted.org/packages/20/12/1a41eddad8265c5c19dda8fb6c269ce15ee25e0b9f8f26286e6202df6693/pillow-11.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8b2351c85d855293a299038e1f89db92a2f35e8d2f783489c6f0b2b5f3fe8a3", size = 4190220 }, - { url = "https://files.pythonhosted.org/packages/a9/9b/8a8c4d07d77447b7457164b861d18f5a31ae6418ef5c07f6f878fa09039a/pillow-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4dba50cfa56f910241eb7f883c20f1e7b1d8f7d91c750cd0b318bad443f4d5", size = 4291399 }, - { url = "https://files.pythonhosted.org/packages/fc/e4/130c5fab4a54d3991129800dd2801feeb4b118d7630148cd67f0e6269d4c/pillow-11.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5ddbfd761ee00c12ee1be86c9c0683ecf5bb14c9772ddbd782085779a63dd55b", size = 4202709 }, - { url = "https://files.pythonhosted.org/packages/39/63/b3fc299528d7df1f678b0666002b37affe6b8751225c3d9c12cf530e73ed/pillow-11.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa", size = 4372556 }, - { url = "https://files.pythonhosted.org/packages/c6/a6/694122c55b855b586c26c694937d36bb8d3b09c735ff41b2f315c6e66a10/pillow-11.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b4fd7bd29610a83a8c9b564d457cf5bd92b4e11e79a4ee4716a63c959699b306", size = 4287187 }, - { url = "https://files.pythonhosted.org/packages/ba/a9/f9d763e2671a8acd53d29b1e284ca298bc10a595527f6be30233cdb9659d/pillow-11.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cb929ca942d0ec4fac404cbf520ee6cac37bf35be479b970c4ffadf2b6a1cad9", size = 4418468 }, - { url = "https://files.pythonhosted.org/packages/6e/0e/b5cbad2621377f11313a94aeb44ca55a9639adabcaaa073597a1925f8c26/pillow-11.0.0-cp311-cp311-win32.whl", hash = "sha256:006bcdd307cc47ba43e924099a038cbf9591062e6c50e570819743f5607404f5", size = 2249249 }, - { url = "https://files.pythonhosted.org/packages/dc/83/1470c220a4ff06cd75fc609068f6605e567ea51df70557555c2ab6516b2c/pillow-11.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:52a2d8323a465f84faaba5236567d212c3668f2ab53e1c74c15583cf507a0291", size = 2566769 }, - { url = "https://files.pythonhosted.org/packages/52/98/def78c3a23acee2bcdb2e52005fb2810ed54305602ec1bfcfab2bda6f49f/pillow-11.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:16095692a253047fe3ec028e951fa4221a1f3ed3d80c397e83541a3037ff67c9", size = 2254611 }, - { url = "https://files.pythonhosted.org/packages/1c/a3/26e606ff0b2daaf120543e537311fa3ae2eb6bf061490e4fea51771540be/pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923", size = 3147642 }, - { url = "https://files.pythonhosted.org/packages/4f/d5/1caabedd8863526a6cfa44ee7a833bd97f945dc1d56824d6d76e11731939/pillow-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903", size = 2978999 }, - { url = "https://files.pythonhosted.org/packages/d9/ff/5a45000826a1aa1ac6874b3ec5a856474821a1b59d838c4f6ce2ee518fe9/pillow-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4", size = 4196794 }, - { url = "https://files.pythonhosted.org/packages/9d/21/84c9f287d17180f26263b5f5c8fb201de0f88b1afddf8a2597a5c9fe787f/pillow-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f", size = 4300762 }, - { url = "https://files.pythonhosted.org/packages/84/39/63fb87cd07cc541438b448b1fed467c4d687ad18aa786a7f8e67b255d1aa/pillow-11.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9", size = 4210468 }, - { url = "https://files.pythonhosted.org/packages/7f/42/6e0f2c2d5c60f499aa29be14f860dd4539de322cd8fb84ee01553493fb4d/pillow-11.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7", size = 4381824 }, - { url = "https://files.pythonhosted.org/packages/31/69/1ef0fb9d2f8d2d114db982b78ca4eeb9db9a29f7477821e160b8c1253f67/pillow-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6", size = 4296436 }, - { url = "https://files.pythonhosted.org/packages/44/ea/dad2818c675c44f6012289a7c4f46068c548768bc6c7f4e8c4ae5bbbc811/pillow-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc", size = 4429714 }, - { url = "https://files.pythonhosted.org/packages/af/3a/da80224a6eb15bba7a0dcb2346e2b686bb9bf98378c0b4353cd88e62b171/pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6", size = 2249631 }, - { url = "https://files.pythonhosted.org/packages/57/97/73f756c338c1d86bb802ee88c3cab015ad7ce4b838f8a24f16b676b1ac7c/pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47", size = 2567533 }, - { url = "https://files.pythonhosted.org/packages/0b/30/2b61876e2722374558b871dfbfcbe4e406626d63f4f6ed92e9c8e24cac37/pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25", size = 2254890 }, - { url = "https://files.pythonhosted.org/packages/63/24/e2e15e392d00fcf4215907465d8ec2a2f23bcec1481a8ebe4ae760459995/pillow-11.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699", size = 3147300 }, - { url = "https://files.pythonhosted.org/packages/43/72/92ad4afaa2afc233dc44184adff289c2e77e8cd916b3ddb72ac69495bda3/pillow-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38", size = 2978742 }, - { url = "https://files.pythonhosted.org/packages/9e/da/c8d69c5bc85d72a8523fe862f05ababdc52c0a755cfe3d362656bb86552b/pillow-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2", size = 4194349 }, - { url = "https://files.pythonhosted.org/packages/cd/e8/686d0caeed6b998351d57796496a70185376ed9c8ec7d99e1d19ad591fc6/pillow-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2", size = 4298714 }, - { url = "https://files.pythonhosted.org/packages/ec/da/430015cec620d622f06854be67fd2f6721f52fc17fca8ac34b32e2d60739/pillow-11.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527", size = 4208514 }, - { url = "https://files.pythonhosted.org/packages/44/ae/7e4f6662a9b1cb5f92b9cc9cab8321c381ffbee309210940e57432a4063a/pillow-11.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa", size = 4380055 }, - { url = "https://files.pythonhosted.org/packages/74/d5/1a807779ac8a0eeed57f2b92a3c32ea1b696e6140c15bd42eaf908a261cd/pillow-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f", size = 4296751 }, - { url = "https://files.pythonhosted.org/packages/38/8c/5fa3385163ee7080bc13026d59656267daaaaf3c728c233d530e2c2757c8/pillow-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb", size = 4430378 }, - { url = "https://files.pythonhosted.org/packages/ca/1d/ad9c14811133977ff87035bf426875b93097fb50af747793f013979facdb/pillow-11.0.0-cp313-cp313-win32.whl", hash = "sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798", size = 2249588 }, - { url = "https://files.pythonhosted.org/packages/fb/01/3755ba287dac715e6afdb333cb1f6d69740a7475220b4637b5ce3d78cec2/pillow-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de", size = 2567509 }, - { url = "https://files.pythonhosted.org/packages/c0/98/2c7d727079b6be1aba82d195767d35fcc2d32204c7a5820f822df5330152/pillow-11.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84", size = 2254791 }, - { url = "https://files.pythonhosted.org/packages/eb/38/998b04cc6f474e78b563716b20eecf42a2fa16a84589d23c8898e64b0ffd/pillow-11.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b", size = 3150854 }, - { url = "https://files.pythonhosted.org/packages/13/8e/be23a96292113c6cb26b2aa3c8b3681ec62b44ed5c2bd0b258bd59503d3c/pillow-11.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003", size = 2982369 }, - { url = "https://files.pythonhosted.org/packages/97/8a/3db4eaabb7a2ae8203cd3a332a005e4aba00067fc514aaaf3e9721be31f1/pillow-11.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2", size = 4333703 }, - { url = "https://files.pythonhosted.org/packages/28/ac/629ffc84ff67b9228fe87a97272ab125bbd4dc462745f35f192d37b822f1/pillow-11.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a", size = 4412550 }, - { url = "https://files.pythonhosted.org/packages/d6/07/a505921d36bb2df6868806eaf56ef58699c16c388e378b0dcdb6e5b2fb36/pillow-11.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8", size = 4461038 }, - { url = "https://files.pythonhosted.org/packages/d6/b9/fb620dd47fc7cc9678af8f8bd8c772034ca4977237049287e99dda360b66/pillow-11.0.0-cp313-cp313t-win32.whl", hash = "sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8", size = 2253197 }, - { url = "https://files.pythonhosted.org/packages/df/86/25dde85c06c89d7fc5db17940f07aae0a56ac69aa9ccb5eb0f09798862a8/pillow-11.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904", size = 2572169 }, - { url = "https://files.pythonhosted.org/packages/51/85/9c33f2517add612e17f3381aee7c4072779130c634921a756c97bc29fb49/pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3", size = 2256828 }, +name = "pluggy" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, ] [[package]] @@ -1135,6 +972,45 @@ crypto = [ { name = "cryptography" }, ] +[[package]] +name = "pytest" +version = "8.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8b/6c/62bbd536103af674e227c41a8f3dcd022d591f6eed5facb5a0f31ee33bbc/pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", size = 1442487 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/77/7440a06a8ead44c7757a64362dd22df5760f9b12dc5f11b6188cd2fc27a0/pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2", size = 342341 }, +] + +[[package]] +name = "pytest-asyncio" +version = "0.24.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/52/6d/c6cf50ce320cf8611df7a1254d86233b3df7cc07f9b5f5cbcb82e08aa534/pytest_asyncio-0.24.0.tar.gz", hash = "sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276", size = 49855 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b", size = 18024 }, +] + +[[package]] +name = "pytest-repeat" +version = "0.9.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/86/5e/99365eb229efff0b1bd475886150fc6db9937ab7e1bd21f6f65c1279e0eb/pytest_repeat-0.9.3.tar.gz", hash = "sha256:ffd3836dfcd67bb270bec648b330e20be37d2966448c4148c4092d1e8aba8185", size = 6272 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/a8/0a0aec0c2541b8baf4a0b95af2ba99abce217ee43534adf9cb7c908cf184/pytest_repeat-0.9.3-py3-none-any.whl", hash = "sha256:26ab2df18226af9d5ce441c858f273121e92ff55f5bb311d25755b8d7abdd8ed", size = 4196 }, +] + [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -1156,15 +1032,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 }, ] -[[package]] -name = "python-json-logger" -version = "2.0.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4f/da/95963cebfc578dabd323d7263958dfb68898617912bb09327dd30e9c8d13/python-json-logger-2.0.7.tar.gz", hash = "sha256:23e7ec02d34237c5aa1e29a070193a4ea87583bb4e7f8fd06d3de8264c4b2e1c", size = 10508 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/35/a6/145655273568ee78a581e734cf35beb9e33a370b29c5d3c8fee3744de29f/python_json_logger-2.0.7-py3-none-any.whl", hash = "sha256:f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd", size = 8067 }, -] - [[package]] name = "python-liquid" version = "1.12.1" @@ -1179,15 +1046,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2c/6e/bfd01926e28f6cf355a7a8460271ba135013870f5857b06f35dbf65ab237/python_liquid-1.12.1-py3-none-any.whl", hash = "sha256:2224312944be16c1a44406398eb8a07c7e57398d5c0ef15ff950946dbefe7c33", size = 206592 }, ] -[[package]] -name = "python-multipart" -version = "0.0.17" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/40/22/edea41c2d4a22e666c0c7db7acdcbf7bc8c1c1f7d3b3ca246ec982fec612/python_multipart-0.0.17.tar.gz", hash = "sha256:41330d831cae6e2f22902704ead2826ea038d0419530eadff3ea80175aec5538", size = 36452 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/fb/275137a799169392f1fa88fff2be92f16eee38e982720a8aaadefc4a36b2/python_multipart-0.0.17-py3-none-any.whl", hash = "sha256:15dc4f487e0a9476cc1201261188ee0940165cffc94429b6fc565c4d3045cb5d", size = 24453 }, -] - [[package]] name = "pywin32" version = "306" @@ -1390,6 +1248,7 @@ name = "skill-library" version = "0.1.0" source = { editable = "." } dependencies = [ + { name = "assistant-drive" }, { name = "chat-driver" }, { name = "context" }, { name = "events" }, @@ -1402,8 +1261,16 @@ dependencies = [ { name = "tiktoken" }, ] +[package.dev-dependencies] +dev = [ + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-repeat" }, +] + [package.metadata] requires-dist = [ + { name = "assistant-drive", editable = "../../assistant-drive" }, { name = "chat-driver", editable = "../../chat-driver" }, { name = "context", editable = "../../context" }, { name = "events", editable = "../../events" }, @@ -1416,6 +1283,13 @@ requires-dist = [ { name = "tiktoken", specifier = ">=0.7.0" }, ] +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.1" }, + { name = "pytest-asyncio", specifier = ">=0.23.8" }, + { name = "pytest-repeat", specifier = ">=0.9.3" }, +] + [[package]] name = "sniffio" version = "1.3.1" From b0b72e687fb0acf9934aa98df119af991c9d6962 Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Fri, 25 Oct 2024 22:57:40 +0000 Subject: [PATCH 02/14] Adds subdrive. Fixes model overwriting config. --- assistants/prospector-assistant/uv.lock | 9 + .../assistant/skill_controller.py | 4 +- assistants/skill-assistant/uv.lock | 872 +++++++++++------- libraries/python/context/context/context.py | 4 +- .../notebooks/notebooks/chat_driver.ipynb | 193 ++-- libraries/python/skills/notebooks/uv.lock | 9 + .../instruction_routine_runner.py | 4 +- .../skill_library/run_context.py | 6 +- .../skill-library/skill_library/skill.py | 5 +- .../skill_library/skill_registry.py | 8 +- libraries/python/skills/skill-library/uv.lock | 526 ++++++++--- .../document_skill/document_skill.py | 6 +- .../skills/skills/document-skill/uv.lock | 34 + .../posix-skill/posix_skill/posix_skill.py | 29 +- .../python/skills/skills/posix-skill/uv.lock | 34 + .../prospector_skill/skill.py | 18 +- .../skills/skills/prospector-skill/uv.lock | 34 + .../skills/skills/skill-template/uv.lock | 34 + .../skills/skill-template/your_skill/skill.py | 11 +- 19 files changed, 1229 insertions(+), 611 deletions(-) diff --git a/assistants/prospector-assistant/uv.lock b/assistants/prospector-assistant/uv.lock index 4946c570..7bf660ca 100644 --- a/assistants/prospector-assistant/uv.lock +++ b/assistants/prospector-assistant/uv.lock @@ -2064,6 +2064,7 @@ name = "skill-library" version = "0.1.0" source = { editable = "../../libraries/python/skills/skill-library" } dependencies = [ + { name = "assistant-drive" }, { name = "chat-driver" }, { name = "context" }, { name = "events" }, @@ -2078,6 +2079,7 @@ dependencies = [ [package.metadata] requires-dist = [ + { name = "assistant-drive", editable = "../../libraries/python/assistant-drive" }, { name = "chat-driver", editable = "../../libraries/python/chat-driver" }, { name = "context", editable = "../../libraries/python/context" }, { name = "events", editable = "../../libraries/python/events" }, @@ -2090,6 +2092,13 @@ requires-dist = [ { name = "tiktoken", specifier = ">=0.7.0" }, ] +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.1" }, + { name = "pytest-asyncio", specifier = ">=0.23.8" }, + { name = "pytest-repeat", specifier = ">=0.9.3" }, +] + [[package]] name = "sniffio" version = "1.3.1" diff --git a/assistants/skill-assistant/assistant/skill_controller.py b/assistants/skill-assistant/assistant/skill_controller.py index 274af7f1..3189cb7e 100644 --- a/assistants/skill-assistant/assistant/skill_controller.py +++ b/assistants/skill-assistant/assistant/skill_controller.py @@ -147,7 +147,7 @@ async def create_assistant( # Define the skills this assistant should have. posix_skill = PosixSkill( - context=assistant.context, + context=assistant.run_context, sandbox_dir=Path(".data"), mount_dir="/mnt/data", chat_driver_config=ChatDriverConfig( @@ -157,7 +157,7 @@ async def create_assistant( ) document_skill = DocumentSkill( - context=assistant.context, + context=assistant.run_context, chat_driver_config=ChatDriverConfig( openai_client=async_client, model=chat_driver_config.openai_model, diff --git a/assistants/skill-assistant/uv.lock b/assistants/skill-assistant/uv.lock index 64370905..bf45b297 100644 --- a/assistants/skill-assistant/uv.lock +++ b/assistants/skill-assistant/uv.lock @@ -16,7 +16,7 @@ wheels = [ [[package]] name = "aiohttp" -version = "3.10.8" +version = "3.10.10" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, @@ -26,53 +26,53 @@ dependencies = [ { name = "multidict" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/4e/05/da5ff89c85444a6ade9079e73580fb3f78c6ba0e170a2472f15400d03e02/aiohttp-3.10.8.tar.gz", hash = "sha256:21f8225f7dc187018e8433c9326be01477fb2810721e048b33ac49091b19fb4a", size = 7540022 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/07/ca/2fc934c4c86865d0eb9c46f8f57443f0655f2a4a5c1dde60ec1d6d0f0881/aiohttp-3.10.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:33a68011a38020ed4ff41ae0dbf4a96a202562ecf2024bdd8f65385f1d07f6ef", size = 586333 }, - { url = "https://files.pythonhosted.org/packages/4a/07/7215d085dc10dd2e10f36832b2ca278f30970b4db98d5ebfed9e228d5c0c/aiohttp-3.10.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6c7efa6616a95e3bd73b8a69691012d2ef1f95f9ea0189e42f338fae080c2fc6", size = 398817 }, - { url = "https://files.pythonhosted.org/packages/c4/e4/77b029c12d025d1e448662977f1e7c6fb33a19c42181c8d20c2791b5c5d9/aiohttp-3.10.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ddb9b9764cfb4459acf01c02d2a59d3e5066b06a846a364fd1749aa168efa2be", size = 390465 }, - { url = "https://files.pythonhosted.org/packages/17/f5/206e6a58a3a5be39662a07f531a6033384e361e272735437c5c15176c601/aiohttp-3.10.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c7f270f4ca92760f98a42c45a58674fff488e23b144ec80b1cc6fa2effed377", size = 1306316 }, - { url = "https://files.pythonhosted.org/packages/33/e7/3b6b5ad02e367f30927bb93263127c23290f5b11900d036429f4787e1948/aiohttp-3.10.8-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6984dda9d79064361ab58d03f6c1e793ea845c6cfa89ffe1a7b9bb400dfd56bd", size = 1344486 }, - { url = "https://files.pythonhosted.org/packages/ae/9f/f27ba4cd2bffb4885aa35827a21878dbd3f50d6e5b205ce1107ce79edc40/aiohttp-3.10.8-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3f6d47e392c27206701565c8df4cac6ebed28fdf6dcaea5b1eea7a4631d8e6db", size = 1378320 }, - { url = "https://files.pythonhosted.org/packages/54/76/b106eb516d327527a6b1e0409a3553745ad34480eddfd0d7cad48ddc9848/aiohttp-3.10.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a72f89aea712c619b2ca32c6f4335c77125ede27530ad9705f4f349357833695", size = 1292542 }, - { url = "https://files.pythonhosted.org/packages/7d/0c/c116a27253c0bc76959ab8df5a109d482c0977d4028e1b3ec7fac038bb1a/aiohttp-3.10.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c36074b26f3263879ba8e4dbd33db2b79874a3392f403a70b772701363148b9f", size = 1251608 }, - { url = "https://files.pythonhosted.org/packages/9e/05/f9624dc401f72a3ee4cddea1a555b430e9a7be9d0cd2ab53dbec2fc78279/aiohttp-3.10.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e32148b4a745e70a255a1d44b5664de1f2e24fcefb98a75b60c83b9e260ddb5b", size = 1271551 }, - { url = "https://files.pythonhosted.org/packages/6d/77/19a032cfb9fdfd69591cf173c23c62992774b2ff978e4dab3038a1955e14/aiohttp-3.10.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5aa1a073514cf59c81ad49a4ed9b5d72b2433638cd53160fd2f3a9cfa94718db", size = 1266089 }, - { url = "https://files.pythonhosted.org/packages/12/63/58ebde5ea32cf5f19c83d6dc2c582ca5f0c42ce4cf084216a3cda4b2e34a/aiohttp-3.10.8-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d3a79200a9d5e621c4623081ddb25380b713c8cf5233cd11c1aabad990bb9381", size = 1321455 }, - { url = "https://files.pythonhosted.org/packages/1a/22/d8439a280161b542a28f88794ab55917cdc672544b87db52d3c41ce8d9a1/aiohttp-3.10.8-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e45fdfcb2d5bcad83373e4808825b7512953146d147488114575780640665027", size = 1339057 }, - { url = "https://files.pythonhosted.org/packages/bc/67/1a76a69adfe3013863df4142d37059fb357146815b29596945d61fb940cb/aiohttp-3.10.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f78e2a78432c537ae876a93013b7bc0027ba5b93ad7b3463624c4b6906489332", size = 1298892 }, - { url = "https://files.pythonhosted.org/packages/38/13/7294cb679ab7a80e5b0d0aa97c527690cffed2f34cb8892d73ebdb4204e8/aiohttp-3.10.8-cp311-cp311-win32.whl", hash = "sha256:f8179855a4e4f3b931cb1764ec87673d3fbdcca2af496c8d30567d7b034a13db", size = 362066 }, - { url = "https://files.pythonhosted.org/packages/bc/4a/8881d4d7259427897e1a314c2724e65fd0d20084c72cac8360665f96c347/aiohttp-3.10.8-cp311-cp311-win_amd64.whl", hash = "sha256:ef9b484604af05ca745b6108ca1aaa22ae1919037ae4f93aaf9a37ba42e0b835", size = 381406 }, - { url = "https://files.pythonhosted.org/packages/bb/ce/a8ff9f5bd2b36e3049cfe8d53656fed03075221ff42f946c581325bdc8fc/aiohttp-3.10.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ab2d6523575fc98896c80f49ac99e849c0b0e69cc80bf864eed6af2ae728a52b", size = 583366 }, - { url = "https://files.pythonhosted.org/packages/91/5c/75287ab8a6ae9cbe02d45ebb36b1e899c11da5eb47060e0dcb98ee30a951/aiohttp-3.10.8-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f5d5d5401744dda50b943d8764508d0e60cc2d3305ac1e6420935861a9d544bc", size = 395525 }, - { url = "https://files.pythonhosted.org/packages/a8/5a/aca17d71eb7e0f4611b2f28cb04e05aaebe6c7c2a7d1364e494da9722714/aiohttp-3.10.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de23085cf90911600ace512e909114385026b16324fa203cc74c81f21fd3276a", size = 390727 }, - { url = "https://files.pythonhosted.org/packages/1b/ee/c1663449864ec9dd3d2a61dde09112bea5e1d881496c36146a96fe85da62/aiohttp-3.10.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4618f0d2bf523043866a9ff8458900d8eb0a6d4018f251dae98e5f1fb699f3a8", size = 1311898 }, - { url = "https://files.pythonhosted.org/packages/8b/7e/ed2eb276fdf946a9303f3f80033555d3eaa0eadbcdd0c31b153e33b495fc/aiohttp-3.10.8-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21c1925541ca84f7b5e0df361c0a813a7d6a56d3b0030ebd4b220b8d232015f9", size = 1350380 }, - { url = "https://files.pythonhosted.org/packages/0c/3f/1d74a1311b14a1d69aad06775ffc1c09c195db67d951c8319220b9c64fdc/aiohttp-3.10.8-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:497a7d20caea8855c5429db3cdb829385467217d7feb86952a6107e033e031b9", size = 1392486 }, - { url = "https://files.pythonhosted.org/packages/9f/95/b940d71b1f61cf2ed48f2918c292609d251dba012a8e033afc0c778ed6a7/aiohttp-3.10.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c887019dbcb4af58a091a45ccf376fffe800b5531b45c1efccda4bedf87747ea", size = 1306135 }, - { url = "https://files.pythonhosted.org/packages/9b/25/b096aebc2f9b3ed738a4a667b841780b1dcd23ce5dff7dfabab4d09de4c8/aiohttp-3.10.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40d2d719c3c36a7a65ed26400e2b45b2d9ed7edf498f4df38b2ae130f25a0d01", size = 1260085 }, - { url = "https://files.pythonhosted.org/packages/9e/cf/bc024d8a848ee4feaae6a037034cf8b173a14ea9cb5c2988b6e5018abf33/aiohttp-3.10.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:57359785f27394a8bcab0da6dcd46706d087dfebf59a8d0ad2e64a4bc2f6f94f", size = 1270968 }, - { url = "https://files.pythonhosted.org/packages/40/1d/2513347c445d1aaa694e79f4d45f80d777ea3e4d772d9480577834dc2c1c/aiohttp-3.10.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a961ee6f2cdd1a2be4735333ab284691180d40bad48f97bb598841bfcbfb94ec", size = 1280083 }, - { url = "https://files.pythonhosted.org/packages/22/e1/4be1b057044c3d874e795744446c682715b232281adbe94612ddc9877ee4/aiohttp-3.10.8-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:fe3d79d6af839ffa46fdc5d2cf34295390894471e9875050eafa584cb781508d", size = 1316638 }, - { url = "https://files.pythonhosted.org/packages/6d/c3/84492f103c724d3149bba413e1dc081e573c44013bd2cc8f4addd51cf365/aiohttp-3.10.8-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9a281cba03bdaa341c70b7551b2256a88d45eead149f48b75a96d41128c240b3", size = 1343764 }, - { url = "https://files.pythonhosted.org/packages/cf/b7/50cc827dd54df087d7c30293b29fbc13a7ea45a3ac54a4a12127b271265c/aiohttp-3.10.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c6769d71bfb1ed60321363a9bc05e94dcf05e38295ef41d46ac08919e5b00d19", size = 1306007 }, - { url = "https://files.pythonhosted.org/packages/1e/c0/a4cb21ad677757368743d73aff27047dfc0d7248cb39dec06c059b773c24/aiohttp-3.10.8-cp312-cp312-win32.whl", hash = "sha256:a3081246bab4d419697ee45e555cef5cd1def7ac193dff6f50be761d2e44f194", size = 359125 }, - { url = "https://files.pythonhosted.org/packages/d2/0f/1ecbc18eed29952393d5a9c4636bfe789dde3c98fe0a0a4759d323478e72/aiohttp-3.10.8-cp312-cp312-win_amd64.whl", hash = "sha256:ab1546fc8e00676febc81c548a876c7bde32f881b8334b77f84719ab2c7d28dc", size = 379143 }, - { url = "https://files.pythonhosted.org/packages/9f/dd/3d944769ed65d3d245f8f976040654b3eae2e21d05c81f91fb450365bddf/aiohttp-3.10.8-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:b1a012677b8e0a39e181e218de47d6741c5922202e3b0b65e412e2ce47c39337", size = 575934 }, - { url = "https://files.pythonhosted.org/packages/2a/bf/a6a1d14b0e5f90d53b1f0850204f9fafdfec7c1d99dda8aaea1dd93ba181/aiohttp-3.10.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2df786c96c57cd6b87156ba4c5f166af7b88f3fc05f9d592252fdc83d8615a3c", size = 391728 }, - { url = "https://files.pythonhosted.org/packages/0e/1b/27cc6efa6ca3e563973c7e03e8b7e26b75b4046aefea991bad42c028a906/aiohttp-3.10.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8885ca09d3a9317219c0831276bfe26984b17b2c37b7bf70dd478d17092a4772", size = 387247 }, - { url = "https://files.pythonhosted.org/packages/ae/fd/235401bd4a98ea31cdda7b3822921e2a9cbc3ca0af1958a12a2709261735/aiohttp-3.10.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4dbf252ac19860e0ab56cd480d2805498f47c5a2d04f5995d8d8a6effd04b48c", size = 1286909 }, - { url = "https://files.pythonhosted.org/packages/ab/1c/8ae6b12be2ae88e94be34d96765d6cc820d61d320f33c0423de8af0cfa47/aiohttp-3.10.8-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b2036479b6b94afaaca7d07b8a68dc0e67b0caf5f6293bb6a5a1825f5923000", size = 1323446 }, - { url = "https://files.pythonhosted.org/packages/23/09/5ebe3a2dbdd008711b659dc2f2a6135bbc055b6c8869688083f4bec6b50a/aiohttp-3.10.8-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:365783e1b7c40b59ed4ce2b5a7491bae48f41cd2c30d52647a5b1ee8604c68ad", size = 1368237 }, - { url = "https://files.pythonhosted.org/packages/47/22/f184c27d03d34ce71e6d4b9976a4ff845d091b725f174b09f641e4a28f63/aiohttp-3.10.8-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:270e653b5a4b557476a1ed40e6b6ce82f331aab669620d7c95c658ef976c9c5e", size = 1282598 }, - { url = "https://files.pythonhosted.org/packages/82/f6/bae1703bfacb19bb35e3522632fc5279793070625a0b5e567b109c0f0e8d/aiohttp-3.10.8-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8960fabc20bfe4fafb941067cda8e23c8c17c98c121aa31c7bf0cdab11b07842", size = 1236350 }, - { url = "https://files.pythonhosted.org/packages/a4/bc/ad73aced93836b8749c70e617c5d389d17a36da9ee220cdb0804f803bd9b/aiohttp-3.10.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f21e8f2abed9a44afc3d15bba22e0dfc71e5fa859bea916e42354c16102b036f", size = 1250172 }, - { url = "https://files.pythonhosted.org/packages/3b/18/027a8497caf3a9c247477831d67ede58e1e42a92fd635ecdb74cf5d45c8b/aiohttp-3.10.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fecd55e7418fabd297fd836e65cbd6371aa4035a264998a091bbf13f94d9c44d", size = 1248783 }, - { url = "https://files.pythonhosted.org/packages/6f/d2/5080c27b656e6d478e820752d633d7a4dab4a2c4fd23a6f645b553fb9da5/aiohttp-3.10.8-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:badb51d851358cd7535b647bb67af4854b64f3c85f0d089c737f75504d5910ec", size = 1293209 }, - { url = "https://files.pythonhosted.org/packages/ae/ec/c38c8690e804cb9bf3e8c473a4a7bb339ed549cd63c469f19995269ca9ec/aiohttp-3.10.8-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e860985f30f3a015979e63e7ba1a391526cdac1b22b7b332579df7867848e255", size = 1319943 }, - { url = "https://files.pythonhosted.org/packages/df/55/d6e3a13c3f37ad7a3e60a377c96541261c1943837d240f1ab2151a96da6b/aiohttp-3.10.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:71462f8eeca477cbc0c9700a9464e3f75f59068aed5e9d4a521a103692da72dc", size = 1281380 }, - { url = "https://files.pythonhosted.org/packages/c3/31/0b84027487fa58a124251b47f9dca781e4777a50d1c4eea4d3fc8950bd10/aiohttp-3.10.8-cp313-cp313-win32.whl", hash = "sha256:177126e971782769b34933e94fddd1089cef0fe6b82fee8a885e539f5b0f0c6a", size = 357352 }, - { url = "https://files.pythonhosted.org/packages/cb/8a/b4f3a8d0fb7f4fdb3869db6c3334e23e11878123605579e067be85f7e01f/aiohttp-3.10.8-cp313-cp313-win_amd64.whl", hash = "sha256:98a4eb60e27033dee9593814ca320ee8c199489fbc6b2699d0f710584db7feb7", size = 376618 }, +sdist = { url = "https://files.pythonhosted.org/packages/17/7e/16e57e6cf20eb62481a2f9ce8674328407187950ccc602ad07c685279141/aiohttp-3.10.10.tar.gz", hash = "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a", size = 7542993 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/31/3c351d17596194e5a38ef169a4da76458952b2497b4b54645b9d483cbbb0/aiohttp-3.10.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c30a0eafc89d28e7f959281b58198a9fa5e99405f716c0289b7892ca345fe45f", size = 586501 }, + { url = "https://files.pythonhosted.org/packages/a4/a8/a559d09eb08478cdead6b7ce05b0c4a133ba27fcdfa91e05d2e62867300d/aiohttp-3.10.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:258c5dd01afc10015866114e210fb7365f0d02d9d059c3c3415382ab633fcbcb", size = 398993 }, + { url = "https://files.pythonhosted.org/packages/c5/47/7736d4174613feef61d25332c3bd1a4f8ff5591fbd7331988238a7299485/aiohttp-3.10.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:15ecd889a709b0080f02721255b3f80bb261c2293d3c748151274dfea93ac871", size = 390647 }, + { url = "https://files.pythonhosted.org/packages/27/21/e9ba192a04b7160f5a8952c98a1de7cf8072ad150fa3abd454ead1ab1d7f/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3935f82f6f4a3820270842e90456ebad3af15810cf65932bd24da4463bc0a4c", size = 1306481 }, + { url = "https://files.pythonhosted.org/packages/cf/50/f364c01c8d0def1dc34747b2470969e216f5a37c7ece00fe558810f37013/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:413251f6fcf552a33c981c4709a6bba37b12710982fec8e558ae944bfb2abd38", size = 1344652 }, + { url = "https://files.pythonhosted.org/packages/1d/c2/74f608e984e9b585649e2e83883facad6fa3fc1d021de87b20cc67e8e5ae/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1720b4f14c78a3089562b8875b53e36b51c97c51adc53325a69b79b4b48ebcb", size = 1378498 }, + { url = "https://files.pythonhosted.org/packages/9f/a7/05a48c7c0a7a80a5591b1203bf1b64ca2ed6a2050af918d09c05852dc42b/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:679abe5d3858b33c2cf74faec299fda60ea9de62916e8b67e625d65bf069a3b7", size = 1292718 }, + { url = "https://files.pythonhosted.org/packages/7d/78/a925655018747e9790350180330032e27d6e0d7ed30bde545fae42f8c49c/aiohttp-3.10.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79019094f87c9fb44f8d769e41dbb664d6e8fcfd62f665ccce36762deaa0e911", size = 1251776 }, + { url = "https://files.pythonhosted.org/packages/47/9d/85c6b69f702351d1236594745a4fdc042fc43f494c247a98dac17e004026/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe2fb38c2ed905a2582948e2de560675e9dfbee94c6d5ccdb1301c6d0a5bf092", size = 1271716 }, + { url = "https://files.pythonhosted.org/packages/7f/a7/55fc805ff9b14af818903882ece08e2235b12b73b867b521b92994c52b14/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a3f00003de6eba42d6e94fabb4125600d6e484846dbf90ea8e48a800430cc142", size = 1266263 }, + { url = "https://files.pythonhosted.org/packages/1f/ec/d2be2ca7b063e4f91519d550dbc9c1cb43040174a322470deed90b3d3333/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1bbb122c557a16fafc10354b9d99ebf2f2808a660d78202f10ba9d50786384b9", size = 1321617 }, + { url = "https://files.pythonhosted.org/packages/c9/a3/b29f7920e1cd0a9a68a45dd3eb16140074d2efb1518d2e1f3e140357dc37/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:30ca7c3b94708a9d7ae76ff281b2f47d8eaf2579cd05971b5dc681db8caac6e1", size = 1339227 }, + { url = "https://files.pythonhosted.org/packages/8a/81/34b67235c47e232d807b4bbc42ba9b927c7ce9476872372fddcfd1e41b3d/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:df9270660711670e68803107d55c2b5949c2e0f2e4896da176e1ecfc068b974a", size = 1299068 }, + { url = "https://files.pythonhosted.org/packages/04/1f/26a7fe11b6ad3184f214733428353c89ae9fe3e4f605a657f5245c5e720c/aiohttp-3.10.10-cp311-cp311-win32.whl", hash = "sha256:aafc8ee9b742ce75044ae9a4d3e60e3d918d15a4c2e08a6c3c3e38fa59b92d94", size = 362223 }, + { url = "https://files.pythonhosted.org/packages/10/91/85dcd93f64011434359ce2666bece981f08d31bc49df33261e625b28595d/aiohttp-3.10.10-cp311-cp311-win_amd64.whl", hash = "sha256:362f641f9071e5f3ee6f8e7d37d5ed0d95aae656adf4ef578313ee585b585959", size = 381576 }, + { url = "https://files.pythonhosted.org/packages/ae/99/4c5aefe5ad06a1baf206aed6598c7cdcbc7c044c46801cd0d1ecb758cae3/aiohttp-3.10.10-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9294bbb581f92770e6ed5c19559e1e99255e4ca604a22c5c6397b2f9dd3ee42c", size = 583536 }, + { url = "https://files.pythonhosted.org/packages/a9/36/8b3bc49b49cb6d2da40ee61ff15dbcc44fd345a3e6ab5bb20844df929821/aiohttp-3.10.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a8fa23fe62c436ccf23ff930149c047f060c7126eae3ccea005f0483f27b2e28", size = 395693 }, + { url = "https://files.pythonhosted.org/packages/e1/77/0aa8660dcf11fa65d61712dbb458c4989de220a844bd69778dff25f2d50b/aiohttp-3.10.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c6a5b8c7926ba5d8545c7dd22961a107526562da31a7a32fa2456baf040939f", size = 390898 }, + { url = "https://files.pythonhosted.org/packages/38/d2/b833d95deb48c75db85bf6646de0a697e7fb5d87bd27cbade4f9746b48b1/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:007ec22fbc573e5eb2fb7dec4198ef8f6bf2fe4ce20020798b2eb5d0abda6138", size = 1312060 }, + { url = "https://files.pythonhosted.org/packages/aa/5f/29fd5113165a0893de8efedf9b4737e0ba92dfcd791415a528f947d10299/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9627cc1a10c8c409b5822a92d57a77f383b554463d1884008e051c32ab1b3742", size = 1350553 }, + { url = "https://files.pythonhosted.org/packages/ad/cc/f835f74b7d344428469200105236d44606cfa448be1e7c95ca52880d9bac/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:50edbcad60d8f0e3eccc68da67f37268b5144ecc34d59f27a02f9611c1d4eec7", size = 1392646 }, + { url = "https://files.pythonhosted.org/packages/bf/fe/1332409d845ca601893bbf2d76935e0b93d41686e5f333841c7d7a4a770d/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a45d85cf20b5e0d0aa5a8dca27cce8eddef3292bc29d72dcad1641f4ed50aa16", size = 1306310 }, + { url = "https://files.pythonhosted.org/packages/e4/a1/25a7633a5a513278a9892e333501e2e69c83e50be4b57a62285fb7a008c3/aiohttp-3.10.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b00807e2605f16e1e198f33a53ce3c4523114059b0c09c337209ae55e3823a8", size = 1260255 }, + { url = "https://files.pythonhosted.org/packages/f2/39/30eafe89e0e2a06c25e4762844c8214c0c0cd0fd9ffc3471694a7986f421/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f2d4324a98062be0525d16f768a03e0bbb3b9fe301ceee99611dc9a7953124e6", size = 1271141 }, + { url = "https://files.pythonhosted.org/packages/5b/fc/33125df728b48391ef1fcb512dfb02072158cc10d041414fb79803463020/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:438cd072f75bb6612f2aca29f8bd7cdf6e35e8f160bc312e49fbecab77c99e3a", size = 1280244 }, + { url = "https://files.pythonhosted.org/packages/3b/61/e42bf2c2934b5caa4e2ec0b5e5fd86989adb022b5ee60c2572a9d77cf6fe/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:baa42524a82f75303f714108fea528ccacf0386af429b69fff141ffef1c534f9", size = 1316805 }, + { url = "https://files.pythonhosted.org/packages/18/32/f52a5e2ae9ad3bba10e026a63a7a23abfa37c7d97aeeb9004eaa98df3ce3/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a7d8d14fe962153fc681f6366bdec33d4356f98a3e3567782aac1b6e0e40109a", size = 1343930 }, + { url = "https://files.pythonhosted.org/packages/05/be/6a403b464dcab3631fe8e27b0f1d906d9e45c5e92aca97ee007e5a895560/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205", size = 1306186 }, + { url = "https://files.pythonhosted.org/packages/8e/fd/bb50fe781068a736a02bf5c7ad5f3ab53e39f1d1e63110da6d30f7605edc/aiohttp-3.10.10-cp312-cp312-win32.whl", hash = "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628", size = 359289 }, + { url = "https://files.pythonhosted.org/packages/70/9e/5add7e240f77ef67c275c82cc1d08afbca57b77593118c1f6e920ae8ad3f/aiohttp-3.10.10-cp312-cp312-win_amd64.whl", hash = "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf", size = 379313 }, + { url = "https://files.pythonhosted.org/packages/b1/eb/618b1b76c7fe8082a71c9d62e3fe84c5b9af6703078caa9ec57850a12080/aiohttp-3.10.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28", size = 576114 }, + { url = "https://files.pythonhosted.org/packages/aa/37/3126995d7869f8b30d05381b81a2d4fb4ec6ad313db788e009bc6d39c211/aiohttp-3.10.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d", size = 391901 }, + { url = "https://files.pythonhosted.org/packages/3e/f2/8fdfc845be1f811c31ceb797968523813f8e1263ee3e9120d61253f6848f/aiohttp-3.10.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79", size = 387418 }, + { url = "https://files.pythonhosted.org/packages/60/d5/33d2061d36bf07e80286e04b7e0a4de37ce04b5ebfed72dba67659a05250/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e", size = 1287073 }, + { url = "https://files.pythonhosted.org/packages/00/52/affb55be16a4747740bd630b4c002dac6c5eac42f9bb64202fc3cf3f1930/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6", size = 1323612 }, + { url = "https://files.pythonhosted.org/packages/94/f2/cddb69b975387daa2182a8442566971d6410b8a0179bb4540d81c97b1611/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42", size = 1368406 }, + { url = "https://files.pythonhosted.org/packages/c1/e4/afba7327da4d932da8c6e29aecaf855f9d52dace53ac15bfc8030a246f1b/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e", size = 1282761 }, + { url = "https://files.pythonhosted.org/packages/9f/6b/364856faa0c9031ea76e24ef0f7fef79cddd9fa8e7dba9a1771c6acc56b5/aiohttp-3.10.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc", size = 1236518 }, + { url = "https://files.pythonhosted.org/packages/46/af/c382846f8356fe64a7b5908bb9b477457aa23b71be7ed551013b7b7d4d87/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a", size = 1250344 }, + { url = "https://files.pythonhosted.org/packages/87/53/294f87fc086fd0772d0ab82497beb9df67f0f27a8b3dd5742a2656db2bc6/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414", size = 1248956 }, + { url = "https://files.pythonhosted.org/packages/86/30/7d746717fe11bdfefb88bb6c09c5fc985d85c4632da8bb6018e273899254/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3", size = 1293379 }, + { url = "https://files.pythonhosted.org/packages/48/b9/45d670a834458db67a24258e9139ba61fa3bd7d69b98ecf3650c22806f8f/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67", size = 1320108 }, + { url = "https://files.pythonhosted.org/packages/72/8c/804bb2e837a175635d2000a0659eafc15b2e9d92d3d81c8f69e141ecd0b0/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b", size = 1281546 }, + { url = "https://files.pythonhosted.org/packages/89/c0/862e6a9de3d6eeb126cd9d9ea388243b70df9b871ce1a42b193b7a4a77fc/aiohttp-3.10.10-cp313-cp313-win32.whl", hash = "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8", size = 357516 }, + { url = "https://files.pythonhosted.org/packages/ae/63/3e1aee3e554263f3f1011cca50d78a4894ae16ce99bf78101ac3a2f0ef74/aiohttp-3.10.10-cp313-cp313-win_amd64.whl", hash = "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151", size = 376785 }, ] [[package]] @@ -98,27 +98,28 @@ wheels = [ [[package]] name = "anyio" -version = "4.6.0" +version = "4.6.2.post1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "sniffio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/78/49/f3f17ec11c4a91fe79275c426658e509b07547f874b14c1a526d86a83fc8/anyio-4.6.0.tar.gz", hash = "sha256:137b4559cbb034c477165047febb6ff83f390fc3b20bf181c1fc0a728cb8beeb", size = 170983 } +sdist = { url = "https://files.pythonhosted.org/packages/9f/09/45b9b7a6d4e45c6bcb5bf61d19e3ab87df68e0601fa8c5293de3542546cc/anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c", size = 173422 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/ef/7a4f225581a0d7886ea28359179cb861d7fbcdefad29663fc1167b86f69f/anyio-4.6.0-py3-none-any.whl", hash = "sha256:c7d2e9d63e31599eeb636c8c5c03a7e108d73b345f064f1c19fdc87b79036a9a", size = 89631 }, + { url = "https://files.pythonhosted.org/packages/e4/f5/f2b75d2fc6f1a260f340f0e7c6a060f4dd2961cc16884ed851b0d18da06a/anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d", size = 90377 }, ] [[package]] name = "asgi-correlation-id" -version = "4.3.3" +version = "4.3.4" source = { registry = "https://pypi.org/simple" } dependencies = [ + { name = "packaging" }, { name = "starlette" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/be/81/15a920a166d38ce0685de33f3c5e64b86a3c112c7d646ed46d8ec1cb4047/asgi_correlation_id-4.3.3.tar.gz", hash = "sha256:25d89b52f3d32c0f3b4915a9fc38d9cffc7395960d05910bdce5c13023dc237b", size = 20052 } +sdist = { url = "https://files.pythonhosted.org/packages/f4/ff/a6538245ac1eaa7733ec6740774e9d5add019e2c63caa29e758c16c0afdd/asgi_correlation_id-4.3.4.tar.gz", hash = "sha256:ea6bc310380373cb9f731dc2e8b2b6fb978a76afe33f7a2384f697b8d6cd811d", size = 20075 } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/e1/aa53fea4e367c1ec0e69cb78c234dec4ec50d80ce02279e1ec647dea1a47/asgi_correlation_id-4.3.3-py3-none-any.whl", hash = "sha256:62ba38c359aa004c1c3e2b8e0cdf0e8ad4aa5a93864eaadc46e77d5c142a206a", size = 15253 }, + { url = "https://files.pythonhosted.org/packages/d9/ab/6936e2663c47a926e0659437b9333ad87d1ff49b1375d239026e0a268eba/asgi_correlation_id-4.3.4-py3-none-any.whl", hash = "sha256:36ce69b06c7d96b4acb89c7556a4c4f01a972463d3d49c675026cbbd08e9a0a2", size = 15262 }, ] [[package]] @@ -150,6 +151,31 @@ requires-dist = [ { name = "semantic-workbench-assistant", editable = "../../libraries/python/semantic-workbench-assistant" }, ] +[[package]] +name = "assistant-drive" +version = "0.1.0" +source = { editable = "../../libraries/python/assistant-drive" } +dependencies = [ + { name = "context" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, +] + +[package.metadata] +requires-dist = [ + { name = "context", editable = "../../libraries/python/context" }, + { name = "pydantic", specifier = ">=2.6.1" }, + { name = "pydantic-settings", specifier = ">=2.5.2" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "ipykernel", specifier = ">=6.29.5" }, + { name = "pytest", specifier = ">=8.3.1" }, + { name = "pytest-asyncio", specifier = ">=0.23.8" }, + { name = "pytest-repeat", specifier = ">=0.9.3" }, +] + [[package]] name = "attrs" version = "24.2.0" @@ -174,16 +200,16 @@ wheels = [ [[package]] name = "azure-core" -version = "1.31.0" +version = "1.32.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, { name = "six" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/03/7a/f79ad135a276a37e61168495697c14ba1721a52c3eab4dae2941929c79f8/azure_core-1.31.0.tar.gz", hash = "sha256:656a0dd61e1869b1506b7c6a3b31d62f15984b1a573d6326f6aa2f3e4123284b", size = 277147 } +sdist = { url = "https://files.pythonhosted.org/packages/cc/ee/668328306a9e963a5ad9f152cd98c7adad86c822729fd1d2a01613ad1e67/azure_core-1.32.0.tar.gz", hash = "sha256:22b3c35d6b2dae14990f6c1be2912bf23ffe50b220e708a28ab1bb92b1c730e5", size = 279128 } wheels = [ - { url = "https://files.pythonhosted.org/packages/01/8e/fcb6a77d3029d2a7356f38dbc77cf7daa113b81ddab76b5593d23321e44c/azure_core-1.31.0-py3-none-any.whl", hash = "sha256:22954de3777e0250029360ef31d80448ef1be13b80a459bff80ba7073379e2cd", size = 197399 }, + { url = "https://files.pythonhosted.org/packages/39/83/325bf5e02504dbd8b4faa98197a44cdf8a325ef259b48326a2b6f17f8383/azure_core-1.32.0-py3-none-any.whl", hash = "sha256:eac191a0efb23bfa83fddf321b27b122b4ec847befa3091fa736a5c32c50d7b4", size = 198855 }, ] [package.optional-dependencies] @@ -193,7 +219,7 @@ aio = [ [[package]] name = "azure-identity" -version = "1.18.0" +version = "1.19.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "azure-core" }, @@ -202,9 +228,9 @@ dependencies = [ { name = "msal-extensions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b3/5d/1c7da35dd640b4a95a38f980bb6b0b56c4e91d5b3d518ac11a2c4ebf5f62/azure_identity-1.18.0.tar.gz", hash = "sha256:f567579a65d8932fa913c76eddf3305101a15e5727a5e4aa5df649a0f553d4c3", size = 263322 } +sdist = { url = "https://files.pythonhosted.org/packages/aa/91/cbaeff9eb0b838f0d35b4607ac1c6195c735c8eb17db235f8f60e622934c/azure_identity-1.19.0.tar.gz", hash = "sha256:500144dc18197d7019b81501165d4fa92225f03778f17d7ca8a2a180129a9c83", size = 263058 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/71/1d1bb387b6acaa5daa3e703c70dde3d54823ccd229bd6730de6e724f296e/azure_identity-1.18.0-py3-none-any.whl", hash = "sha256:bccf6106245b49ff41d0c4cd7b72851c5a2ba3a32cef7589da246f5727f26f02", size = 187179 }, + { url = "https://files.pythonhosted.org/packages/f0/d5/3995ed12f941f4a41a273d9b1709282e825ef87ed8eab3833038fee54d59/azure_identity-1.19.0-py3-none-any.whl", hash = "sha256:e3f6558c181692d7509f09de10cca527c7dce426776454fb97df512a46527e81", size = 187587 }, ] [[package]] @@ -272,41 +298,56 @@ wheels = [ [[package]] name = "charset-normalizer" -version = "3.3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/63/09/c1bc53dab74b1816a00d8d030de5bf98f724c52c1635e07681d312f20be8/charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", size = 104809 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/77/02839016f6fbbf808e8b38601df6e0e66c17bbab76dff4613f7511413597/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", size = 191647 }, - { url = "https://files.pythonhosted.org/packages/3e/33/21a875a61057165e92227466e54ee076b73af1e21fe1b31f1e292251aa1e/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", size = 121434 }, - { url = "https://files.pythonhosted.org/packages/dd/51/68b61b90b24ca35495956b718f35a9756ef7d3dd4b3c1508056fa98d1a1b/charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", size = 118979 }, - { url = "https://files.pythonhosted.org/packages/e4/a6/7ee57823d46331ddc37dd00749c95b0edec2c79b15fc0d6e6efb532e89ac/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", size = 136582 }, - { url = "https://files.pythonhosted.org/packages/74/f1/0d9fe69ac441467b737ba7f48c68241487df2f4522dd7246d9426e7c690e/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", size = 146645 }, - { url = "https://files.pythonhosted.org/packages/05/31/e1f51c76db7be1d4aef220d29fbfa5dbb4a99165d9833dcbf166753b6dc0/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", size = 139398 }, - { url = "https://files.pythonhosted.org/packages/40/26/f35951c45070edc957ba40a5b1db3cf60a9dbb1b350c2d5bef03e01e61de/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", size = 140273 }, - { url = "https://files.pythonhosted.org/packages/07/07/7e554f2bbce3295e191f7e653ff15d55309a9ca40d0362fcdab36f01063c/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", size = 142577 }, - { url = "https://files.pythonhosted.org/packages/d8/b5/eb705c313100defa57da79277d9207dc8d8e45931035862fa64b625bfead/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", size = 137747 }, - { url = "https://files.pythonhosted.org/packages/19/28/573147271fd041d351b438a5665be8223f1dd92f273713cb882ddafe214c/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", size = 143375 }, - { url = "https://files.pythonhosted.org/packages/cf/7c/f3b682fa053cc21373c9a839e6beba7705857075686a05c72e0f8c4980ca/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", size = 148474 }, - { url = "https://files.pythonhosted.org/packages/1e/49/7ab74d4ac537ece3bc3334ee08645e231f39f7d6df6347b29a74b0537103/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", size = 140232 }, - { url = "https://files.pythonhosted.org/packages/2d/dc/9dacba68c9ac0ae781d40e1a0c0058e26302ea0660e574ddf6797a0347f7/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", size = 140859 }, - { url = "https://files.pythonhosted.org/packages/6c/c2/4a583f800c0708dd22096298e49f887b49d9746d0e78bfc1d7e29816614c/charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", size = 92509 }, - { url = "https://files.pythonhosted.org/packages/57/ec/80c8d48ac8b1741d5b963797b7c0c869335619e13d4744ca2f67fc11c6fc/charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", size = 99870 }, - { url = "https://files.pythonhosted.org/packages/d1/b2/fcedc8255ec42afee97f9e6f0145c734bbe104aac28300214593eb326f1d/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", size = 192892 }, - { url = "https://files.pythonhosted.org/packages/2e/7d/2259318c202f3d17f3fe6438149b3b9e706d1070fe3fcbb28049730bb25c/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", size = 122213 }, - { url = "https://files.pythonhosted.org/packages/3a/52/9f9d17c3b54dc238de384c4cb5a2ef0e27985b42a0e5cc8e8a31d918d48d/charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", size = 119404 }, - { url = "https://files.pythonhosted.org/packages/99/b0/9c365f6d79a9f0f3c379ddb40a256a67aa69c59609608fe7feb6235896e1/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", size = 137275 }, - { url = "https://files.pythonhosted.org/packages/91/33/749df346e93d7a30cdcb90cbfdd41a06026317bfbfb62cd68307c1a3c543/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", size = 147518 }, - { url = "https://files.pythonhosted.org/packages/72/1a/641d5c9f59e6af4c7b53da463d07600a695b9824e20849cb6eea8a627761/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", size = 140182 }, - { url = "https://files.pythonhosted.org/packages/ee/fb/14d30eb4956408ee3ae09ad34299131fb383c47df355ddb428a7331cfa1e/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", size = 141869 }, - { url = "https://files.pythonhosted.org/packages/df/3e/a06b18788ca2eb6695c9b22325b6fde7dde0f1d1838b1792a0076f58fe9d/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", size = 144042 }, - { url = "https://files.pythonhosted.org/packages/45/59/3d27019d3b447a88fe7e7d004a1e04be220227760264cc41b405e863891b/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", size = 138275 }, - { url = "https://files.pythonhosted.org/packages/7b/ef/5eb105530b4da8ae37d506ccfa25057961b7b63d581def6f99165ea89c7e/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", size = 144819 }, - { url = "https://files.pythonhosted.org/packages/a2/51/e5023f937d7f307c948ed3e5c29c4b7a3e42ed2ee0b8cdf8f3a706089bf0/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", size = 149415 }, - { url = "https://files.pythonhosted.org/packages/24/9d/2e3ef673dfd5be0154b20363c5cdcc5606f35666544381bee15af3778239/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", size = 141212 }, - { url = "https://files.pythonhosted.org/packages/5b/ae/ce2c12fcac59cb3860b2e2d76dc405253a4475436b1861d95fe75bdea520/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", size = 142167 }, - { url = "https://files.pythonhosted.org/packages/ed/3a/a448bf035dce5da359daf9ae8a16b8a39623cc395a2ffb1620aa1bce62b0/charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", size = 93041 }, - { url = "https://files.pythonhosted.org/packages/b6/7c/8debebb4f90174074b827c63242c23851bdf00a532489fba57fef3416e40/charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", size = 100397 }, - { url = "https://files.pythonhosted.org/packages/28/76/e6222113b83e3622caa4bb41032d0b1bf785250607392e1b778aca0b8a7d/charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", size = 48543 }, +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/4f/e1808dc01273379acc506d18f1504eb2d299bd4131743b9fc54d7be4df1e/charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", size = 106620 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/61/73589dcc7a719582bf56aae309b6103d2762b526bffe189d635a7fcfd998/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c", size = 193339 }, + { url = "https://files.pythonhosted.org/packages/77/d5/8c982d58144de49f59571f940e329ad6e8615e1e82ef84584c5eeb5e1d72/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944", size = 124366 }, + { url = "https://files.pythonhosted.org/packages/bf/19/411a64f01ee971bed3231111b69eb56f9331a769072de479eae7de52296d/charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee", size = 118874 }, + { url = "https://files.pythonhosted.org/packages/4c/92/97509850f0d00e9f14a46bc751daabd0ad7765cff29cdfb66c68b6dad57f/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c", size = 138243 }, + { url = "https://files.pythonhosted.org/packages/e2/29/d227805bff72ed6d6cb1ce08eec707f7cfbd9868044893617eb331f16295/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6", size = 148676 }, + { url = "https://files.pythonhosted.org/packages/13/bc/87c2c9f2c144bedfa62f894c3007cd4530ba4b5351acb10dc786428a50f0/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea", size = 141289 }, + { url = "https://files.pythonhosted.org/packages/eb/5b/6f10bad0f6461fa272bfbbdf5d0023b5fb9bc6217c92bf068fa5a99820f5/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc", size = 142585 }, + { url = "https://files.pythonhosted.org/packages/3b/a0/a68980ab8a1f45a36d9745d35049c1af57d27255eff8c907e3add84cf68f/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5", size = 144408 }, + { url = "https://files.pythonhosted.org/packages/d7/a1/493919799446464ed0299c8eef3c3fad0daf1c3cd48bff9263c731b0d9e2/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594", size = 139076 }, + { url = "https://files.pythonhosted.org/packages/fb/9d/9c13753a5a6e0db4a0a6edb1cef7aee39859177b64e1a1e748a6e3ba62c2/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c", size = 146874 }, + { url = "https://files.pythonhosted.org/packages/75/d2/0ab54463d3410709c09266dfb416d032a08f97fd7d60e94b8c6ef54ae14b/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365", size = 150871 }, + { url = "https://files.pythonhosted.org/packages/8d/c9/27e41d481557be53d51e60750b85aa40eaf52b841946b3cdeff363105737/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129", size = 148546 }, + { url = "https://files.pythonhosted.org/packages/ee/44/4f62042ca8cdc0cabf87c0fc00ae27cd8b53ab68be3605ba6d071f742ad3/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236", size = 143048 }, + { url = "https://files.pythonhosted.org/packages/01/f8/38842422988b795220eb8038745d27a675ce066e2ada79516c118f291f07/charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99", size = 94389 }, + { url = "https://files.pythonhosted.org/packages/0b/6e/b13bd47fa9023b3699e94abf565b5a2f0b0be6e9ddac9812182596ee62e4/charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27", size = 101752 }, + { url = "https://files.pythonhosted.org/packages/d3/0b/4b7a70987abf9b8196845806198975b6aab4ce016632f817ad758a5aa056/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6", size = 194445 }, + { url = "https://files.pythonhosted.org/packages/50/89/354cc56cf4dd2449715bc9a0f54f3aef3dc700d2d62d1fa5bbea53b13426/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf", size = 125275 }, + { url = "https://files.pythonhosted.org/packages/fa/44/b730e2a2580110ced837ac083d8ad222343c96bb6b66e9e4e706e4d0b6df/charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db", size = 119020 }, + { url = "https://files.pythonhosted.org/packages/9d/e4/9263b8240ed9472a2ae7ddc3e516e71ef46617fe40eaa51221ccd4ad9a27/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1", size = 139128 }, + { url = "https://files.pythonhosted.org/packages/6b/e3/9f73e779315a54334240353eaea75854a9a690f3f580e4bd85d977cb2204/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03", size = 149277 }, + { url = "https://files.pythonhosted.org/packages/1a/cf/f1f50c2f295312edb8a548d3fa56a5c923b146cd3f24114d5adb7e7be558/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284", size = 142174 }, + { url = "https://files.pythonhosted.org/packages/16/92/92a76dc2ff3a12e69ba94e7e05168d37d0345fa08c87e1fe24d0c2a42223/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15", size = 143838 }, + { url = "https://files.pythonhosted.org/packages/a4/01/2117ff2b1dfc61695daf2babe4a874bca328489afa85952440b59819e9d7/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8", size = 146149 }, + { url = "https://files.pythonhosted.org/packages/f6/9b/93a332b8d25b347f6839ca0a61b7f0287b0930216994e8bf67a75d050255/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2", size = 140043 }, + { url = "https://files.pythonhosted.org/packages/ab/f6/7ac4a01adcdecbc7a7587767c776d53d369b8b971382b91211489535acf0/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719", size = 148229 }, + { url = "https://files.pythonhosted.org/packages/9d/be/5708ad18161dee7dc6a0f7e6cf3a88ea6279c3e8484844c0590e50e803ef/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631", size = 151556 }, + { url = "https://files.pythonhosted.org/packages/5a/bb/3d8bc22bacb9eb89785e83e6723f9888265f3a0de3b9ce724d66bd49884e/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b", size = 149772 }, + { url = "https://files.pythonhosted.org/packages/f7/fa/d3fc622de05a86f30beea5fc4e9ac46aead4731e73fd9055496732bcc0a4/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", size = 144800 }, + { url = "https://files.pythonhosted.org/packages/9a/65/bdb9bc496d7d190d725e96816e20e2ae3a6fa42a5cac99c3c3d6ff884118/charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", size = 94836 }, + { url = "https://files.pythonhosted.org/packages/3e/67/7b72b69d25b89c0b3cea583ee372c43aa24df15f0e0f8d3982c57804984b/charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", size = 102187 }, + { url = "https://files.pythonhosted.org/packages/f3/89/68a4c86f1a0002810a27f12e9a7b22feb198c59b2f05231349fbce5c06f4/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", size = 194617 }, + { url = "https://files.pythonhosted.org/packages/4f/cd/8947fe425e2ab0aa57aceb7807af13a0e4162cd21eee42ef5b053447edf5/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", size = 125310 }, + { url = "https://files.pythonhosted.org/packages/5b/f0/b5263e8668a4ee9becc2b451ed909e9c27058337fda5b8c49588183c267a/charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", size = 119126 }, + { url = "https://files.pythonhosted.org/packages/ff/6e/e445afe4f7fda27a533f3234b627b3e515a1b9429bc981c9a5e2aa5d97b6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", size = 139342 }, + { url = "https://files.pythonhosted.org/packages/a1/b2/4af9993b532d93270538ad4926c8e37dc29f2111c36f9c629840c57cd9b3/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", size = 149383 }, + { url = "https://files.pythonhosted.org/packages/fb/6f/4e78c3b97686b871db9be6f31d64e9264e889f8c9d7ab33c771f847f79b7/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", size = 142214 }, + { url = "https://files.pythonhosted.org/packages/2b/c9/1c8fe3ce05d30c87eff498592c89015b19fade13df42850aafae09e94f35/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", size = 144104 }, + { url = "https://files.pythonhosted.org/packages/ee/68/efad5dcb306bf37db7db338338e7bb8ebd8cf38ee5bbd5ceaaaa46f257e6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", size = 146255 }, + { url = "https://files.pythonhosted.org/packages/0c/75/1ed813c3ffd200b1f3e71121c95da3f79e6d2a96120163443b3ad1057505/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", size = 140251 }, + { url = "https://files.pythonhosted.org/packages/7d/0d/6f32255c1979653b448d3c709583557a4d24ff97ac4f3a5be156b2e6a210/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", size = 148474 }, + { url = "https://files.pythonhosted.org/packages/ac/a0/c1b5298de4670d997101fef95b97ac440e8c8d8b4efa5a4d1ef44af82f0d/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", size = 151849 }, + { url = "https://files.pythonhosted.org/packages/04/4f/b3961ba0c664989ba63e30595a3ed0875d6790ff26671e2aae2fdc28a399/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", size = 149781 }, + { url = "https://files.pythonhosted.org/packages/d8/90/6af4cd042066a4adad58ae25648a12c09c879efa4849c705719ba1b23d8c/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482", size = 144970 }, + { url = "https://files.pythonhosted.org/packages/cc/67/e5e7e0cbfefc4ca79025238b43cdf8a2037854195b37d6417f3d0895c4c2/charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", size = 94973 }, + { url = "https://files.pythonhosted.org/packages/65/97/fc9bbc54ee13d33dc54a7fcf17b26368b18505500fc01e228c27b5222d80/charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", size = 102308 }, + { url = "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", size = 49446 }, ] [[package]] @@ -404,31 +445,31 @@ dev = [ [[package]] name = "cryptography" -version = "43.0.1" +version = "43.0.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/de/ba/0664727028b37e249e73879348cc46d45c5c1a2a2e81e8166462953c5755/cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d", size = 686927 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/28/b92c98a04ba762f8cdeb54eba5c4c84e63cac037a7c5e70117d337b15ad6/cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d", size = 6223222 }, - { url = "https://files.pythonhosted.org/packages/33/13/1193774705783ba364121aa2a60132fa31a668b8ababd5edfa1662354ccd/cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062", size = 3794751 }, - { url = "https://files.pythonhosted.org/packages/5e/4b/39bb3c4c8cfb3e94e736b8d8859ce5c81536e91a1033b1d26770c4249000/cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962", size = 3981827 }, - { url = "https://files.pythonhosted.org/packages/ce/dc/1471d4d56608e1013237af334b8a4c35d53895694fbb73882d1c4fd3f55e/cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277", size = 3780034 }, - { url = "https://files.pythonhosted.org/packages/ad/43/7a9920135b0d5437cc2f8f529fa757431eb6a7736ddfadfdee1cc5890800/cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a", size = 3993407 }, - { url = "https://files.pythonhosted.org/packages/cc/42/9ab8467af6c0b76f3d9b8f01d1cf25b9c9f3f2151f4acfab888d21c55a72/cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042", size = 3886457 }, - { url = "https://files.pythonhosted.org/packages/a4/65/430509e31700286ec02868a2457d2111d03ccefc20349d24e58d171ae0a7/cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494", size = 4081499 }, - { url = "https://files.pythonhosted.org/packages/bb/18/a04b6467e6e09df8c73b91dcee8878f4a438a43a3603dc3cd6f8003b92d8/cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2", size = 2616504 }, - { url = "https://files.pythonhosted.org/packages/cc/73/0eacbdc437202edcbdc07f3576ed8fb8b0ab79d27bf2c5d822d758a72faa/cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d", size = 3067456 }, - { url = "https://files.pythonhosted.org/packages/8a/b6/bc54b371f02cffd35ff8dc6baba88304d7cf8e83632566b4b42e00383e03/cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d", size = 6225263 }, - { url = "https://files.pythonhosted.org/packages/00/0e/8217e348a1fa417ec4c78cd3cdf24154f5e76fd7597343a35bd403650dfd/cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806", size = 3794368 }, - { url = "https://files.pythonhosted.org/packages/3d/ed/38b6be7254d8f7251fde8054af597ee8afa14f911da67a9410a45f602fc3/cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85", size = 3981750 }, - { url = "https://files.pythonhosted.org/packages/64/f3/b7946c3887cf7436f002f4cbb1e6aec77b8d299b86be48eeadfefb937c4b/cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c", size = 3778925 }, - { url = "https://files.pythonhosted.org/packages/ac/7e/ebda4dd4ae098a0990753efbb4b50954f1d03003846b943ea85070782da7/cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1", size = 3993152 }, - { url = "https://files.pythonhosted.org/packages/43/f6/feebbd78a3e341e3913846a3bb2c29d0b09b1b3af1573c6baabc2533e147/cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa", size = 3886392 }, - { url = "https://files.pythonhosted.org/packages/bd/4c/ab0b9407d5247576290b4fd8abd06b7f51bd414f04eef0f2800675512d61/cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4", size = 4082606 }, - { url = "https://files.pythonhosted.org/packages/05/36/e532a671998d6fcfdb9122da16434347a58a6bae9465e527e450e0bc60a5/cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47", size = 2617948 }, - { url = "https://files.pythonhosted.org/packages/b3/c6/c09cee6968add5ff868525c3815e5dccc0e3c6e89eec58dc9135d3c40e88/cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb", size = 3070445 }, +sdist = { url = "https://files.pythonhosted.org/packages/0d/05/07b55d1fa21ac18c3a8c79f764e2514e6f6a9698f1be44994f5adf0d29db/cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805", size = 686989 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/f3/01fdf26701a26f4b4dbc337a26883ad5bccaa6f1bbbdd29cd89e22f18a1c/cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e", size = 6225303 }, + { url = "https://files.pythonhosted.org/packages/a3/01/4896f3d1b392025d4fcbecf40fdea92d3df8662123f6835d0af828d148fd/cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e", size = 3760905 }, + { url = "https://files.pythonhosted.org/packages/0a/be/f9a1f673f0ed4b7f6c643164e513dbad28dd4f2dcdf5715004f172ef24b6/cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f", size = 3977271 }, + { url = "https://files.pythonhosted.org/packages/4e/49/80c3a7b5514d1b416d7350830e8c422a4d667b6d9b16a9392ebfd4a5388a/cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6", size = 3746606 }, + { url = "https://files.pythonhosted.org/packages/0e/16/a28ddf78ac6e7e3f25ebcef69ab15c2c6be5ff9743dd0709a69a4f968472/cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18", size = 3986484 }, + { url = "https://files.pythonhosted.org/packages/01/f5/69ae8da70c19864a32b0315049866c4d411cce423ec169993d0434218762/cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd", size = 3852131 }, + { url = "https://files.pythonhosted.org/packages/fd/db/e74911d95c040f9afd3612b1f732e52b3e517cb80de8bf183be0b7d413c6/cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73", size = 4075647 }, + { url = "https://files.pythonhosted.org/packages/56/48/7b6b190f1462818b324e674fa20d1d5ef3e24f2328675b9b16189cbf0b3c/cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2", size = 2623873 }, + { url = "https://files.pythonhosted.org/packages/eb/b1/0ebff61a004f7f89e7b65ca95f2f2375679d43d0290672f7713ee3162aff/cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd", size = 3068039 }, + { url = "https://files.pythonhosted.org/packages/30/d5/c8b32c047e2e81dd172138f772e81d852c51f0f2ad2ae8a24f1122e9e9a7/cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984", size = 6222984 }, + { url = "https://files.pythonhosted.org/packages/2f/78/55356eb9075d0be6e81b59f45c7b48df87f76a20e73893872170471f3ee8/cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5", size = 3762968 }, + { url = "https://files.pythonhosted.org/packages/2a/2c/488776a3dc843f95f86d2f957ca0fc3407d0242b50bede7fad1e339be03f/cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4", size = 3977754 }, + { url = "https://files.pythonhosted.org/packages/7c/04/2345ca92f7a22f601a9c62961741ef7dd0127c39f7310dffa0041c80f16f/cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7", size = 3749458 }, + { url = "https://files.pythonhosted.org/packages/ac/25/e715fa0bc24ac2114ed69da33adf451a38abb6f3f24ec207908112e9ba53/cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405", size = 3988220 }, + { url = "https://files.pythonhosted.org/packages/21/ce/b9c9ff56c7164d8e2edfb6c9305045fbc0df4508ccfdb13ee66eb8c95b0e/cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16", size = 3853898 }, + { url = "https://files.pythonhosted.org/packages/2a/33/b3682992ab2e9476b9c81fff22f02c8b0a1e6e1d49ee1750a67d85fd7ed2/cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73", size = 4076592 }, + { url = "https://files.pythonhosted.org/packages/81/1e/ffcc41b3cebd64ca90b28fd58141c5f68c83d48563c88333ab660e002cd3/cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995", size = 2623145 }, + { url = "https://files.pythonhosted.org/packages/87/5c/3dab83cc4aba1f4b0e733e3f0c3e7d4386440d660ba5b1e3ff995feb734d/cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362", size = 3068026 }, ] [[package]] @@ -451,11 +492,11 @@ wheels = [ [[package]] name = "dnspython" -version = "2.6.1" +version = "2.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/37/7d/c871f55054e403fdfd6b8f65fd6d1c4e147ed100d3e9f9ba1fe695403939/dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc", size = 332727 } +sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197 } wheels = [ - { url = "https://files.pythonhosted.org/packages/87/a1/8c5287991ddb8d3e4662f71356d9656d91ab3a36618c3dd11b280df0d255/dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50", size = 307696 }, + { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632 }, ] [[package]] @@ -503,16 +544,16 @@ requires-dist = [{ name = "pydantic", specifier = ">=2.6.1" }] [[package]] name = "fastapi" -version = "0.115.0" +version = "0.115.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "starlette" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7b/5e/bf0471f14bf6ebfbee8208148a3396d1a23298531a6cc10776c59f4c0f87/fastapi-0.115.0.tar.gz", hash = "sha256:f93b4ca3529a8ebc6fc3fcf710e5efa8de3df9b41570958abf1d97d843138004", size = 302295 } +sdist = { url = "https://files.pythonhosted.org/packages/a9/db/5781f19bd30745885e0737ff3fdd4e63e7bc691710f9da691128bb0dc73b/fastapi-0.115.4.tar.gz", hash = "sha256:db653475586b091cb8b2fec2ac54a680ac6a158e07406e1abae31679e8826349", size = 300737 } wheels = [ - { url = "https://files.pythonhosted.org/packages/06/ab/a1f7eed031aeb1c406a6e9d45ca04bff401c8a25a30dd0e4fd2caae767c3/fastapi-0.115.0-py3-none-any.whl", hash = "sha256:17ea427674467486e997206a5ab25760f6b09e069f099b96f5b55a32fb6f1631", size = 94625 }, + { url = "https://files.pythonhosted.org/packages/99/f6/af0d1f58f86002be0cf1e2665cdd6f7a4a71cdc8a7a9438cdc9e3b5375fe/fastapi-0.115.4-py3-none-any.whl", hash = "sha256:0b504a063ffb3cf96a5e27dc1bc32c80ca743a2528574f9cdc77daa2d31b4742", size = 94732 }, ] [package.optional-dependencies] @@ -545,41 +586,56 @@ standard = [ [[package]] name = "frozenlist" -version = "1.4.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/cf/3d/2102257e7acad73efc4a0c306ad3953f68c504c16982bbdfee3ad75d8085/frozenlist-1.4.1.tar.gz", hash = "sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b", size = 37820 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/01/bc/8d33f2d84b9368da83e69e42720cff01c5e199b5a868ba4486189a4d8fa9/frozenlist-1.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0", size = 97060 }, - { url = "https://files.pythonhosted.org/packages/af/b2/904500d6a162b98a70e510e743e7ea992241b4f9add2c8063bf666ca21df/frozenlist-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49", size = 55347 }, - { url = "https://files.pythonhosted.org/packages/5b/9c/f12b69997d3891ddc0d7895999a00b0c6a67f66f79498c0e30f27876435d/frozenlist-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced", size = 53374 }, - { url = "https://files.pythonhosted.org/packages/ac/6e/e0322317b7c600ba21dec224498c0c5959b2bce3865277a7c0badae340a9/frozenlist-1.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0", size = 273288 }, - { url = "https://files.pythonhosted.org/packages/a7/76/180ee1b021568dad5b35b7678616c24519af130ed3fa1e0f1ed4014e0f93/frozenlist-1.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106", size = 284737 }, - { url = "https://files.pythonhosted.org/packages/05/08/40159d706a6ed983c8aca51922a93fc69f3c27909e82c537dd4054032674/frozenlist-1.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068", size = 280267 }, - { url = "https://files.pythonhosted.org/packages/e0/18/9f09f84934c2b2aa37d539a322267939770362d5495f37783440ca9c1b74/frozenlist-1.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2", size = 258778 }, - { url = "https://files.pythonhosted.org/packages/b3/c9/0bc5ee7e1f5cc7358ab67da0b7dfe60fbd05c254cea5c6108e7d1ae28c63/frozenlist-1.4.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19", size = 272276 }, - { url = "https://files.pythonhosted.org/packages/12/5d/147556b73a53ad4df6da8bbb50715a66ac75c491fdedac3eca8b0b915345/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82", size = 272424 }, - { url = "https://files.pythonhosted.org/packages/83/61/2087bbf24070b66090c0af922685f1d0596c24bb3f3b5223625bdeaf03ca/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec", size = 260881 }, - { url = "https://files.pythonhosted.org/packages/a8/be/a235bc937dd803258a370fe21b5aa2dd3e7bfe0287a186a4bec30c6cccd6/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a", size = 282327 }, - { url = "https://files.pythonhosted.org/packages/5d/e7/b2469e71f082948066b9382c7b908c22552cc705b960363c390d2e23f587/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74", size = 281502 }, - { url = "https://files.pythonhosted.org/packages/db/1b/6a5b970e55dffc1a7d0bb54f57b184b2a2a2ad0b7bca16a97ca26d73c5b5/frozenlist-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2", size = 272292 }, - { url = "https://files.pythonhosted.org/packages/1a/05/ebad68130e6b6eb9b287dacad08ea357c33849c74550c015b355b75cc714/frozenlist-1.4.1-cp311-cp311-win32.whl", hash = "sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17", size = 44446 }, - { url = "https://files.pythonhosted.org/packages/b3/21/c5aaffac47fd305d69df46cfbf118768cdf049a92ee6b0b5cb029d449dcf/frozenlist-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825", size = 50459 }, - { url = "https://files.pythonhosted.org/packages/b4/db/4cf37556a735bcdb2582f2c3fa286aefde2322f92d3141e087b8aeb27177/frozenlist-1.4.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae", size = 93937 }, - { url = "https://files.pythonhosted.org/packages/46/03/69eb64642ca8c05f30aa5931d6c55e50b43d0cd13256fdd01510a1f85221/frozenlist-1.4.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb", size = 53656 }, - { url = "https://files.pythonhosted.org/packages/3f/ab/c543c13824a615955f57e082c8a5ee122d2d5368e80084f2834e6f4feced/frozenlist-1.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b", size = 51868 }, - { url = "https://files.pythonhosted.org/packages/a9/b8/438cfd92be2a124da8259b13409224d9b19ef8f5a5b2507174fc7e7ea18f/frozenlist-1.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86", size = 280652 }, - { url = "https://files.pythonhosted.org/packages/54/72/716a955521b97a25d48315c6c3653f981041ce7a17ff79f701298195bca3/frozenlist-1.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480", size = 286739 }, - { url = "https://files.pythonhosted.org/packages/65/d8/934c08103637567084568e4d5b4219c1016c60b4d29353b1a5b3587827d6/frozenlist-1.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09", size = 289447 }, - { url = "https://files.pythonhosted.org/packages/70/bb/d3b98d83ec6ef88f9bd63d77104a305d68a146fd63a683569ea44c3085f6/frozenlist-1.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a", size = 265466 }, - { url = "https://files.pythonhosted.org/packages/0b/f2/b8158a0f06faefec33f4dff6345a575c18095a44e52d4f10c678c137d0e0/frozenlist-1.4.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd", size = 281530 }, - { url = "https://files.pythonhosted.org/packages/ea/a2/20882c251e61be653764038ece62029bfb34bd5b842724fff32a5b7a2894/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6", size = 281295 }, - { url = "https://files.pythonhosted.org/packages/4c/f9/8894c05dc927af2a09663bdf31914d4fb5501653f240a5bbaf1e88cab1d3/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1", size = 268054 }, - { url = "https://files.pythonhosted.org/packages/37/ff/a613e58452b60166507d731812f3be253eb1229808e59980f0405d1eafbf/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b", size = 286904 }, - { url = "https://files.pythonhosted.org/packages/cc/6e/0091d785187f4c2020d5245796d04213f2261ad097e0c1cf35c44317d517/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e", size = 290754 }, - { url = "https://files.pythonhosted.org/packages/a5/c2/e42ad54bae8bcffee22d1e12a8ee6c7717f7d5b5019261a8c861854f4776/frozenlist-1.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8", size = 282602 }, - { url = "https://files.pythonhosted.org/packages/b6/61/56bad8cb94f0357c4bc134acc30822e90e203b5cb8ff82179947de90c17f/frozenlist-1.4.1-cp312-cp312-win32.whl", hash = "sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89", size = 44063 }, - { url = "https://files.pythonhosted.org/packages/3e/dc/96647994a013bc72f3d453abab18340b7f5e222b7b7291e3697ca1fcfbd5/frozenlist-1.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5", size = 50452 }, - { url = "https://files.pythonhosted.org/packages/83/10/466fe96dae1bff622021ee687f68e5524d6392b0a2f80d05001cd3a451ba/frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7", size = 11552 }, +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8f/ed/0f4cec13a93c02c47ec32d81d11c0c1efbadf4a471e3f3ce7cad366cbbd3/frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817", size = 39930 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/43/0bed28bf5eb1c9e4301003b74453b8e7aa85fb293b31dde352aac528dafc/frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30", size = 94987 }, + { url = "https://files.pythonhosted.org/packages/bb/bf/b74e38f09a246e8abbe1e90eb65787ed745ccab6eaa58b9c9308e052323d/frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5", size = 54584 }, + { url = "https://files.pythonhosted.org/packages/2c/31/ab01375682f14f7613a1ade30149f684c84f9b8823a4391ed950c8285656/frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778", size = 52499 }, + { url = "https://files.pythonhosted.org/packages/98/a8/d0ac0b9276e1404f58fec3ab6e90a4f76b778a49373ccaf6a563f100dfbc/frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a", size = 276357 }, + { url = "https://files.pythonhosted.org/packages/ad/c9/c7761084fa822f07dac38ac29f841d4587570dd211e2262544aa0b791d21/frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869", size = 287516 }, + { url = "https://files.pythonhosted.org/packages/a1/ff/cd7479e703c39df7bdab431798cef89dc75010d8aa0ca2514c5b9321db27/frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d", size = 283131 }, + { url = "https://files.pythonhosted.org/packages/59/a0/370941beb47d237eca4fbf27e4e91389fd68699e6f4b0ebcc95da463835b/frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45", size = 261320 }, + { url = "https://files.pythonhosted.org/packages/b8/5f/c10123e8d64867bc9b4f2f510a32042a306ff5fcd7e2e09e5ae5100ee333/frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d", size = 274877 }, + { url = "https://files.pythonhosted.org/packages/fa/79/38c505601ae29d4348f21706c5d89755ceded02a745016ba2f58bd5f1ea6/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3", size = 269592 }, + { url = "https://files.pythonhosted.org/packages/19/e2/39f3a53191b8204ba9f0bb574b926b73dd2efba2a2b9d2d730517e8f7622/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a", size = 265934 }, + { url = "https://files.pythonhosted.org/packages/d5/c9/3075eb7f7f3a91f1a6b00284af4de0a65a9ae47084930916f5528144c9dd/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9", size = 283859 }, + { url = "https://files.pythonhosted.org/packages/05/f5/549f44d314c29408b962fa2b0e69a1a67c59379fb143b92a0a065ffd1f0f/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2", size = 287560 }, + { url = "https://files.pythonhosted.org/packages/9d/f8/cb09b3c24a3eac02c4c07a9558e11e9e244fb02bf62c85ac2106d1eb0c0b/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf", size = 277150 }, + { url = "https://files.pythonhosted.org/packages/37/48/38c2db3f54d1501e692d6fe058f45b6ad1b358d82cd19436efab80cfc965/frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942", size = 45244 }, + { url = "https://files.pythonhosted.org/packages/ca/8c/2ddffeb8b60a4bce3b196c32fcc30d8830d4615e7b492ec2071da801b8ad/frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d", size = 51634 }, + { url = "https://files.pythonhosted.org/packages/79/73/fa6d1a96ab7fd6e6d1c3500700963eab46813847f01ef0ccbaa726181dd5/frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21", size = 94026 }, + { url = "https://files.pythonhosted.org/packages/ab/04/ea8bf62c8868b8eada363f20ff1b647cf2e93377a7b284d36062d21d81d1/frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d", size = 54150 }, + { url = "https://files.pythonhosted.org/packages/d0/9a/8e479b482a6f2070b26bda572c5e6889bb3ba48977e81beea35b5ae13ece/frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e", size = 51927 }, + { url = "https://files.pythonhosted.org/packages/e3/12/2aad87deb08a4e7ccfb33600871bbe8f0e08cb6d8224371387f3303654d7/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a", size = 282647 }, + { url = "https://files.pythonhosted.org/packages/77/f2/07f06b05d8a427ea0060a9cef6e63405ea9e0d761846b95ef3fb3be57111/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a", size = 289052 }, + { url = "https://files.pythonhosted.org/packages/bd/9f/8bf45a2f1cd4aa401acd271b077989c9267ae8463e7c8b1eb0d3f561b65e/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee", size = 291719 }, + { url = "https://files.pythonhosted.org/packages/41/d1/1f20fd05a6c42d3868709b7604c9f15538a29e4f734c694c6bcfc3d3b935/frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6", size = 267433 }, + { url = "https://files.pythonhosted.org/packages/af/f2/64b73a9bb86f5a89fb55450e97cd5c1f84a862d4ff90d9fd1a73ab0f64a5/frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e", size = 283591 }, + { url = "https://files.pythonhosted.org/packages/29/e2/ffbb1fae55a791fd6c2938dd9ea779509c977435ba3940b9f2e8dc9d5316/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9", size = 273249 }, + { url = "https://files.pythonhosted.org/packages/2e/6e/008136a30798bb63618a114b9321b5971172a5abddff44a100c7edc5ad4f/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039", size = 271075 }, + { url = "https://files.pythonhosted.org/packages/ae/f0/4e71e54a026b06724cec9b6c54f0b13a4e9e298cc8db0f82ec70e151f5ce/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784", size = 285398 }, + { url = "https://files.pythonhosted.org/packages/4d/36/70ec246851478b1c0b59f11ef8ade9c482ff447c1363c2bd5fad45098b12/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631", size = 294445 }, + { url = "https://files.pythonhosted.org/packages/37/e0/47f87544055b3349b633a03c4d94b405956cf2437f4ab46d0928b74b7526/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f", size = 280569 }, + { url = "https://files.pythonhosted.org/packages/f9/7c/490133c160fb6b84ed374c266f42800e33b50c3bbab1652764e6e1fc498a/frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8", size = 44721 }, + { url = "https://files.pythonhosted.org/packages/b1/56/4e45136ffc6bdbfa68c29ca56ef53783ef4c2fd395f7cbf99a2624aa9aaa/frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f", size = 51329 }, + { url = "https://files.pythonhosted.org/packages/da/3b/915f0bca8a7ea04483622e84a9bd90033bab54bdf485479556c74fd5eaf5/frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953", size = 91538 }, + { url = "https://files.pythonhosted.org/packages/c7/d1/a7c98aad7e44afe5306a2b068434a5830f1470675f0e715abb86eb15f15b/frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0", size = 52849 }, + { url = "https://files.pythonhosted.org/packages/3a/c8/76f23bf9ab15d5f760eb48701909645f686f9c64fbb8982674c241fbef14/frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2", size = 50583 }, + { url = "https://files.pythonhosted.org/packages/1f/22/462a3dd093d11df623179d7754a3b3269de3b42de2808cddef50ee0f4f48/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f", size = 265636 }, + { url = "https://files.pythonhosted.org/packages/80/cf/e075e407fc2ae7328155a1cd7e22f932773c8073c1fc78016607d19cc3e5/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608", size = 270214 }, + { url = "https://files.pythonhosted.org/packages/a1/58/0642d061d5de779f39c50cbb00df49682832923f3d2ebfb0fedf02d05f7f/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b", size = 273905 }, + { url = "https://files.pythonhosted.org/packages/ab/66/3fe0f5f8f2add5b4ab7aa4e199f767fd3b55da26e3ca4ce2cc36698e50c4/frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840", size = 250542 }, + { url = "https://files.pythonhosted.org/packages/f6/b8/260791bde9198c87a465224e0e2bb62c4e716f5d198fc3a1dacc4895dbd1/frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439", size = 267026 }, + { url = "https://files.pythonhosted.org/packages/2e/a4/3d24f88c527f08f8d44ade24eaee83b2627793fa62fa07cbb7ff7a2f7d42/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de", size = 257690 }, + { url = "https://files.pythonhosted.org/packages/de/9a/d311d660420b2beeff3459b6626f2ab4fb236d07afbdac034a4371fe696e/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641", size = 253893 }, + { url = "https://files.pythonhosted.org/packages/c6/23/e491aadc25b56eabd0f18c53bb19f3cdc6de30b2129ee0bc39cd387cd560/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e", size = 267006 }, + { url = "https://files.pythonhosted.org/packages/08/c4/ab918ce636a35fb974d13d666dcbe03969592aeca6c3ab3835acff01f79c/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9", size = 276157 }, + { url = "https://files.pythonhosted.org/packages/c0/29/3b7a0bbbbe5a34833ba26f686aabfe982924adbdcafdc294a7a129c31688/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03", size = 264642 }, + { url = "https://files.pythonhosted.org/packages/ab/42/0595b3dbffc2e82d7fe658c12d5a5bafcd7516c6bf2d1d1feb5387caa9c1/frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c", size = 44914 }, + { url = "https://files.pythonhosted.org/packages/17/c4/b7db1206a3fea44bf3b838ca61deb6f74424a8a5db1dd53ecb21da669be6/frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28", size = 51167 }, + { url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 }, ] [[package]] @@ -640,24 +696,31 @@ wheels = [ [[package]] name = "httptools" -version = "0.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/67/1d/d77686502fced061b3ead1c35a2d70f6b281b5f723c4eff7a2277c04e4a2/httptools-0.6.1.tar.gz", hash = "sha256:c6e26c30455600b95d94b1b836085138e82f177351454ee841c148f93a9bad5a", size = 191228 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f5/d1/53283b96ed823d5e4d89ee9aa0f29df5a1bdf67f148e061549a595d534e4/httptools-0.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7a7ea483c1a4485c71cb5f38be9db078f8b0e8b4c4dc0210f531cdd2ddac1ef1", size = 145855 }, - { url = "https://files.pythonhosted.org/packages/80/dd/cebc9d4b1d4b70e9f3d40d1db0829a28d57ca139d0b04197713816a11996/httptools-0.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:85ed077c995e942b6f1b07583e4eb0a8d324d418954fc6af913d36db7c05a5a0", size = 75604 }, - { url = "https://files.pythonhosted.org/packages/76/7a/45c5a9a2e9d21f7381866eb7b6ead5a84d8fe7e54e35208eeb18320a29b4/httptools-0.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0bb634338334385351a1600a73e558ce619af390c2b38386206ac6a27fecfc", size = 324784 }, - { url = "https://files.pythonhosted.org/packages/59/23/047a89e66045232fb82c50ae57699e40f70e073ae5ccd53f54e532fbd2a2/httptools-0.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d9ceb2c957320def533671fc9c715a80c47025139c8d1f3797477decbc6edd2", size = 318547 }, - { url = "https://files.pythonhosted.org/packages/82/f5/50708abc7965d7d93c0ee14a148ccc6d078a508f47fe9357c79d5360f252/httptools-0.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4f0f8271c0a4db459f9dc807acd0eadd4839934a4b9b892f6f160e94da309837", size = 330211 }, - { url = "https://files.pythonhosted.org/packages/e3/1e/9823ca7aab323c0e0e9dd82ce835a6e93b69f69aedffbc94d31e327f4283/httptools-0.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6a4f5ccead6d18ec072ac0b84420e95d27c1cdf5c9f1bc8fbd8daf86bd94f43d", size = 322174 }, - { url = "https://files.pythonhosted.org/packages/14/e4/20d28dfe7f5b5603b6b04c33bb88662ad749de51f0c539a561f235f42666/httptools-0.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:5cceac09f164bcba55c0500a18fe3c47df29b62353198e4f37bbcc5d591172c3", size = 55434 }, - { url = "https://files.pythonhosted.org/packages/60/13/b62e086b650752adf9094b7e62dab97f4cb7701005664544494b7956a51e/httptools-0.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:75c8022dca7935cba14741a42744eee13ba05db00b27a4b940f0d646bd4d56d0", size = 146354 }, - { url = "https://files.pythonhosted.org/packages/f8/5d/9ad32b79b6c24524087e78aa3f0a2dfcf58c11c90e090e4593b35def8a86/httptools-0.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:48ed8129cd9a0d62cf4d1575fcf90fb37e3ff7d5654d3a5814eb3d55f36478c2", size = 75785 }, - { url = "https://files.pythonhosted.org/packages/d0/a4/b503851c40f20bcbd453db24ed35d961f62abdae0dccc8f672cd5d350d87/httptools-0.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f58e335a1402fb5a650e271e8c2d03cfa7cea46ae124649346d17bd30d59c90", size = 345396 }, - { url = "https://files.pythonhosted.org/packages/a2/9a/aa406864f3108e06f7320425a528ff8267124dead1fd72a3e9da2067f893/httptools-0.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93ad80d7176aa5788902f207a4e79885f0576134695dfb0fefc15b7a4648d503", size = 344741 }, - { url = "https://files.pythonhosted.org/packages/cf/3a/3fd8dfb987c4247651baf2ac6f28e8e9f889d484ca1a41a9ad0f04dfe300/httptools-0.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9bb68d3a085c2174c2477eb3ffe84ae9fb4fde8792edb7bcd09a1d8467e30a84", size = 345096 }, - { url = "https://files.pythonhosted.org/packages/80/01/379f6466d8e2edb861c1f44ccac255ed1f8a0d4c5c666a1ceb34caad7555/httptools-0.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b512aa728bc02354e5ac086ce76c3ce635b62f5fbc32ab7082b5e582d27867bb", size = 343535 }, - { url = "https://files.pythonhosted.org/packages/d3/97/60860e9ee87a7d4712b98f7e1411730520053b9d69e9e42b0b9751809c17/httptools-0.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:97662ce7fb196c785344d00d638fc9ad69e18ee4bfb4000b35a52efe5adcc949", size = 55660 }, +version = "0.6.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/26/bb526d4d14c2774fe07113ca1db7255737ffbb119315839af2065abfdac3/httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069", size = 199029 }, + { url = "https://files.pythonhosted.org/packages/a6/17/3e0d3e9b901c732987a45f4f94d4e2c62b89a041d93db89eafb262afd8d5/httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a", size = 103492 }, + { url = "https://files.pythonhosted.org/packages/b7/24/0fe235d7b69c42423c7698d086d4db96475f9b50b6ad26a718ef27a0bce6/httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975", size = 462891 }, + { url = "https://files.pythonhosted.org/packages/b1/2f/205d1f2a190b72da6ffb5f41a3736c26d6fa7871101212b15e9b5cd8f61d/httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636", size = 459788 }, + { url = "https://files.pythonhosted.org/packages/6e/4c/d09ce0eff09057a206a74575ae8f1e1e2f0364d20e2442224f9e6612c8b9/httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721", size = 433214 }, + { url = "https://files.pythonhosted.org/packages/3e/d2/84c9e23edbccc4a4c6f96a1b8d99dfd2350289e94f00e9ccc7aadde26fb5/httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988", size = 434120 }, + { url = "https://files.pythonhosted.org/packages/d0/46/4d8e7ba9581416de1c425b8264e2cadd201eb709ec1584c381f3e98f51c1/httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17", size = 88565 }, + { url = "https://files.pythonhosted.org/packages/bb/0e/d0b71465c66b9185f90a091ab36389a7352985fe857e352801c39d6127c8/httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2", size = 200683 }, + { url = "https://files.pythonhosted.org/packages/e2/b8/412a9bb28d0a8988de3296e01efa0bd62068b33856cdda47fe1b5e890954/httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44", size = 104337 }, + { url = "https://files.pythonhosted.org/packages/9b/01/6fb20be3196ffdc8eeec4e653bc2a275eca7f36634c86302242c4fbb2760/httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1", size = 508796 }, + { url = "https://files.pythonhosted.org/packages/f7/d8/b644c44acc1368938317d76ac991c9bba1166311880bcc0ac297cb9d6bd7/httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2", size = 510837 }, + { url = "https://files.pythonhosted.org/packages/52/d8/254d16a31d543073a0e57f1c329ca7378d8924e7e292eda72d0064987486/httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81", size = 485289 }, + { url = "https://files.pythonhosted.org/packages/5f/3c/4aee161b4b7a971660b8be71a92c24d6c64372c1ab3ae7f366b3680df20f/httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", size = 489779 }, + { url = "https://files.pythonhosted.org/packages/12/b7/5cae71a8868e555f3f67a50ee7f673ce36eac970f029c0c5e9d584352961/httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970", size = 88634 }, + { url = "https://files.pythonhosted.org/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214 }, + { url = "https://files.pythonhosted.org/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431 }, + { url = "https://files.pythonhosted.org/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121 }, + { url = "https://files.pythonhosted.org/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071", size = 473805 }, + { url = "https://files.pythonhosted.org/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858 }, + { url = "https://files.pythonhosted.org/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042 }, + { url = "https://files.pythonhosted.org/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682 }, ] [[package]] @@ -696,14 +759,11 @@ wheels = [ [[package]] name = "isodate" -version = "0.6.1" +version = "0.7.2" source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/db/7a/c0a56c7d56c7fa723988f122fa1f1ccf8c5c4ccc48efad0d214b49e5b1af/isodate-0.6.1.tar.gz", hash = "sha256:48c5881de7e8b0a0d648cb024c8062dc84e7b840ed81e864c7614fd3c127bde9", size = 28443 } +sdist = { url = "https://files.pythonhosted.org/packages/54/4d/e940025e2ce31a8ce1202635910747e5a87cc3a6a6bb2d00973375014749/isodate-0.7.2.tar.gz", hash = "sha256:4cd1aa0f43ca76f4a6c6c0292a85f40b35ec2e43e315b59f06e6d32171a953e6", size = 29705 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/85/7882d311924cbcfc70b1890780763e36ff0b140c7e51c110fc59a532f087/isodate-0.6.1-py2.py3-none-any.whl", hash = "sha256:0751eece944162659049d35f4f549ed815792b38793f07cf73381c1c87cbed96", size = 41722 }, + { url = "https://files.pythonhosted.org/packages/15/aa/0aca39a37d3c7eb941ba736ede56d689e7be91cab5d9ca846bde3999eba6/isodate-0.7.2-py3-none-any.whl", hash = "sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15", size = 22320 }, ] [[package]] @@ -720,34 +780,46 @@ wheels = [ [[package]] name = "jiter" -version = "0.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/1a/aa64be757afc614484b370a4d9fc1747dc9237b37ce464f7f9d9ca2a3d38/jiter-0.5.0.tar.gz", hash = "sha256:1d916ba875bcab5c5f7d927df998c4cb694d27dceddf3392e58beaf10563368a", size = 158300 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/5f/3ac960ed598726aae46edea916e6df4df7ff6fe084bc60774b95cf3154e6/jiter-0.5.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d4c8e1ed0ef31ad29cae5ea16b9e41529eb50a7fba70600008e9f8de6376d553", size = 284131 }, - { url = "https://files.pythonhosted.org/packages/03/eb/2308fa5f5c14c97c4c7720fef9465f1fa0771826cddb4eec9866bdd88846/jiter-0.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6f16e21276074a12d8421692515b3fd6d2ea9c94fd0734c39a12960a20e85f3", size = 299310 }, - { url = "https://files.pythonhosted.org/packages/3c/f6/dba34ca10b44715fa5302b8e8d2113f72eb00a9297ddf3fa0ae4fd22d1d1/jiter-0.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5280e68e7740c8c128d3ae5ab63335ce6d1fb6603d3b809637b11713487af9e6", size = 332282 }, - { url = "https://files.pythonhosted.org/packages/69/f7/64e0a7439790ec47f7681adb3871c9d9c45fff771102490bbee5e92c00b7/jiter-0.5.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:583c57fc30cc1fec360e66323aadd7fc3edeec01289bfafc35d3b9dcb29495e4", size = 342370 }, - { url = "https://files.pythonhosted.org/packages/55/31/1efbfff2ae8e4d919144c53db19b828049ad0622a670be3bbea94a86282c/jiter-0.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26351cc14507bdf466b5f99aba3df3143a59da75799bf64a53a3ad3155ecded9", size = 363591 }, - { url = "https://files.pythonhosted.org/packages/30/c3/7ab2ca2276426a7398c6dfb651e38dbc81954c79a3bfbc36c514d8599499/jiter-0.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4829df14d656b3fb87e50ae8b48253a8851c707da9f30d45aacab2aa2ba2d614", size = 378551 }, - { url = "https://files.pythonhosted.org/packages/47/e7/5d88031cd743c62199b125181a591b1671df3ff2f6e102df85c58d8f7d31/jiter-0.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a42a4bdcf7307b86cb863b2fb9bb55029b422d8f86276a50487982d99eed7c6e", size = 319152 }, - { url = "https://files.pythonhosted.org/packages/4c/2d/09ea58e1adca9f0359f3d41ef44a1a18e59518d7c43a21f4ece9e72e28c0/jiter-0.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04d461ad0aebf696f8da13c99bc1b3e06f66ecf6cfd56254cc402f6385231c06", size = 357377 }, - { url = "https://files.pythonhosted.org/packages/7d/2f/83ff1058cb56fc3ff73e0d3c6440703ddc9cdb7f759b00cfbde8228fc435/jiter-0.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e6375923c5f19888c9226582a124b77b622f8fd0018b843c45eeb19d9701c403", size = 511091 }, - { url = "https://files.pythonhosted.org/packages/ae/c9/4f85f97c9894382ab457382337aea0012711baaa17f2ed55c0ff25f3668a/jiter-0.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2cec323a853c24fd0472517113768c92ae0be8f8c384ef4441d3632da8baa646", size = 492948 }, - { url = "https://files.pythonhosted.org/packages/4d/f2/2e987e0eb465e064c5f52c2f29c8d955452e3b316746e326269263bfb1b7/jiter-0.5.0-cp311-none-win32.whl", hash = "sha256:aa1db0967130b5cab63dfe4d6ff547c88b2a394c3410db64744d491df7f069bb", size = 195183 }, - { url = "https://files.pythonhosted.org/packages/ab/59/05d1c3203c349b37c4dd28b02b9b4e5915a7bcbd9319173b4548a67d2e93/jiter-0.5.0-cp311-none-win_amd64.whl", hash = "sha256:aa9d2b85b2ed7dc7697597dcfaac66e63c1b3028652f751c81c65a9f220899ae", size = 191032 }, - { url = "https://files.pythonhosted.org/packages/aa/bd/c3950e2c478161e131bed8cb67c36aed418190e2a961a1c981e69954e54b/jiter-0.5.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9f664e7351604f91dcdd557603c57fc0d551bc65cc0a732fdacbf73ad335049a", size = 283511 }, - { url = "https://files.pythonhosted.org/packages/80/1c/8ce58d8c37a589eeaaa5d07d131fd31043886f5e77ab50c00a66d869a361/jiter-0.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:044f2f1148b5248ad2c8c3afb43430dccf676c5a5834d2f5089a4e6c5bbd64df", size = 296974 }, - { url = "https://files.pythonhosted.org/packages/4d/b8/6faeff9eed8952bed93a77ea1cffae7b946795b88eafd1a60e87a67b09e0/jiter-0.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:702e3520384c88b6e270c55c772d4bd6d7b150608dcc94dea87ceba1b6391248", size = 331897 }, - { url = "https://files.pythonhosted.org/packages/4f/54/1d9a2209b46d39ce6f0cef3ad87c462f9c50312ab84585e6bd5541292b35/jiter-0.5.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:528d742dcde73fad9d63e8242c036ab4a84389a56e04efd854062b660f559544", size = 342962 }, - { url = "https://files.pythonhosted.org/packages/2a/de/90360be7fc54b2b4c2dfe79eb4ed1f659fce9c96682e6a0be4bbe71371f7/jiter-0.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8cf80e5fe6ab582c82f0c3331df27a7e1565e2dcf06265afd5173d809cdbf9ba", size = 363844 }, - { url = "https://files.pythonhosted.org/packages/ba/ad/ef32b173191b7a53ea8a6757b80723cba321f8469834825e8c71c96bde17/jiter-0.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:44dfc9ddfb9b51a5626568ef4e55ada462b7328996294fe4d36de02fce42721f", size = 378709 }, - { url = "https://files.pythonhosted.org/packages/07/de/353ce53743c0defbbbd652e89c106a97dbbac4eb42c95920b74b5056b93a/jiter-0.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c451f7922992751a936b96c5f5b9bb9312243d9b754c34b33d0cb72c84669f4e", size = 319038 }, - { url = "https://files.pythonhosted.org/packages/3f/92/42d47310bf9530b9dece9e2d7c6d51cf419af5586ededaf5e66622d160e2/jiter-0.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:308fce789a2f093dca1ff91ac391f11a9f99c35369117ad5a5c6c4903e1b3e3a", size = 357763 }, - { url = "https://files.pythonhosted.org/packages/bd/8c/2bb76a9a84474d48fdd133d3445db8a4413da4e87c23879d917e000a9d87/jiter-0.5.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7f5ad4a7c6b0d90776fdefa294f662e8a86871e601309643de30bf94bb93a64e", size = 511031 }, - { url = "https://files.pythonhosted.org/packages/33/4f/9f23d79c0795e0a8e56e7988e8785c2dcda27e0ed37977256d50c77c6a19/jiter-0.5.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ea189db75f8eca08807d02ae27929e890c7d47599ce3d0a6a5d41f2419ecf338", size = 493042 }, - { url = "https://files.pythonhosted.org/packages/df/67/8a4f975aa834b8aecdb6b131422390173928fd47f42f269dcc32034ab432/jiter-0.5.0-cp312-none-win32.whl", hash = "sha256:e3bbe3910c724b877846186c25fe3c802e105a2c1fc2b57d6688b9f8772026e4", size = 195405 }, - { url = "https://files.pythonhosted.org/packages/15/81/296b1e25c43db67848728cdab34ac3eb5c5cbb4955ceb3f51ae60d4a5e3d/jiter-0.5.0-cp312-none-win_amd64.whl", hash = "sha256:a586832f70c3f1481732919215f36d41c59ca080fa27a65cf23d9490e75b2ef5", size = 189720 }, +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ac/3d/4ca1c6b8d1d15ea747da474891f9879c0f0777e2e44e87c0be81657ed016/jiter-0.7.0.tar.gz", hash = "sha256:c061d9738535497b5509f8970584f20de1e900806b239a39a9994fc191dad630", size = 162154 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/01/ac41fe6d402da0ff454e2abaee6b8cc29ad2c97cf985f503e46ca7724aca/jiter-0.7.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:91cec0ad755bd786c9f769ce8d843af955df6a8e56b17658771b2d5cb34a3ff8", size = 292667 }, + { url = "https://files.pythonhosted.org/packages/9d/cb/d2e612729676cbe022ad732aaed9c842ac459a70808a927f7f845cfc6dc1/jiter-0.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:feba70a28a27d962e353e978dbb6afd798e711c04cb0b4c5e77e9d3779033a1a", size = 306403 }, + { url = "https://files.pythonhosted.org/packages/e9/db/d88002c550f6405dbf98962cc3dc1c8e66de9c4f3246abebe1582b2f919f/jiter-0.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9d866ec066c3616cacb8535dbda38bb1d470b17b25f0317c4540182bc886ce2", size = 329020 }, + { url = "https://files.pythonhosted.org/packages/18/42/54d6527bcdea2909396849491b96a6fe595bd97ec43bdc522399c534ed33/jiter-0.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8e7a7a00b6f9f18289dd563596f97ecaba6c777501a8ba04bf98e03087bcbc60", size = 347638 }, + { url = "https://files.pythonhosted.org/packages/ec/12/a3c43061d5e189def91c07472e64a569196687f60c2f86150e29a5692ce7/jiter-0.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9aaf564094c7db8687f2660605e099f3d3e6ea5e7135498486674fcb78e29165", size = 373916 }, + { url = "https://files.pythonhosted.org/packages/32/08/2c7432ed26d194927ec07c1dfc08cdae5b6d302369df7fdda320d6393736/jiter-0.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a4d27e09825c1b3c7a667adb500ce8b840e8fc9f630da8454b44cdd4fb0081bb", size = 390942 }, + { url = "https://files.pythonhosted.org/packages/65/9b/70f3ecbd3f18ef19e50fbe5a51bdb1c520282720896c16ae1a68b90675b8/jiter-0.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ca7c287da9c1d56dda88da1d08855a787dbb09a7e2bd13c66a2e288700bd7c7", size = 327315 }, + { url = "https://files.pythonhosted.org/packages/2c/30/ba97e50e5fe1f58a1012257e0cfac0cc09e548b63f81982546c6dac8f1e7/jiter-0.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db19a6d160f093cbc8cd5ea2abad420b686f6c0e5fb4f7b41941ebc6a4f83cda", size = 367159 }, + { url = "https://files.pythonhosted.org/packages/a1/6d/73bb48ca87951c6c01b902258d0b792ed9404980bafceb1aa87ac43eb925/jiter-0.7.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6e46a63c7f877cf7441ffc821c28287cfb9f533ae6ed707bde15e7d4dfafa7ae", size = 514891 }, + { url = "https://files.pythonhosted.org/packages/6f/03/50c665a3d9067c5e384604310d67a184ae3176f27f677ca0c2670bb061ac/jiter-0.7.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7ba426fa7ff21cb119fa544b75dd3fbee6a70e55a5829709c0338d07ccd30e6d", size = 498039 }, + { url = "https://files.pythonhosted.org/packages/85/35/9fb7c7fea9b9c159d2089ea9b5ff4e3e56e2d42069456e3568dadf904e99/jiter-0.7.0-cp311-none-win32.whl", hash = "sha256:c07f55a64912b0c7982377831210836d2ea92b7bd343fca67a32212dd72e38e0", size = 198533 }, + { url = "https://files.pythonhosted.org/packages/96/19/e9b32c69c6dea404d983847e92cf86c3287b0f2f3e7621180a544c0ff153/jiter-0.7.0-cp311-none-win_amd64.whl", hash = "sha256:ed27b2c43e1b5f6c7fedc5c11d4d8bfa627de42d1143d87e39e2e83ddefd861a", size = 205728 }, + { url = "https://files.pythonhosted.org/packages/d9/7b/ed881a65e8f0989913408643b68a3a0913365c5c3884e85bae01a9679dd5/jiter-0.7.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ac7930bcaaeb1e229e35c91c04ed2e9f39025b86ee9fc3141706bbf6fff4aeeb", size = 292762 }, + { url = "https://files.pythonhosted.org/packages/d8/44/d0409912bc28508abffd99b9d55baba869592c1d27f9ee1cc035ef62371e/jiter-0.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:571feae3e7c901a8eedde9fd2865b0dfc1432fb15cab8c675a8444f7d11b7c5d", size = 302790 }, + { url = "https://files.pythonhosted.org/packages/8d/4f/38d0e87c8863c1b1f2dbac48acca8da85f6931a7b735e7163781843170a5/jiter-0.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8af4df8a262fa2778b68c2a03b6e9d1cb4d43d02bea6976d46be77a3a331af1", size = 329246 }, + { url = "https://files.pythonhosted.org/packages/88/3c/1af75094cbeba25df672b3f772dc717203be843e08248a0e03ef0ca382bc/jiter-0.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd028d4165097a611eb0c7494d8c1f2aebd46f73ca3200f02a175a9c9a6f22f5", size = 347808 }, + { url = "https://files.pythonhosted.org/packages/0b/74/55f00ca01223665e1418bec76cdeebb17a5f9ffae94e886da5c9bef5abd2/jiter-0.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6b487247c7836810091e9455efe56a52ec51bfa3a222237e1587d04d3e04527", size = 374011 }, + { url = "https://files.pythonhosted.org/packages/f7/ae/c1c892861796aa0adb720da75c59de5dbcf74ad51243c2aeea46681dcb16/jiter-0.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6d28a92f28814e1a9f2824dc11f4e17e1df1f44dc4fdeb94c5450d34bcb2602", size = 388863 }, + { url = "https://files.pythonhosted.org/packages/9d/a2/914587a68cba16920b1f979267a4e5c19f6977cac8fb8a6fbbd00035d0ed/jiter-0.7.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90443994bbafe134f0b34201dad3ebe1c769f0599004084e046fb249ad912425", size = 326765 }, + { url = "https://files.pythonhosted.org/packages/c8/ea/79abc48a6c9ba9ee3ccb0c194ec4cc1dd62e523c7c7003189380d00e5f16/jiter-0.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f9abf464f9faac652542ce8360cea8e68fba2b78350e8a170248f9bcc228702a", size = 367756 }, + { url = "https://files.pythonhosted.org/packages/4b/eb/ddc874819382081f9ad71cf681ee76450b17ac981f78a8db6408e7e28f34/jiter-0.7.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db7a8d99fc5f842f7d2852f06ccaed066532292c41723e5dff670c339b649f88", size = 515349 }, + { url = "https://files.pythonhosted.org/packages/af/9d/816d2d7f19070b72cf0133437cbacf99a9202f6fbbc2cfa2111fb686b0e0/jiter-0.7.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:15cf691ebd8693b70c94627d6b748f01e6d697d9a6e9f2bc310934fcfb7cf25e", size = 498050 }, + { url = "https://files.pythonhosted.org/packages/3e/a5/d0afb758c02d2d3c8ac3214a5be26579594d790944eaee7a47af06915e0e/jiter-0.7.0-cp312-none-win32.whl", hash = "sha256:9dcd54fa422fb66ca398bec296fed5f58e756aa0589496011cfea2abb5be38a5", size = 198912 }, + { url = "https://files.pythonhosted.org/packages/d0/8e/80b2afd0391a3530966d8fc2f9c104955ba41093b3c319ae40b25e68e323/jiter-0.7.0-cp312-none-win_amd64.whl", hash = "sha256:cc989951f73f9375b8eacd571baaa057f3d7d11b7ce6f67b9d54642e7475bfad", size = 199942 }, + { url = "https://files.pythonhosted.org/packages/50/bb/82c7180dc126687ddcc25386727b3a1688ab8eff496afe7838b69886fcc7/jiter-0.7.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:24cecd18df540963cd27c08ca5ce1d0179f229ff78066d9eecbe5add29361340", size = 292624 }, + { url = "https://files.pythonhosted.org/packages/11/c2/3b6d4596eab2ff81ebfe5bab779f457433cc2ffb8a2d1d6ab5ac187f26f6/jiter-0.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d41b46236b90b043cca73785674c23d2a67d16f226394079d0953f94e765ed76", size = 304723 }, + { url = "https://files.pythonhosted.org/packages/49/65/56f78dfccfb22e43815cad4a468b4360f8cfebecc024edb5e2a625b83a04/jiter-0.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b160db0987171365c153e406a45dcab0ee613ae3508a77bfff42515cb4ce4d6e", size = 328319 }, + { url = "https://files.pythonhosted.org/packages/fd/f2/9e3ed9ac0b122dd65250fc83cd0f0979da82f055ef6041411191f6301284/jiter-0.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1c8d91e0f0bd78602eaa081332e8ee4f512c000716f5bc54e9a037306d693a7", size = 347323 }, + { url = "https://files.pythonhosted.org/packages/42/18/24517f9f8575daf36fdac9dd53fcecde3d4c5bdd9f7b97a55e26ed2555b5/jiter-0.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997706c683195eeff192d2e5285ce64d2a610414f37da3a3f2625dcf8517cf90", size = 374073 }, + { url = "https://files.pythonhosted.org/packages/a1/b1/b368ccdeff3eabb4b293a21a94317a6f717ecc5bfbfca4eecd12ff39da3f/jiter-0.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ea52a8a0ff0229ab2920284079becd2bae0688d432fca94857ece83bb49c541", size = 388224 }, + { url = "https://files.pythonhosted.org/packages/92/1e/cc3d0655bcbc026e4b7746cb1ccab10d6eb2c29ffa64e574072db4d55f73/jiter-0.7.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d77449d2738cf74752bb35d75ee431af457e741124d1db5e112890023572c7c", size = 326145 }, + { url = "https://files.pythonhosted.org/packages/bb/24/d410c732326738d4f392689621ff14e10d3717efe7de9ecb97c44d8765a3/jiter-0.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8203519907a1d81d6cb00902c98e27c2d0bf25ce0323c50ca594d30f5f1fbcf", size = 366857 }, + { url = "https://files.pythonhosted.org/packages/14/a1/53df95b8248968936e7ba9eb5839918e3cfd183e56356d2961b9b29a49fc/jiter-0.7.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41d15ccc53931c822dd7f1aebf09faa3cda2d7b48a76ef304c7dbc19d1302e51", size = 514972 }, + { url = "https://files.pythonhosted.org/packages/97/c8/1876add533606ff1204450dd2564638cac7f164ff90844cb921cdf25cf68/jiter-0.7.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:febf3179b2fabf71fbd2fd52acb8594163bb173348b388649567a548f356dbf6", size = 497728 }, + { url = "https://files.pythonhosted.org/packages/94/31/1e59f246e264414b004864b63783e54aa3397be88f53dda3b01db3ae4251/jiter-0.7.0-cp313-none-win32.whl", hash = "sha256:4a8e2d866e7eda19f012444e01b55079d8e1c4c30346aaac4b97e80c54e2d6d3", size = 198660 }, + { url = "https://files.pythonhosted.org/packages/ca/96/58b3d260e212add0087563672931b1176e70bef1225839a4470ec66157a5/jiter-0.7.0-cp313-none-win_amd64.whl", hash = "sha256:7417c2b928062c496f381fb0cb50412eee5ad1d8b53dbc0e011ce45bb2de522c", size = 199305 }, ] [[package]] @@ -764,30 +836,50 @@ wheels = [ [[package]] name = "markupsafe" -version = "2.1.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/87/5b/aae44c6655f3801e81aa3eef09dbbf012431987ba564d7231722f68df02d/MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b", size = 19384 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/11/e7/291e55127bb2ae67c64d66cef01432b5933859dfb7d6949daa721b89d0b3/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f", size = 18219 }, - { url = "https://files.pythonhosted.org/packages/6b/cb/aed7a284c00dfa7c0682d14df85ad4955a350a21d2e3b06d8240497359bf/MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2", size = 14098 }, - { url = "https://files.pythonhosted.org/packages/1c/cf/35fe557e53709e93feb65575c93927942087e9b97213eabc3fe9d5b25a55/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced", size = 29014 }, - { url = "https://files.pythonhosted.org/packages/97/18/c30da5e7a0e7f4603abfc6780574131221d9148f323752c2755d48abad30/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5", size = 28220 }, - { url = "https://files.pythonhosted.org/packages/0c/40/2e73e7d532d030b1e41180807a80d564eda53babaf04d65e15c1cf897e40/MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c", size = 27756 }, - { url = "https://files.pythonhosted.org/packages/18/46/5dca760547e8c59c5311b332f70605d24c99d1303dd9a6e1fc3ed0d73561/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f", size = 33988 }, - { url = "https://files.pythonhosted.org/packages/6d/c5/27febe918ac36397919cd4a67d5579cbbfa8da027fa1238af6285bb368ea/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a", size = 32718 }, - { url = "https://files.pythonhosted.org/packages/f8/81/56e567126a2c2bc2684d6391332e357589a96a76cb9f8e5052d85cb0ead8/MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f", size = 33317 }, - { url = "https://files.pythonhosted.org/packages/00/0b/23f4b2470accb53285c613a3ab9ec19dc944eaf53592cb6d9e2af8aa24cc/MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906", size = 16670 }, - { url = "https://files.pythonhosted.org/packages/b7/a2/c78a06a9ec6d04b3445a949615c4c7ed86a0b2eb68e44e7541b9d57067cc/MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617", size = 17224 }, - { url = "https://files.pythonhosted.org/packages/53/bd/583bf3e4c8d6a321938c13f49d44024dbe5ed63e0a7ba127e454a66da974/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1", size = 18215 }, - { url = "https://files.pythonhosted.org/packages/48/d6/e7cd795fc710292c3af3a06d80868ce4b02bfbbf370b7cee11d282815a2a/MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4", size = 14069 }, - { url = "https://files.pythonhosted.org/packages/51/b5/5d8ec796e2a08fc814a2c7d2584b55f889a55cf17dd1a90f2beb70744e5c/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee", size = 29452 }, - { url = "https://files.pythonhosted.org/packages/0a/0d/2454f072fae3b5a137c119abf15465d1771319dfe9e4acbb31722a0fff91/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5", size = 28462 }, - { url = "https://files.pythonhosted.org/packages/2d/75/fd6cb2e68780f72d47e6671840ca517bda5ef663d30ada7616b0462ad1e3/MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b", size = 27869 }, - { url = "https://files.pythonhosted.org/packages/b0/81/147c477391c2750e8fc7705829f7351cf1cd3be64406edcf900dc633feb2/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a", size = 33906 }, - { url = "https://files.pythonhosted.org/packages/8b/ff/9a52b71839d7a256b563e85d11050e307121000dcebc97df120176b3ad93/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f", size = 32296 }, - { url = "https://files.pythonhosted.org/packages/88/07/2dc76aa51b481eb96a4c3198894f38b480490e834479611a4053fbf08623/MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169", size = 33038 }, - { url = "https://files.pythonhosted.org/packages/96/0c/620c1fb3661858c0e37eb3cbffd8c6f732a67cd97296f725789679801b31/MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad", size = 16572 }, - { url = "https://files.pythonhosted.org/packages/3f/14/c3554d512d5f9100a95e737502f4a2323a1959f6d0d01e0d0997b35f7b10/MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb", size = 17127 }, +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353 }, + { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392 }, + { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984 }, + { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120 }, + { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032 }, + { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057 }, + { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359 }, + { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306 }, + { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094 }, + { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521 }, + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, ] [[package]] @@ -882,7 +974,7 @@ wheels = [ [[package]] name = "openai" -version = "1.51.0" +version = "1.54.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -894,9 +986,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/28/af/cc59b1447f5a02bb1f25b9b0cd94b607aa2c969a81d9a244d4067f91f6fe/openai-1.51.0.tar.gz", hash = "sha256:8dc4f9d75ccdd5466fc8c99a952186eddceb9fd6ba694044773f3736a847149d", size = 306880 } +sdist = { url = "https://files.pythonhosted.org/packages/da/26/f1a79d8332ac5ed38fdc347701aa4a7ad8f8f66ec3f9880122c455d7ffb1/openai-1.54.2.tar.gz", hash = "sha256:0dbb8f2bb36f7ff1d200d103b9f95c35773ed3248e3a697b02f5a39015627e5e", size = 312551 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/08/9f22356d4fbd273f734db1e6663b7ca6987943080567f5580471022e57ca/openai-1.51.0-py3-none-any.whl", hash = "sha256:d9affafb7e51e5a27dce78589d4964ce4d6f6d560307265933a94b2e3f3c5d2c", size = 383533 }, + { url = "https://files.pythonhosted.org/packages/f6/0f/ea8717dedbef16fa61a0bdeb0b7ae96ff574933ed5932102d3f5a4ce01a1/openai-1.54.2-py3-none-any.whl", hash = "sha256:77010b439e69d37f67cc2f44eaa62b2b6d5a60add2d8636e4603c0e762982708", size = 389315 }, ] [[package]] @@ -931,6 +1023,15 @@ requires-dist = [ [package.metadata.requires-dev] dev = [{ name = "pytest", specifier = ">=8.3.3" }] +[[package]] +name = "packaging" +version = "24.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/51/65/50db4dda066951078f0a96cf12f4b9ada6e4b811516bf0262c0f4f7064d4/packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", size = 148788 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124", size = 53985 }, +] + [[package]] name = "pillow" version = "11.0.0" @@ -1011,6 +1112,63 @@ requires-dist = [ { name = "skill-library", editable = "../../libraries/python/skills/skill-library" }, ] +[[package]] +name = "propcache" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/4d/5e5a60b78dbc1d464f8a7bbaeb30957257afdc8512cbb9dfd5659304f5cd/propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70", size = 40951 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/1c/71eec730e12aec6511e702ad0cd73c2872eccb7cad39de8ba3ba9de693ef/propcache-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354", size = 80811 }, + { url = "https://files.pythonhosted.org/packages/89/c3/7e94009f9a4934c48a371632197406a8860b9f08e3f7f7d922ab69e57a41/propcache-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de", size = 46365 }, + { url = "https://files.pythonhosted.org/packages/c0/1d/c700d16d1d6903aeab28372fe9999762f074b80b96a0ccc953175b858743/propcache-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87", size = 45602 }, + { url = "https://files.pythonhosted.org/packages/2e/5e/4a3e96380805bf742712e39a4534689f4cddf5fa2d3a93f22e9fd8001b23/propcache-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016", size = 236161 }, + { url = "https://files.pythonhosted.org/packages/a5/85/90132481183d1436dff6e29f4fa81b891afb6cb89a7306f32ac500a25932/propcache-0.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb", size = 244938 }, + { url = "https://files.pythonhosted.org/packages/4a/89/c893533cb45c79c970834274e2d0f6d64383ec740be631b6a0a1d2b4ddc0/propcache-0.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2", size = 243576 }, + { url = "https://files.pythonhosted.org/packages/8c/56/98c2054c8526331a05f205bf45cbb2cda4e58e56df70e76d6a509e5d6ec6/propcache-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4", size = 236011 }, + { url = "https://files.pythonhosted.org/packages/2d/0c/8b8b9f8a6e1abd869c0fa79b907228e7abb966919047d294ef5df0d136cf/propcache-0.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504", size = 224834 }, + { url = "https://files.pythonhosted.org/packages/18/bb/397d05a7298b7711b90e13108db697732325cafdcd8484c894885c1bf109/propcache-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178", size = 224946 }, + { url = "https://files.pythonhosted.org/packages/25/19/4fc08dac19297ac58135c03770b42377be211622fd0147f015f78d47cd31/propcache-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d", size = 217280 }, + { url = "https://files.pythonhosted.org/packages/7e/76/c79276a43df2096ce2aba07ce47576832b1174c0c480fe6b04bd70120e59/propcache-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2", size = 220088 }, + { url = "https://files.pythonhosted.org/packages/c3/9a/8a8cf428a91b1336b883f09c8b884e1734c87f724d74b917129a24fe2093/propcache-0.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db", size = 233008 }, + { url = "https://files.pythonhosted.org/packages/25/7b/768a8969abd447d5f0f3333df85c6a5d94982a1bc9a89c53c154bf7a8b11/propcache-0.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b", size = 237719 }, + { url = "https://files.pythonhosted.org/packages/ed/0d/e5d68ccc7976ef8b57d80613ac07bbaf0614d43f4750cf953f0168ef114f/propcache-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b", size = 227729 }, + { url = "https://files.pythonhosted.org/packages/05/64/17eb2796e2d1c3d0c431dc5f40078d7282f4645af0bb4da9097fbb628c6c/propcache-0.2.0-cp311-cp311-win32.whl", hash = "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1", size = 40473 }, + { url = "https://files.pythonhosted.org/packages/83/c5/e89fc428ccdc897ade08cd7605f174c69390147526627a7650fb883e0cd0/propcache-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71", size = 44921 }, + { url = "https://files.pythonhosted.org/packages/7c/46/a41ca1097769fc548fc9216ec4c1471b772cc39720eb47ed7e38ef0006a9/propcache-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2", size = 80800 }, + { url = "https://files.pythonhosted.org/packages/75/4f/93df46aab9cc473498ff56be39b5f6ee1e33529223d7a4d8c0a6101a9ba2/propcache-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7", size = 46443 }, + { url = "https://files.pythonhosted.org/packages/0b/17/308acc6aee65d0f9a8375e36c4807ac6605d1f38074b1581bd4042b9fb37/propcache-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8", size = 45676 }, + { url = "https://files.pythonhosted.org/packages/65/44/626599d2854d6c1d4530b9a05e7ff2ee22b790358334b475ed7c89f7d625/propcache-0.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793", size = 246191 }, + { url = "https://files.pythonhosted.org/packages/f2/df/5d996d7cb18df076debae7d76ac3da085c0575a9f2be6b1f707fe227b54c/propcache-0.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09", size = 251791 }, + { url = "https://files.pythonhosted.org/packages/2e/6d/9f91e5dde8b1f662f6dd4dff36098ed22a1ef4e08e1316f05f4758f1576c/propcache-0.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89", size = 253434 }, + { url = "https://files.pythonhosted.org/packages/3c/e9/1b54b7e26f50b3e0497cd13d3483d781d284452c2c50dd2a615a92a087a3/propcache-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e", size = 248150 }, + { url = "https://files.pythonhosted.org/packages/a7/ef/a35bf191c8038fe3ce9a414b907371c81d102384eda5dbafe6f4dce0cf9b/propcache-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9", size = 233568 }, + { url = "https://files.pythonhosted.org/packages/97/d9/d00bb9277a9165a5e6d60f2142cd1a38a750045c9c12e47ae087f686d781/propcache-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4", size = 229874 }, + { url = "https://files.pythonhosted.org/packages/8e/78/c123cf22469bdc4b18efb78893e69c70a8b16de88e6160b69ca6bdd88b5d/propcache-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c", size = 225857 }, + { url = "https://files.pythonhosted.org/packages/31/1b/fd6b2f1f36d028820d35475be78859d8c89c8f091ad30e377ac49fd66359/propcache-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887", size = 227604 }, + { url = "https://files.pythonhosted.org/packages/99/36/b07be976edf77a07233ba712e53262937625af02154353171716894a86a6/propcache-0.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57", size = 238430 }, + { url = "https://files.pythonhosted.org/packages/0d/64/5822f496c9010e3966e934a011ac08cac8734561842bc7c1f65586e0683c/propcache-0.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23", size = 244814 }, + { url = "https://files.pythonhosted.org/packages/fd/bd/8657918a35d50b18a9e4d78a5df7b6c82a637a311ab20851eef4326305c1/propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348", size = 235922 }, + { url = "https://files.pythonhosted.org/packages/a8/6f/ec0095e1647b4727db945213a9f395b1103c442ef65e54c62e92a72a3f75/propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5", size = 40177 }, + { url = "https://files.pythonhosted.org/packages/20/a2/bd0896fdc4f4c1db46d9bc361c8c79a9bf08ccc08ba054a98e38e7ba1557/propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3", size = 44446 }, + { url = "https://files.pythonhosted.org/packages/a8/a7/5f37b69197d4f558bfef5b4bceaff7c43cc9b51adf5bd75e9081d7ea80e4/propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7", size = 78120 }, + { url = "https://files.pythonhosted.org/packages/c8/cd/48ab2b30a6b353ecb95a244915f85756d74f815862eb2ecc7a518d565b48/propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763", size = 45127 }, + { url = "https://files.pythonhosted.org/packages/a5/ba/0a1ef94a3412aab057bd996ed5f0ac7458be5bf469e85c70fa9ceb43290b/propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d", size = 44419 }, + { url = "https://files.pythonhosted.org/packages/b4/6c/ca70bee4f22fa99eacd04f4d2f1699be9d13538ccf22b3169a61c60a27fa/propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a", size = 229611 }, + { url = "https://files.pythonhosted.org/packages/19/70/47b872a263e8511ca33718d96a10c17d3c853aefadeb86dc26e8421184b9/propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b", size = 234005 }, + { url = "https://files.pythonhosted.org/packages/4f/be/3b0ab8c84a22e4a3224719099c1229ddfdd8a6a1558cf75cb55ee1e35c25/propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb", size = 237270 }, + { url = "https://files.pythonhosted.org/packages/04/d8/f071bb000d4b8f851d312c3c75701e586b3f643fe14a2e3409b1b9ab3936/propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf", size = 231877 }, + { url = "https://files.pythonhosted.org/packages/93/e7/57a035a1359e542bbb0a7df95aad6b9871ebee6dce2840cb157a415bd1f3/propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2", size = 217848 }, + { url = "https://files.pythonhosted.org/packages/f0/93/d1dea40f112ec183398fb6c42fde340edd7bab202411c4aa1a8289f461b6/propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f", size = 216987 }, + { url = "https://files.pythonhosted.org/packages/62/4c/877340871251145d3522c2b5d25c16a1690ad655fbab7bb9ece6b117e39f/propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136", size = 212451 }, + { url = "https://files.pythonhosted.org/packages/7c/bb/a91b72efeeb42906ef58ccf0cdb87947b54d7475fee3c93425d732f16a61/propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325", size = 212879 }, + { url = "https://files.pythonhosted.org/packages/9b/7f/ee7fea8faac57b3ec5d91ff47470c6c5d40d7f15d0b1fccac806348fa59e/propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44", size = 222288 }, + { url = "https://files.pythonhosted.org/packages/ff/d7/acd67901c43d2e6b20a7a973d9d5fd543c6e277af29b1eb0e1f7bd7ca7d2/propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83", size = 228257 }, + { url = "https://files.pythonhosted.org/packages/8d/6f/6272ecc7a8daad1d0754cfc6c8846076a8cb13f810005c79b15ce0ef0cf2/propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544", size = 221075 }, + { url = "https://files.pythonhosted.org/packages/7c/bd/c7a6a719a6b3dd8b3aeadb3675b5783983529e4a3185946aa444d3e078f6/propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032", size = 39654 }, + { url = "https://files.pythonhosted.org/packages/88/e7/0eef39eff84fa3e001b44de0bd41c7c0e3432e7648ffd3d64955910f002d/propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e", size = 43705 }, + { url = "https://files.pythonhosted.org/packages/3d/b6/e6d98278f2d49b22b4d033c9f792eda783b9ab2094b041f013fc69bcde87/propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036", size = 11603 }, +] + [[package]] name = "pycparser" version = "2.22" @@ -1083,15 +1241,15 @@ wheels = [ [[package]] name = "pydantic-settings" -version = "2.5.2" +version = "2.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/68/27/0bed9dd26b93328b60a1402febc780e7be72b42847fa8b5c94b7d0aeb6d1/pydantic_settings-2.5.2.tar.gz", hash = "sha256:f90b139682bee4d2065273d5185d71d37ea46cfe57e1b5ae184fc6a0b2484ca0", size = 70938 } +sdist = { url = "https://files.pythonhosted.org/packages/b5/d4/9dfbe238f45ad8b168f5c96ee49a3df0598ce18a0795a983b419949ce65b/pydantic_settings-2.6.1.tar.gz", hash = "sha256:e0f92546d8a9923cb8941689abf85d6601a8c19a23e97a34b2964a2e3f813ca0", size = 75646 } wheels = [ - { url = "https://files.pythonhosted.org/packages/29/8d/29e82e333f32d9e2051c10764b906c2a6cd140992910b5f49762790911ba/pydantic_settings-2.5.2-py3-none-any.whl", hash = "sha256:2c912e55fd5794a59bf8c832b9de832dcfdf4778d79ff79b708744eed499a907", size = 26864 }, + { url = "https://files.pythonhosted.org/packages/5e/f9/ff95fd7d760af42f647ea87f9b8a383d891cdb5e5dbd4613edaeb094252a/pydantic_settings-2.6.1-py3-none-any.whl", hash = "sha256:7fb0637c786a558d3103436278a7c4f1cfd29ba8973238a50c5bb9a55387da87", size = 28595 }, ] [[package]] @@ -1163,24 +1321,27 @@ wheels = [ [[package]] name = "python-multipart" -version = "0.0.12" +version = "0.0.17" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/16/6e/7ecfe1366b9270f7f475c76fcfa28812493a6a1abd489b2433851a444f4f/python_multipart-0.0.12.tar.gz", hash = "sha256:045e1f98d719c1ce085ed7f7e1ef9d8ccc8c02ba02b5566d5f7521410ced58cb", size = 35713 } +sdist = { url = "https://files.pythonhosted.org/packages/40/22/edea41c2d4a22e666c0c7db7acdcbf7bc8c1c1f7d3b3ca246ec982fec612/python_multipart-0.0.17.tar.gz", hash = "sha256:41330d831cae6e2f22902704ead2826ea038d0419530eadff3ea80175aec5538", size = 36452 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f5/0b/c316262244abea7481f95f1e91d7575f3dfcf6455d56d1ffe9839c582eb1/python_multipart-0.0.12-py3-none-any.whl", hash = "sha256:43dcf96cf65888a9cd3423544dd0d75ac10f7aa0c3c28a175bbcd00c9ce1aebf", size = 23246 }, + { url = "https://files.pythonhosted.org/packages/b4/fb/275137a799169392f1fa88fff2be92f16eee38e982720a8aaadefc4a36b2/python_multipart-0.0.17-py3-none-any.whl", hash = "sha256:15dc4f487e0a9476cc1201261188ee0940165cffc94429b6fc565c4d3045cb5d", size = 24453 }, ] [[package]] name = "pywin32" -version = "306" +version = "308" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/1e/fc18ad83ca553e01b97aa8393ff10e33c1fb57801db05488b83282ee9913/pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407", size = 8507689 }, - { url = "https://files.pythonhosted.org/packages/7e/9e/ad6b1ae2a5ad1066dc509350e0fbf74d8d50251a51e420a2a8feaa0cecbd/pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e", size = 9227547 }, - { url = "https://files.pythonhosted.org/packages/91/20/f744bff1da8f43388498503634378dbbefbe493e65675f2cc52f7185c2c2/pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a", size = 10388324 }, - { url = "https://files.pythonhosted.org/packages/14/91/17e016d5923e178346aabda3dfec6629d1a26efe587d19667542105cf0a6/pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b", size = 8507705 }, - { url = "https://files.pythonhosted.org/packages/83/1c/25b79fc3ec99b19b0a0730cc47356f7e2959863bf9f3cd314332bddb4f68/pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e", size = 9227429 }, - { url = "https://files.pythonhosted.org/packages/1c/43/e3444dc9a12f8365d9603c2145d16bf0a2f8180f343cf87be47f5579e547/pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040", size = 10388145 }, + { url = "https://files.pythonhosted.org/packages/eb/e2/02652007469263fe1466e98439831d65d4ca80ea1a2df29abecedf7e47b7/pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a", size = 5928156 }, + { url = "https://files.pythonhosted.org/packages/48/ef/f4fb45e2196bc7ffe09cad0542d9aff66b0e33f6c0954b43e49c33cad7bd/pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b", size = 6559559 }, + { url = "https://files.pythonhosted.org/packages/79/ef/68bb6aa865c5c9b11a35771329e95917b5559845bd75b65549407f9fc6b4/pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6", size = 7972495 }, + { url = "https://files.pythonhosted.org/packages/00/7c/d00d6bdd96de4344e06c4afbf218bc86b54436a94c01c71a8701f613aa56/pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897", size = 5939729 }, + { url = "https://files.pythonhosted.org/packages/21/27/0c8811fbc3ca188f93b5354e7c286eb91f80a53afa4e11007ef661afa746/pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47", size = 6543015 }, + { url = "https://files.pythonhosted.org/packages/9d/0f/d40f8373608caed2255781a3ad9a51d03a594a1248cd632d6a298daca693/pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091", size = 7976033 }, + { url = "https://files.pythonhosted.org/packages/a9/a4/aa562d8935e3df5e49c161b427a3a2efad2ed4e9cf81c3de636f1fdddfd0/pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed", size = 5938579 }, + { url = "https://files.pythonhosted.org/packages/c7/50/b0efb8bb66210da67a53ab95fd7a98826a97ee21f1d22949863e6d588b22/pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4", size = 6542056 }, + { url = "https://files.pythonhosted.org/packages/26/df/2b63e3e4f2df0224f8aaf6d131f54fe4e8c96400eb9df563e2aae2e1a1f9/pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd", size = 7974986 }, ] [[package]] @@ -1288,15 +1449,15 @@ wheels = [ [[package]] name = "rich" -version = "13.9.1" +version = "13.9.4" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b3/78/87d00a1df7c457ad9aa0139f01b8a11c67209f27f927c503b0109bf2ed6c/rich-13.9.1.tar.gz", hash = "sha256:097cffdf85db1babe30cc7deba5ab3a29e1b9885047dab24c57e9a7f8a9c1466", size = 222907 } +sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/71/cd9549551f1aa11cf7e5f92bae5817979e8b3a19e31e8810c15f3f45c311/rich-13.9.1-py3-none-any.whl", hash = "sha256:b340e739f30aa58921dc477b8adaa9ecdb7cecc217be01d93730ee1bc8aa83be", size = 242147 }, + { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, ] [[package]] @@ -1372,6 +1533,7 @@ name = "skill-library" version = "0.1.0" source = { editable = "../../libraries/python/skills/skill-library" } dependencies = [ + { name = "assistant-drive" }, { name = "chat-driver" }, { name = "context" }, { name = "events" }, @@ -1386,6 +1548,7 @@ dependencies = [ [package.metadata] requires-dist = [ + { name = "assistant-drive", editable = "../../libraries/python/assistant-drive" }, { name = "chat-driver", editable = "../../libraries/python/chat-driver" }, { name = "context", editable = "../../libraries/python/context" }, { name = "events", editable = "../../libraries/python/events" }, @@ -1398,6 +1561,13 @@ requires-dist = [ { name = "tiktoken", specifier = ">=0.7.0" }, ] +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.1" }, + { name = "pytest-asyncio", specifier = ">=0.23.8" }, + { name = "pytest-repeat", specifier = ">=0.9.3" }, +] + [[package]] name = "sniffio" version = "1.3.1" @@ -1409,52 +1579,56 @@ wheels = [ [[package]] name = "starlette" -version = "0.38.6" +version = "0.41.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/42/b4/e25c3b688ef703d85e55017c6edd0cbf38e5770ab748234363d54ff0251a/starlette-0.38.6.tar.gz", hash = "sha256:863a1588f5574e70a821dadefb41e4881ea451a47a3cd1b4df359d4ffefe5ead", size = 2569491 } +sdist = { url = "https://files.pythonhosted.org/packages/3e/da/1fb4bdb72ae12b834becd7e1e7e47001d32f91ec0ce8d7bc1b618d9f0bd9/starlette-0.41.2.tar.gz", hash = "sha256:9834fd799d1a87fd346deb76158668cfa0b0d56f85caefe8268e2d97c3468b62", size = 2573867 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/9c/93f7bc03ff03199074e81974cc148908ead60dcf189f68ba1761a0ee35cf/starlette-0.38.6-py3-none-any.whl", hash = "sha256:4517a1409e2e73ee4951214ba012052b9e16f60e90d73cfb06192c19203bbb05", size = 71451 }, + { url = "https://files.pythonhosted.org/packages/54/43/f185bfd0ca1d213beb4293bed51d92254df23d8ceaf6c0e17146d508a776/starlette-0.41.2-py3-none-any.whl", hash = "sha256:fbc189474b4731cf30fcef52f18a8d070e3f3b46c6a04c97579e85e6ffca942d", size = 73259 }, ] [[package]] name = "tiktoken" -version = "0.7.0" +version = "0.8.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "regex" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c4/4a/abaec53e93e3ef37224a4dd9e2fc6bb871e7a538c2b6b9d2a6397271daf4/tiktoken-0.7.0.tar.gz", hash = "sha256:1077266e949c24e0291f6c350433c6f0971365ece2b173a23bc3b9f9defef6b6", size = 33437 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/eb/57492b2568eea1d546da5cc1ae7559d924275280db80ba07e6f9b89a914b/tiktoken-0.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:10c7674f81e6e350fcbed7c09a65bca9356eaab27fb2dac65a1e440f2bcfe30f", size = 961468 }, - { url = "https://files.pythonhosted.org/packages/30/ef/e07dbfcb2f85c84abaa1b035a9279575a8da0236305491dc22ae099327f7/tiktoken-0.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:084cec29713bc9d4189a937f8a35dbdfa785bd1235a34c1124fe2323821ee93f", size = 907005 }, - { url = "https://files.pythonhosted.org/packages/ea/9b/f36db825b1e9904c3a2646439cb9923fc1e09208e2e071c6d9dd64ead131/tiktoken-0.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:811229fde1652fedcca7c6dfe76724d0908775b353556d8a71ed74d866f73f7b", size = 1049183 }, - { url = "https://files.pythonhosted.org/packages/61/b4/b80d1fe33015e782074e96bbbf4108ccd283b8deea86fb43c15d18b7c351/tiktoken-0.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86b6e7dc2e7ad1b3757e8a24597415bafcfb454cebf9a33a01f2e6ba2e663992", size = 1080830 }, - { url = "https://files.pythonhosted.org/packages/2a/40/c66ff3a21af6d62a7e0ff428d12002c4e0389f776d3ff96dcaa0bb354eee/tiktoken-0.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1063c5748be36344c7e18c7913c53e2cca116764c2080177e57d62c7ad4576d1", size = 1092967 }, - { url = "https://files.pythonhosted.org/packages/2e/80/f4c9e255ff236e6a69ce44b927629cefc1b63d3a00e2d1c9ed540c9492d2/tiktoken-0.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:20295d21419bfcca092644f7e2f2138ff947a6eb8cfc732c09cc7d76988d4a89", size = 1142682 }, - { url = "https://files.pythonhosted.org/packages/b1/10/c04b4ff592a5f46b28ebf4c2353f735c02ae7f0ce1b165d00748ced6467e/tiktoken-0.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:959d993749b083acc57a317cbc643fb85c014d055b2119b739487288f4e5d1cb", size = 799009 }, - { url = "https://files.pythonhosted.org/packages/1d/46/4cdda4186ce900608f522da34acf442363346688c71b938a90a52d7b84cc/tiktoken-0.7.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:71c55d066388c55a9c00f61d2c456a6086673ab7dec22dd739c23f77195b1908", size = 960446 }, - { url = "https://files.pythonhosted.org/packages/b6/30/09ced367d280072d7a3e21f34263dfbbf6378661e7a0f6414e7c18971083/tiktoken-0.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:09ed925bccaa8043e34c519fbb2f99110bd07c6fd67714793c21ac298e449410", size = 906652 }, - { url = "https://files.pythonhosted.org/packages/e6/7b/c949e4954441a879a67626963dff69096e3c774758b9f2bb0853f7b4e1e7/tiktoken-0.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03c6c40ff1db0f48a7b4d2dafeae73a5607aacb472fa11f125e7baf9dce73704", size = 1047904 }, - { url = "https://files.pythonhosted.org/packages/50/81/1842a22f15586072280364c2ab1e40835adaf64e42fe80e52aff921ee021/tiktoken-0.7.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d20b5c6af30e621b4aca094ee61777a44118f52d886dbe4f02b70dfe05c15350", size = 1079836 }, - { url = "https://files.pythonhosted.org/packages/6d/87/51a133a3d5307cf7ae3754249b0faaa91d3414b85c3d36f80b54d6817aa6/tiktoken-0.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d427614c3e074004efa2f2411e16c826f9df427d3c70a54725cae860f09e4bf4", size = 1092472 }, - { url = "https://files.pythonhosted.org/packages/a5/1f/c93517dc6d3b2c9e988b8e24f87a8b2d4a4ab28920a3a3f3ea338397ae0c/tiktoken-0.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8c46d7af7b8c6987fac9b9f61041b452afe92eb087d29c9ce54951280f899a97", size = 1141881 }, - { url = "https://files.pythonhosted.org/packages/bf/4b/48ca098cb580c099b5058bf62c4cb5e90ca6130fa43ef4df27088536245b/tiktoken-0.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:0bc603c30b9e371e7c4c7935aba02af5994a909fc3c0fe66e7004070858d3f8f", size = 799281 }, +sdist = { url = "https://files.pythonhosted.org/packages/37/02/576ff3a6639e755c4f70997b2d315f56d6d71e0d046f4fb64cb81a3fb099/tiktoken-0.8.0.tar.gz", hash = "sha256:9ccbb2740f24542534369c5635cfd9b2b3c2490754a78ac8831d99f89f94eeb2", size = 35107 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/1e/ca48e7bfeeccaf76f3a501bd84db1fa28b3c22c9d1a1f41af9fb7579c5f6/tiktoken-0.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d622d8011e6d6f239297efa42a2657043aaed06c4f68833550cac9e9bc723ef1", size = 1039700 }, + { url = "https://files.pythonhosted.org/packages/8c/f8/f0101d98d661b34534769c3818f5af631e59c36ac6d07268fbfc89e539ce/tiktoken-0.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2efaf6199717b4485031b4d6edb94075e4d79177a172f38dd934d911b588d54a", size = 982413 }, + { url = "https://files.pythonhosted.org/packages/ac/3c/2b95391d9bd520a73830469f80a96e3790e6c0a5ac2444f80f20b4b31051/tiktoken-0.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5637e425ce1fc49cf716d88df3092048359a4b3bbb7da762840426e937ada06d", size = 1144242 }, + { url = "https://files.pythonhosted.org/packages/01/c4/c4a4360de845217b6aa9709c15773484b50479f36bb50419c443204e5de9/tiktoken-0.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fb0e352d1dbe15aba082883058b3cce9e48d33101bdaac1eccf66424feb5b47", size = 1176588 }, + { url = "https://files.pythonhosted.org/packages/f8/a3/ef984e976822cd6c2227c854f74d2e60cf4cd6fbfca46251199914746f78/tiktoken-0.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:56edfefe896c8f10aba372ab5706b9e3558e78db39dd497c940b47bf228bc419", size = 1237261 }, + { url = "https://files.pythonhosted.org/packages/1e/86/eea2309dc258fb86c7d9b10db536434fc16420feaa3b6113df18b23db7c2/tiktoken-0.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:326624128590def898775b722ccc327e90b073714227175ea8febbc920ac0a99", size = 884537 }, + { url = "https://files.pythonhosted.org/packages/c1/22/34b2e136a6f4af186b6640cbfd6f93400783c9ef6cd550d9eab80628d9de/tiktoken-0.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:881839cfeae051b3628d9823b2e56b5cc93a9e2efb435f4cf15f17dc45f21586", size = 1039357 }, + { url = "https://files.pythonhosted.org/packages/04/d2/c793cf49c20f5855fd6ce05d080c0537d7418f22c58e71f392d5e8c8dbf7/tiktoken-0.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fe9399bdc3f29d428f16a2f86c3c8ec20be3eac5f53693ce4980371c3245729b", size = 982616 }, + { url = "https://files.pythonhosted.org/packages/b3/a1/79846e5ef911cd5d75c844de3fa496a10c91b4b5f550aad695c5df153d72/tiktoken-0.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a58deb7075d5b69237a3ff4bb51a726670419db6ea62bdcd8bd80c78497d7ab", size = 1144011 }, + { url = "https://files.pythonhosted.org/packages/26/32/e0e3a859136e95c85a572e4806dc58bf1ddf651108ae8b97d5f3ebe1a244/tiktoken-0.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2908c0d043a7d03ebd80347266b0e58440bdef5564f84f4d29fb235b5df3b04", size = 1175432 }, + { url = "https://files.pythonhosted.org/packages/c7/89/926b66e9025b97e9fbabeaa59048a736fe3c3e4530a204109571104f921c/tiktoken-0.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:294440d21a2a51e12d4238e68a5972095534fe9878be57d905c476017bff99fc", size = 1236576 }, + { url = "https://files.pythonhosted.org/packages/45/e2/39d4aa02a52bba73b2cd21ba4533c84425ff8786cc63c511d68c8897376e/tiktoken-0.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:d8f3192733ac4d77977432947d563d7e1b310b96497acd3c196c9bddb36ed9db", size = 883824 }, + { url = "https://files.pythonhosted.org/packages/e3/38/802e79ba0ee5fcbf240cd624143f57744e5d411d2e9d9ad2db70d8395986/tiktoken-0.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:02be1666096aff7da6cbd7cdaa8e7917bfed3467cd64b38b1f112e96d3b06a24", size = 1039648 }, + { url = "https://files.pythonhosted.org/packages/b1/da/24cdbfc302c98663fbea66f5866f7fa1048405c7564ab88483aea97c3b1a/tiktoken-0.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94ff53c5c74b535b2cbf431d907fc13c678bbd009ee633a2aca269a04389f9a", size = 982763 }, + { url = "https://files.pythonhosted.org/packages/e4/f0/0ecf79a279dfa41fc97d00adccf976ecc2556d3c08ef3e25e45eb31f665b/tiktoken-0.8.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b231f5e8982c245ee3065cd84a4712d64692348bc609d84467c57b4b72dcbc5", size = 1144417 }, + { url = "https://files.pythonhosted.org/packages/ab/d3/155d2d4514f3471a25dc1d6d20549ef254e2aa9bb5b1060809b1d3b03d3a/tiktoken-0.8.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4177faa809bd55f699e88c96d9bb4635d22e3f59d635ba6fd9ffedf7150b9953", size = 1175108 }, + { url = "https://files.pythonhosted.org/packages/19/eb/5989e16821ee8300ef8ee13c16effc20dfc26c777d05fbb6825e3c037b81/tiktoken-0.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5376b6f8dc4753cd81ead935c5f518fa0fbe7e133d9e25f648d8c4dabdd4bad7", size = 1236520 }, + { url = "https://files.pythonhosted.org/packages/40/59/14b20465f1d1cb89cfbc96ec27e5617b2d41c79da12b5e04e96d689be2a7/tiktoken-0.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:18228d624807d66c87acd8f25fc135665617cab220671eb65b50f5d70fa51f69", size = 883849 }, ] [[package]] name = "tqdm" -version = "4.66.5" +version = "4.67.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "platform_system == 'Windows'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/83/6ba9844a41128c62e810fddddd72473201f3eacde02046066142a2d96cc5/tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad", size = 169504 } +sdist = { url = "https://files.pythonhosted.org/packages/e8/4f/0153c21dc5779a49a0598c445b1978126b1344bab9ee71e53e44877e14e0/tqdm-4.67.0.tar.gz", hash = "sha256:fe5a6f95e6fe0b9755e9469b77b9c3cf850048224ecaa8293d7d2d31f97d869a", size = 169739 } wheels = [ - { url = "https://files.pythonhosted.org/packages/48/5d/acf5905c36149bbaec41ccf7f2b68814647347b72075ac0b1fe3022fdc73/tqdm-4.66.5-py3-none-any.whl", hash = "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd", size = 78351 }, + { url = "https://files.pythonhosted.org/packages/2b/78/57043611a16c655c8350b4c01b8d6abfb38cc2acb475238b62c2146186d7/tqdm-4.67.0-py3-none-any.whl", hash = "sha256:0cd8af9d56911acab92182e88d763100d4788bdf421d251616040cc4d44863be", size = 78590 }, ] [[package]] @@ -1492,15 +1666,15 @@ wheels = [ [[package]] name = "uvicorn" -version = "0.31.0" +version = "0.32.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "h11" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0a/96/ee52d900f8e41cc35eaebfda76f3619c2e45b741f3ee957d6fe32be1b2aa/uvicorn-0.31.0.tar.gz", hash = "sha256:13bc21373d103859f68fe739608e2eb054a816dea79189bc3ca08ea89a275906", size = 77140 } +sdist = { url = "https://files.pythonhosted.org/packages/e0/fc/1d785078eefd6945f3e5bab5c076e4230698046231eb0f3747bc5c8fa992/uvicorn-0.32.0.tar.gz", hash = "sha256:f78b36b143c16f54ccdb8190d0a26b5f1901fe5a3c777e1ab29f26391af8551e", size = 77564 } wheels = [ - { url = "https://files.pythonhosted.org/packages/05/12/206aca5442524d16be7702d08b453d7c274c86fd759266b1f709d4ef43ba/uvicorn-0.31.0-py3-none-any.whl", hash = "sha256:cac7be4dd4d891c363cd942160a7b02e69150dcbc7a36be04d5f4af4b17c8ced", size = 63656 }, + { url = "https://files.pythonhosted.org/packages/eb/14/78bd0e95dd2444b6caacbca2b730671d4295ccb628ef58b81bee903629df/uvicorn-0.32.0-py3-none-any.whl", hash = "sha256:60b8f3a5ac027dcd31448f411ced12b5ef452c646f76f02f8cc3f25d8d26fd82", size = 63723 }, ] [package.optional-dependencies] @@ -1516,22 +1690,28 @@ standard = [ [[package]] name = "uvloop" -version = "0.20.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bc/f1/dc9577455e011ad43d9379e836ee73f40b4f99c02946849a44f7ae64835e/uvloop-0.20.0.tar.gz", hash = "sha256:4603ca714a754fc8d9b197e325db25b2ea045385e8a3ad05d3463de725fdf469", size = 2329938 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/64/bf/45828beccf685b7ed9638d9b77ef382b470c6ca3b5bff78067e02ffd5663/uvloop-0.20.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e50289c101495e0d1bb0bfcb4a60adde56e32f4449a67216a1ab2750aa84f037", size = 1320593 }, - { url = "https://files.pythonhosted.org/packages/27/c0/3c24e50bee7802a2add96ca9f0d5eb0ebab07e0a5615539d38aeb89499b9/uvloop-0.20.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e237f9c1e8a00e7d9ddaa288e535dc337a39bcbf679f290aee9d26df9e72bce9", size = 736676 }, - { url = "https://files.pythonhosted.org/packages/83/ce/ffa3c72954eae36825acfafd2b6a9221d79abd2670c0d25e04d6ef4a2007/uvloop-0.20.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:746242cd703dc2b37f9d8b9f173749c15e9a918ddb021575a0205ec29a38d31e", size = 3494573 }, - { url = "https://files.pythonhosted.org/packages/46/6d/4caab3a36199ba52b98d519feccfcf48921d7a6649daf14a93c7e77497e9/uvloop-0.20.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82edbfd3df39fb3d108fc079ebc461330f7c2e33dbd002d146bf7c445ba6e756", size = 3489932 }, - { url = "https://files.pythonhosted.org/packages/e4/4f/49c51595bd794945c88613df88922c38076eae2d7653f4624aa6f4980b07/uvloop-0.20.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:80dc1b139516be2077b3e57ce1cb65bfed09149e1d175e0478e7a987863b68f0", size = 4185596 }, - { url = "https://files.pythonhosted.org/packages/b8/94/7e256731260d313f5049717d1c4582d52a3b132424c95e16954a50ab95d3/uvloop-0.20.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4f44af67bf39af25db4c1ac27e82e9665717f9c26af2369c404be865c8818dcf", size = 4185746 }, - { url = "https://files.pythonhosted.org/packages/2d/64/31cbd379d6e260ac8de3f672f904e924f09715c3f192b09f26cc8e9f574c/uvloop-0.20.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:4b75f2950ddb6feed85336412b9a0c310a2edbcf4cf931aa5cfe29034829676d", size = 1324302 }, - { url = "https://files.pythonhosted.org/packages/1e/6b/9207e7177ff30f78299401f2e1163ea41130d4fd29bcdc6d12572c06b728/uvloop-0.20.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:77fbc69c287596880ecec2d4c7a62346bef08b6209749bf6ce8c22bbaca0239e", size = 738105 }, - { url = "https://files.pythonhosted.org/packages/c1/ba/b64b10f577519d875992dc07e2365899a1a4c0d28327059ce1e1bdfb6854/uvloop-0.20.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6462c95f48e2d8d4c993a2950cd3d31ab061864d1c226bbf0ee2f1a8f36674b9", size = 4090658 }, - { url = "https://files.pythonhosted.org/packages/0a/f8/5ceea6876154d926604f10c1dd896adf9bce6d55a55911364337b8a5ed8d/uvloop-0.20.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:649c33034979273fa71aa25d0fe120ad1777c551d8c4cd2c0c9851d88fcb13ab", size = 4173357 }, - { url = "https://files.pythonhosted.org/packages/18/b2/117ab6bfb18274753fbc319607bf06e216bd7eea8be81d5bac22c912d6a7/uvloop-0.20.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3a609780e942d43a275a617c0839d85f95c334bad29c4c0918252085113285b5", size = 4029868 }, - { url = "https://files.pythonhosted.org/packages/6f/52/deb4be09060637ef4752adaa0b75bf770c20c823e8108705792f99cd4a6f/uvloop-0.20.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aea15c78e0d9ad6555ed201344ae36db5c63d428818b4b2a42842b3870127c00", size = 4115980 }, +version = "0.21.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/57/a7/4cf0334105c1160dd6819f3297f8700fda7fc30ab4f61fbf3e725acbc7cc/uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8", size = 1447410 }, + { url = "https://files.pythonhosted.org/packages/8c/7c/1517b0bbc2dbe784b563d6ab54f2ef88c890fdad77232c98ed490aa07132/uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0", size = 805476 }, + { url = "https://files.pythonhosted.org/packages/ee/ea/0bfae1aceb82a503f358d8d2fa126ca9dbdb2ba9c7866974faec1cb5875c/uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e", size = 3960855 }, + { url = "https://files.pythonhosted.org/packages/8a/ca/0864176a649838b838f36d44bf31c451597ab363b60dc9e09c9630619d41/uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb", size = 3973185 }, + { url = "https://files.pythonhosted.org/packages/30/bf/08ad29979a936d63787ba47a540de2132169f140d54aa25bc8c3df3e67f4/uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6", size = 3820256 }, + { url = "https://files.pythonhosted.org/packages/da/e2/5cf6ef37e3daf2f06e651aae5ea108ad30df3cb269102678b61ebf1fdf42/uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d", size = 3937323 }, + { url = "https://files.pythonhosted.org/packages/8c/4c/03f93178830dc7ce8b4cdee1d36770d2f5ebb6f3d37d354e061eefc73545/uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c", size = 1471284 }, + { url = "https://files.pythonhosted.org/packages/43/3e/92c03f4d05e50f09251bd8b2b2b584a2a7f8fe600008bcc4523337abe676/uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2", size = 821349 }, + { url = "https://files.pythonhosted.org/packages/a6/ef/a02ec5da49909dbbfb1fd205a9a1ac4e88ea92dcae885e7c961847cd51e2/uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d", size = 4580089 }, + { url = "https://files.pythonhosted.org/packages/06/a7/b4e6a19925c900be9f98bec0a75e6e8f79bb53bdeb891916609ab3958967/uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc", size = 4693770 }, + { url = "https://files.pythonhosted.org/packages/ce/0c/f07435a18a4b94ce6bd0677d8319cd3de61f3a9eeb1e5f8ab4e8b5edfcb3/uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb", size = 4451321 }, + { url = "https://files.pythonhosted.org/packages/8f/eb/f7032be105877bcf924709c97b1bf3b90255b4ec251f9340cef912559f28/uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f", size = 4659022 }, + { url = "https://files.pythonhosted.org/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123 }, + { url = "https://files.pythonhosted.org/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325 }, + { url = "https://files.pythonhosted.org/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806 }, + { url = "https://files.pythonhosted.org/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068 }, + { url = "https://files.pythonhosted.org/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428 }, + { url = "https://files.pythonhosted.org/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018 }, ] [[package]] @@ -1627,58 +1807,62 @@ wheels = [ [[package]] name = "yarl" -version = "1.13.1" +version = "1.17.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "multidict" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e0/11/2b8334f4192646677a2e7da435670d043f536088af943ec242f31453e5ba/yarl-1.13.1.tar.gz", hash = "sha256:ec8cfe2295f3e5e44c51f57272afbd69414ae629ec7c6b27f5a410efc78b70a0", size = 165912 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/37/64/1eaa5d080ceb8742b75a25eff4d510439459ff9c7fbe03e8e929a732ca07/yarl-1.13.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:216a6785f296169ed52cd7dcdc2612f82c20f8c9634bf7446327f50398732a51", size = 189609 }, - { url = "https://files.pythonhosted.org/packages/e2/49/7faf592dd5d4ae4b789988750739c327b81070aa6d428848ce71f6112c1b/yarl-1.13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:40c6e73c03a6befb85b72da213638b8aaa80fe4136ec8691560cf98b11b8ae6e", size = 115504 }, - { url = "https://files.pythonhosted.org/packages/0c/02/6dd48672009bdf135a298a7250875321098b7cbbca5af8c49d8dae07b635/yarl-1.13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2430cf996113abe5aee387d39ee19529327205cda975d2b82c0e7e96e5fdabdc", size = 113754 }, - { url = "https://files.pythonhosted.org/packages/0e/4c/dd49a78833691ccdc15738eb814e37df47f0f25baeefb1cec64ecb4459eb/yarl-1.13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9fb4134cc6e005b99fa29dbc86f1ea0a298440ab6b07c6b3ee09232a3b48f495", size = 486101 }, - { url = "https://files.pythonhosted.org/packages/36/ec/e5e6ed4344de34d3554a22d181df4d90a4d0f257575c28b767ad8c1add0b/yarl-1.13.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:309c104ecf67626c033845b860d31594a41343766a46fa58c3309c538a1e22b2", size = 505989 }, - { url = "https://files.pythonhosted.org/packages/7d/af/0318b0d03471207b3959e0e6ca2964b689744d8482fdbfdc2958854373b4/yarl-1.13.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f90575e9fe3aae2c1e686393a9689c724cd00045275407f71771ae5d690ccf38", size = 500428 }, - { url = "https://files.pythonhosted.org/packages/c4/09/5e47823e3abb26ddda447b500be28137971d246b0c771a02f855dd06b30b/yarl-1.13.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d2e1626be8712333a9f71270366f4a132f476ffbe83b689dd6dc0d114796c74", size = 488954 }, - { url = "https://files.pythonhosted.org/packages/9a/c4/e26317d48bd6bf59dfbb6049d022582a376de01440e5c2bbe92009f8117a/yarl-1.13.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b66c87da3c6da8f8e8b648878903ca54589038a0b1e08dde2c86d9cd92d4ac9", size = 471561 }, - { url = "https://files.pythonhosted.org/packages/93/c5/4dfb00b84fc6df79b3e42d8716ba8f747d7ebf0c14640c7e65d923f39ea7/yarl-1.13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cf1ad338620249f8dd6d4b6a91a69d1f265387df3697ad5dc996305cf6c26fb2", size = 485652 }, - { url = "https://files.pythonhosted.org/packages/9d/fb/bde1430c94d6e5de27d0031e3fb5d85467d975aecdc67e6c686f5c36bbfd/yarl-1.13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:9915300fe5a0aa663c01363db37e4ae8e7c15996ebe2c6cce995e7033ff6457f", size = 483530 }, - { url = "https://files.pythonhosted.org/packages/5c/80/9f9c9d567ac5fb355e252dc27b75ccf92a3e4bea8b1c5610d5d1240c1b30/yarl-1.13.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:703b0f584fcf157ef87816a3c0ff868e8c9f3c370009a8b23b56255885528f10", size = 514085 }, - { url = "https://files.pythonhosted.org/packages/aa/9b/3aeb817a60bde4be6acb476a46bc6184c27b5c91f23ec726d9e6e46b89cf/yarl-1.13.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1d8e3ca29f643dd121f264a7c89f329f0fcb2e4461833f02de6e39fef80f89da", size = 516342 }, - { url = "https://files.pythonhosted.org/packages/71/9d/d7aa4fd8b16e174c4c16b826f54a0e9e4533fb3ae09741906ccc811362d0/yarl-1.13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:7055bbade838d68af73aea13f8c86588e4bcc00c2235b4b6d6edb0dbd174e246", size = 498430 }, - { url = "https://files.pythonhosted.org/packages/b0/3d/b46aad1725f8d043beee2d47ffddffb1939178bec6f9584b46215efe5a78/yarl-1.13.1-cp311-cp311-win32.whl", hash = "sha256:a3442c31c11088e462d44a644a454d48110f0588de830921fd201060ff19612a", size = 102436 }, - { url = "https://files.pythonhosted.org/packages/89/9e/bbbda05279230dc12d879dfcf971f77f9c932e457fbcd870efb4c3bdf10c/yarl-1.13.1-cp311-cp311-win_amd64.whl", hash = "sha256:81bad32c8f8b5897c909bf3468bf601f1b855d12f53b6af0271963ee67fff0d2", size = 111678 }, - { url = "https://files.pythonhosted.org/packages/64/de/1602352e5bb47c4b86921b004fe84d0646ef9abeda3dfc55f1d2271829e4/yarl-1.13.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f452cc1436151387d3d50533523291d5f77c6bc7913c116eb985304abdbd9ec9", size = 190253 }, - { url = "https://files.pythonhosted.org/packages/83/f0/2abc6f0af8f243c4a5190e687897e7684baea2c97f5f1be2321418163c7e/yarl-1.13.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9cec42a20eae8bebf81e9ce23fb0d0c729fc54cf00643eb251ce7c0215ad49fe", size = 116079 }, - { url = "https://files.pythonhosted.org/packages/ad/eb/a578f935e2b6834a00b38156f81f3a6545e14a360ff8a296019116502a9c/yarl-1.13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d959fe96e5c2712c1876d69af0507d98f0b0e8d81bee14cfb3f6737470205419", size = 113943 }, - { url = "https://files.pythonhosted.org/packages/da/ee/2bf5f8ffbea5b18fbca274dd04e300a033e43e92d261ac60722361b216ce/yarl-1.13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b8c837ab90c455f3ea8e68bee143472ee87828bff19ba19776e16ff961425b57", size = 483984 }, - { url = "https://files.pythonhosted.org/packages/05/9f/20d07ed84cbac847b989ef61130f2cbec6dc60f273b81d51041c35740eb3/yarl-1.13.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:94a993f976cdcb2dc1b855d8b89b792893220db8862d1a619efa7451817c836b", size = 499723 }, - { url = "https://files.pythonhosted.org/packages/e5/90/cc6d3dab4fc33b6f80d498c6276995fcbe16db1005141be6133345b597c1/yarl-1.13.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b2442a415a5f4c55ced0fade7b72123210d579f7d950e0b5527fc598866e62c", size = 497279 }, - { url = "https://files.pythonhosted.org/packages/47/a0/c1404aa8c7e025aa05a81f3a34c42131f8b11836e49450e1558bcd64a3bb/yarl-1.13.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fdbf0418489525231723cdb6c79e7738b3cbacbaed2b750cb033e4ea208f220", size = 490188 }, - { url = "https://files.pythonhosted.org/packages/2e/8b/ebb195c4a4a5b5a84b0ade8469404609d68adf8f1dcf88e8b2b5297566cc/yarl-1.13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6b7f6e699304717fdc265a7e1922561b02a93ceffdaefdc877acaf9b9f3080b8", size = 469378 }, - { url = "https://files.pythonhosted.org/packages/40/8f/6a00380c6653006ac0112ebbf0ff24eb7b2d71359ac2c410a98822d89bfa/yarl-1.13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bcd5bf4132e6a8d3eb54b8d56885f3d3a38ecd7ecae8426ecf7d9673b270de43", size = 485681 }, - { url = "https://files.pythonhosted.org/packages/2c/94/797d18a3b9ea125a24ba3c69cd71b3561d227d5bb61dbadf2cb2afd6c319/yarl-1.13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2a93a4557f7fc74a38ca5a404abb443a242217b91cd0c4840b1ebedaad8919d4", size = 486049 }, - { url = "https://files.pythonhosted.org/packages/75/b2/3573e18eb52ca204ee076a94c145edc80c3df21694648b35ae34c19ac9bb/yarl-1.13.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:22b739f99c7e4787922903f27a892744189482125cc7b95b747f04dd5c83aa9f", size = 506742 }, - { url = "https://files.pythonhosted.org/packages/1f/36/f6b5b0fb7c771d5c6c08b7d00a53cd523793454113d4c96460e3f49a1cdd/yarl-1.13.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2db874dd1d22d4c2c657807562411ffdfabec38ce4c5ce48b4c654be552759dc", size = 517070 }, - { url = "https://files.pythonhosted.org/packages/8e/17/48637d4ddcb606f5591afee78d060eab70e172e14766e1fd23453bfed846/yarl-1.13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4feaaa4742517eaceafcbe74595ed335a494c84634d33961214b278126ec1485", size = 502397 }, - { url = "https://files.pythonhosted.org/packages/83/2c/7392645dc1c9eeb8a5485696302a33e3d59bea8a448c8e2f36f98a728e0a/yarl-1.13.1-cp312-cp312-win32.whl", hash = "sha256:bbf9c2a589be7414ac4a534d54e4517d03f1cbb142c0041191b729c2fa23f320", size = 102343 }, - { url = "https://files.pythonhosted.org/packages/9c/c0/7329799080d7e0bf7b10db417900701ba6810e78a249aef1f4bf3fc2cccb/yarl-1.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:d07b52c8c450f9366c34aa205754355e933922c79135125541daae6cbf31c799", size = 111719 }, - { url = "https://files.pythonhosted.org/packages/d3/d2/9542e6207a6e64c32b14b2d9ca4fad6ff80310fc75e70cdbe31680a758c2/yarl-1.13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:95c6737f28069153c399d875317f226bbdea939fd48a6349a3b03da6829fb550", size = 186266 }, - { url = "https://files.pythonhosted.org/packages/8b/68/4c6d1aacbc23a05e84c3fab7aaa68c5a7d4531290021c2370fa1e5524fb1/yarl-1.13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:cd66152561632ed4b2a9192e7f8e5a1d41e28f58120b4761622e0355f0fe034c", size = 114268 }, - { url = "https://files.pythonhosted.org/packages/ed/87/6ad8e22c918d745092329ec427c0778b5c85ffd5b805e38750024b7464f2/yarl-1.13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6a2acde25be0cf9be23a8f6cbd31734536a264723fca860af3ae5e89d771cd71", size = 112164 }, - { url = "https://files.pythonhosted.org/packages/ca/5b/c6c4ac4be1edea6759f05ad74d87a1c61329737bdb90da5f66e188310461/yarl-1.13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a18595e6a2ee0826bf7dfdee823b6ab55c9b70e8f80f8b77c37e694288f5de1", size = 471437 }, - { url = "https://files.pythonhosted.org/packages/c1/5c/ec7f0121a5fa67ee76325e1aaa27470d5521d80a25aa1bad5dde773edbe1/yarl-1.13.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a31d21089894942f7d9a8df166b495101b7258ff11ae0abec58e32daf8088813", size = 485894 }, - { url = "https://files.pythonhosted.org/packages/d7/e8/624fc8082cbff62c537798ce837a6044f70e2e00472ab719deb376ff6e39/yarl-1.13.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:45f209fb4bbfe8630e3d2e2052535ca5b53d4ce2d2026bed4d0637b0416830da", size = 486702 }, - { url = "https://files.pythonhosted.org/packages/dc/18/013f7d2e3f0ff28b85299ed19164f899ea4f02da8812621a40937428bf48/yarl-1.13.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f722f30366474a99745533cc4015b1781ee54b08de73260b2bbe13316079851", size = 478911 }, - { url = "https://files.pythonhosted.org/packages/d7/3c/5b628939e3a22fb9375df453188e97190d21f6244c49637e19799896cd41/yarl-1.13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3bf60444269345d712838bb11cc4eadaf51ff1a364ae39ce87a5ca8ad3bb2c8", size = 456488 }, - { url = "https://files.pythonhosted.org/packages/8b/2b/a3548db86510c1d95bff344c1c588b84582eeb3a55ea15a149a24d7069f0/yarl-1.13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:942c80a832a79c3707cca46bd12ab8aa58fddb34b1626d42b05aa8f0bcefc206", size = 475016 }, - { url = "https://files.pythonhosted.org/packages/d8/e2/e2a540f18f849909e3ee594766bf7b0a7fde176ff0cfb2f95121033752e2/yarl-1.13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:44b07e1690f010c3c01d353b5790ec73b2f59b4eae5b0000593199766b3f7a5c", size = 477521 }, - { url = "https://files.pythonhosted.org/packages/3a/df/4cda4052da48a57ce4f20a0849b7344902aa3e149a0b409525509fc43985/yarl-1.13.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:396e59b8de7e4d59ff5507fb4322d2329865b909f29a7ed7ca37e63ade7f835c", size = 492000 }, - { url = "https://files.pythonhosted.org/packages/bf/b6/180dbb0aa846cafb9ce89bd33c477e200dd00072c7775372f34651c20b9a/yarl-1.13.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3bb83a0f12701c0b91112a11148b5217617982e1e466069d0555be9b372f2734", size = 502195 }, - { url = "https://files.pythonhosted.org/packages/ff/37/e97c280344342e326a1860a70054a0488c379e8937325f97f9a9fe6b453d/yarl-1.13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c92b89bffc660f1274779cb6fbb290ec1f90d6dfe14492523a0667f10170de26", size = 492892 }, - { url = "https://files.pythonhosted.org/packages/ed/97/cd35f39ba8183ef193a6709aa0b2fcaabebd6915202d6999b01fa630b2bb/yarl-1.13.1-cp313-cp313-win32.whl", hash = "sha256:269c201bbc01d2cbba5b86997a1e0f73ba5e2f471cfa6e226bcaa7fd664b598d", size = 486463 }, - { url = "https://files.pythonhosted.org/packages/05/33/bd9d33503a0f73d095b01ed438423b924e6786e90102ca4912e573cc5aa3/yarl-1.13.1-cp313-cp313-win_amd64.whl", hash = "sha256:1d0828e17fa701b557c6eaed5edbd9098eb62d8838344486248489ff233998b8", size = 493804 }, - { url = "https://files.pythonhosted.org/packages/74/81/419c24f7c94f56b96d04955482efb5b381635ad265b5b7fbab333a9dfde3/yarl-1.13.1-py3-none-any.whl", hash = "sha256:6a5185ad722ab4dd52d5fb1f30dcc73282eb1ed494906a92d1a228d3f89607b0", size = 39862 }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/54/9c/9c0a9bfa683fc1be7fdcd9687635151544d992cccd48892dc5e0a5885a29/yarl-1.17.1.tar.gz", hash = "sha256:067a63fcfda82da6b198fa73079b1ca40b7c9b7994995b6ee38acda728b64d47", size = 178163 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/0f/ce6a2c8aab9946446fb27f1e28f0fd89ce84ae913ab18a92d18078a1c7ed/yarl-1.17.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cbad927ea8ed814622305d842c93412cb47bd39a496ed0f96bfd42b922b4a217", size = 140727 }, + { url = "https://files.pythonhosted.org/packages/9d/df/204f7a502bdc3973cd9fc29e7dfad18ae48b3acafdaaf1ae07c0f41025aa/yarl-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fca4b4307ebe9c3ec77a084da3a9d1999d164693d16492ca2b64594340999988", size = 93560 }, + { url = "https://files.pythonhosted.org/packages/a2/e1/f4d522ae0560c91a4ea31113a50f00f85083be885e1092fc6e74eb43cb1d/yarl-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff5c6771c7e3511a06555afa317879b7db8d640137ba55d6ab0d0c50425cab75", size = 91497 }, + { url = "https://files.pythonhosted.org/packages/f1/82/783d97bf4a226f1a2e59b1966f2752244c2bf4dc89bc36f61d597b8e34e5/yarl-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b29beab10211a746f9846baa39275e80034e065460d99eb51e45c9a9495bcca", size = 339446 }, + { url = "https://files.pythonhosted.org/packages/e5/ff/615600647048d81289c80907165de713fbc566d1e024789863a2f6563ba3/yarl-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a52a1ffdd824fb1835272e125385c32fd8b17fbdefeedcb4d543cc23b332d74", size = 354616 }, + { url = "https://files.pythonhosted.org/packages/a5/04/bfb7adb452bd19dfe0c35354ffce8ebc3086e028e5f8270e409d17da5466/yarl-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58c8e9620eb82a189c6c40cb6b59b4e35b2ee68b1f2afa6597732a2b467d7e8f", size = 351801 }, + { url = "https://files.pythonhosted.org/packages/10/e0/efe21edacdc4a638ce911f8cabf1c77cac3f60e9819ba7d891b9ceb6e1d4/yarl-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d216e5d9b8749563c7f2c6f7a0831057ec844c68b4c11cb10fc62d4fd373c26d", size = 343381 }, + { url = "https://files.pythonhosted.org/packages/63/f9/7bc7e69857d6fc3920ecd173592f921d5701f4a0dd3f2ae293b386cfa3bf/yarl-1.17.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:881764d610e3269964fc4bb3c19bb6fce55422828e152b885609ec176b41cf11", size = 337093 }, + { url = "https://files.pythonhosted.org/packages/93/52/99da61947466275ff17d7bc04b0ac31dfb7ec699bd8d8985dffc34c3a913/yarl-1.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8c79e9d7e3d8a32d4824250a9c6401194fb4c2ad9a0cec8f6a96e09a582c2cc0", size = 346619 }, + { url = "https://files.pythonhosted.org/packages/91/8a/8aaad86a35a16e485ba0e5de0d2ae55bf8dd0c9f1cccac12be4c91366b1d/yarl-1.17.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:299f11b44d8d3a588234adbe01112126010bd96d9139c3ba7b3badd9829261c3", size = 344347 }, + { url = "https://files.pythonhosted.org/packages/af/b6/97f29f626b4a1768ffc4b9b489533612cfcb8905c90f745aade7b2eaf75e/yarl-1.17.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:cc7d768260f4ba4ea01741c1b5fe3d3a6c70eb91c87f4c8761bbcce5181beafe", size = 350316 }, + { url = "https://files.pythonhosted.org/packages/d7/98/8e0e8b812479569bdc34d66dd3e2471176ca33be4ff5c272a01333c4b269/yarl-1.17.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:de599af166970d6a61accde358ec9ded821234cbbc8c6413acfec06056b8e860", size = 361336 }, + { url = "https://files.pythonhosted.org/packages/9e/d3/d1507efa0a85c25285f8eb51df9afa1ba1b6e446dda781d074d775b6a9af/yarl-1.17.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2b24ec55fad43e476905eceaf14f41f6478780b870eda5d08b4d6de9a60b65b4", size = 365350 }, + { url = "https://files.pythonhosted.org/packages/22/ba/ee7f1830449c96bae6f33210b7d89e8aaf3079fbdaf78ac398e50a9da404/yarl-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9fb815155aac6bfa8d86184079652c9715c812d506b22cfa369196ef4e99d1b4", size = 357689 }, + { url = "https://files.pythonhosted.org/packages/a0/85/321c563dc5afe1661108831b965c512d185c61785400f5606006507d2e18/yarl-1.17.1-cp311-cp311-win32.whl", hash = "sha256:7615058aabad54416ddac99ade09a5510cf77039a3b903e94e8922f25ed203d7", size = 83635 }, + { url = "https://files.pythonhosted.org/packages/bc/da/543a32c00860588ff1235315b68f858cea30769099c32cd22b7bb266411b/yarl-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:14bc88baa44e1f84164a392827b5defb4fa8e56b93fecac3d15315e7c8e5d8b3", size = 90218 }, + { url = "https://files.pythonhosted.org/packages/5d/af/e25615c7920396219b943b9ff8b34636ae3e1ad30777649371317d7f05f8/yarl-1.17.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:327828786da2006085a4d1feb2594de6f6d26f8af48b81eb1ae950c788d97f61", size = 141839 }, + { url = "https://files.pythonhosted.org/packages/83/5e/363d9de3495c7c66592523f05d21576a811015579e0c87dd38c7b5788afd/yarl-1.17.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cc353841428d56b683a123a813e6a686e07026d6b1c5757970a877195f880c2d", size = 94125 }, + { url = "https://files.pythonhosted.org/packages/e3/a2/b65447626227ebe36f18f63ac551790068bf42c69bb22dfa3ae986170728/yarl-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c73df5b6e8fabe2ddb74876fb82d9dd44cbace0ca12e8861ce9155ad3c886139", size = 92048 }, + { url = "https://files.pythonhosted.org/packages/a1/f5/2ef86458446f85cde10582054fd5113495ef8ce8477da35aaaf26d2970ef/yarl-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bdff5e0995522706c53078f531fb586f56de9c4c81c243865dd5c66c132c3b5", size = 331472 }, + { url = "https://files.pythonhosted.org/packages/f3/6b/1ba79758ba352cdf2ad4c20cab1b982dd369aa595bb0d7601fc89bf82bee/yarl-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:06157fb3c58f2736a5e47c8fcbe1afc8b5de6fb28b14d25574af9e62150fcaac", size = 341260 }, + { url = "https://files.pythonhosted.org/packages/2d/41/4e07c2afca3f9ed3da5b0e38d43d0280d9b624a3d5c478c425e5ce17775c/yarl-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1654ec814b18be1af2c857aa9000de7a601400bd4c9ca24629b18486c2e35463", size = 340882 }, + { url = "https://files.pythonhosted.org/packages/c3/c0/cd8e94618983c1b811af082e1a7ad7764edb3a6af2bc6b468e0e686238ba/yarl-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f6595c852ca544aaeeb32d357e62c9c780eac69dcd34e40cae7b55bc4fb1147", size = 336648 }, + { url = "https://files.pythonhosted.org/packages/ac/fc/73ec4340d391ffbb8f34eb4c55429784ec9f5bd37973ce86d52d67135418/yarl-1.17.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:459e81c2fb920b5f5df744262d1498ec2c8081acdcfe18181da44c50f51312f7", size = 325019 }, + { url = "https://files.pythonhosted.org/packages/57/48/da3ebf418fc239d0a156b3bdec6b17a5446f8d2dea752299c6e47b143a85/yarl-1.17.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7e48cdb8226644e2fbd0bdb0a0f87906a3db07087f4de77a1b1b1ccfd9e93685", size = 342841 }, + { url = "https://files.pythonhosted.org/packages/5d/79/107272745a470a8167924e353a5312eb52b5a9bb58e22686adc46c94f7ec/yarl-1.17.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d9b6b28a57feb51605d6ae5e61a9044a31742db557a3b851a74c13bc61de5172", size = 341433 }, + { url = "https://files.pythonhosted.org/packages/30/9c/6459668b3b8dcc11cd061fc53e12737e740fb6b1575b49c84cbffb387b3a/yarl-1.17.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e594b22688d5747b06e957f1ef822060cb5cb35b493066e33ceac0cf882188b7", size = 344927 }, + { url = "https://files.pythonhosted.org/packages/c5/0b/93a17ed733aca8164fc3a01cb7d47b3f08854ce4f957cce67a6afdb388a0/yarl-1.17.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5f236cb5999ccd23a0ab1bd219cfe0ee3e1c1b65aaf6dd3320e972f7ec3a39da", size = 355732 }, + { url = "https://files.pythonhosted.org/packages/9a/63/ead2ed6aec3c59397e135cadc66572330325a0c24cd353cd5c94f5e63463/yarl-1.17.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a2a64e62c7a0edd07c1c917b0586655f3362d2c2d37d474db1a509efb96fea1c", size = 362123 }, + { url = "https://files.pythonhosted.org/packages/89/bf/f6b75b4c2fcf0e7bb56edc0ed74e33f37fac45dc40e5a52a3be66b02587a/yarl-1.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d0eea830b591dbc68e030c86a9569826145df485b2b4554874b07fea1275a199", size = 356355 }, + { url = "https://files.pythonhosted.org/packages/45/1f/50a0257cd07eef65c8c65ad6a21f5fb230012d659e021aeb6ac8a7897bf6/yarl-1.17.1-cp312-cp312-win32.whl", hash = "sha256:46ddf6e0b975cd680eb83318aa1d321cb2bf8d288d50f1754526230fcf59ba96", size = 83279 }, + { url = "https://files.pythonhosted.org/packages/bc/82/fafb2c1268d63d54ec08b3a254fbe51f4ef098211501df646026717abee3/yarl-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:117ed8b3732528a1e41af3aa6d4e08483c2f0f2e3d3d7dca7cf538b3516d93df", size = 89590 }, + { url = "https://files.pythonhosted.org/packages/06/1e/5a93e3743c20eefbc68bd89334d9c9f04f3f2334380f7bbf5e950f29511b/yarl-1.17.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5d1d42556b063d579cae59e37a38c61f4402b47d70c29f0ef15cee1acaa64488", size = 139974 }, + { url = "https://files.pythonhosted.org/packages/a1/be/4e0f6919013c7c5eaea5c31811c551ccd599d2fc80aa3dd6962f1bbdcddd/yarl-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c0167540094838ee9093ef6cc2c69d0074bbf84a432b4995835e8e5a0d984374", size = 93364 }, + { url = "https://files.pythonhosted.org/packages/73/f0/650f994bc491d0cb85df8bb45392780b90eab1e175f103a5edc61445ff67/yarl-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2f0a6423295a0d282d00e8701fe763eeefba8037e984ad5de44aa349002562ac", size = 91177 }, + { url = "https://files.pythonhosted.org/packages/f3/e8/9945ed555d14b43ede3ae8b1bd73e31068a694cad2b9d3cad0a28486c2eb/yarl-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5b078134f48552c4d9527db2f7da0b5359abd49393cdf9794017baec7506170", size = 333086 }, + { url = "https://files.pythonhosted.org/packages/a6/c0/7d167e48e14d26639ca066825af8da7df1d2fcdba827e3fd6341aaf22a3b/yarl-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d401f07261dc5aa36c2e4efc308548f6ae943bfff20fcadb0a07517a26b196d8", size = 343661 }, + { url = "https://files.pythonhosted.org/packages/fa/81/80a266517531d4e3553aecd141800dbf48d02e23ebd52909e63598a80134/yarl-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5f1ac7359e17efe0b6e5fec21de34145caef22b260e978336f325d5c84e6938", size = 345196 }, + { url = "https://files.pythonhosted.org/packages/b0/77/6adc482ba7f2dc6c0d9b3b492e7cd100edfac4cfc3849c7ffa26fd7beb1a/yarl-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f63d176a81555984e91f2c84c2a574a61cab7111cc907e176f0f01538e9ff6e", size = 338743 }, + { url = "https://files.pythonhosted.org/packages/6d/cc/f0c4c0b92ff3ada517ffde2b127406c001504b225692216d969879ada89a/yarl-1.17.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e275792097c9f7e80741c36de3b61917aebecc08a67ae62899b074566ff8556", size = 326719 }, + { url = "https://files.pythonhosted.org/packages/18/3b/7bfc80d3376b5fa162189993a87a5a6a58057f88315bd0ea00610055b57a/yarl-1.17.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:81713b70bea5c1386dc2f32a8f0dab4148a2928c7495c808c541ee0aae614d67", size = 345826 }, + { url = "https://files.pythonhosted.org/packages/2e/66/cf0b0338107a5c370205c1a572432af08f36ca12ecce127f5b558398b4fd/yarl-1.17.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:aa46dce75078fceaf7cecac5817422febb4355fbdda440db55206e3bd288cfb8", size = 340335 }, + { url = "https://files.pythonhosted.org/packages/2f/52/b084b0eec0fd4d2490e1d33ace3320fad704c5f1f3deaa709f929d2d87fc/yarl-1.17.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1ce36ded585f45b1e9bb36d0ae94765c6608b43bd2e7f5f88079f7a85c61a4d3", size = 345301 }, + { url = "https://files.pythonhosted.org/packages/ef/38/9e2036d948efd3bafcdb4976cb212166fded76615f0dfc6c1492c4ce4784/yarl-1.17.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:2d374d70fdc36f5863b84e54775452f68639bc862918602d028f89310a034ab0", size = 354205 }, + { url = "https://files.pythonhosted.org/packages/81/c1/13dfe1e70b86811733316221c696580725ceb1c46d4e4db852807e134310/yarl-1.17.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2d9f0606baaec5dd54cb99667fcf85183a7477f3766fbddbe3f385e7fc253299", size = 360501 }, + { url = "https://files.pythonhosted.org/packages/91/87/756e05c74cd8bf9e71537df4a2cae7e8211a9ebe0d2350a3e26949e1e41c/yarl-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b0341e6d9a0c0e3cdc65857ef518bb05b410dbd70d749a0d33ac0f39e81a4258", size = 359452 }, + { url = "https://files.pythonhosted.org/packages/06/b2/b2bb09c1e6d59e1c9b1b36a86caa473e22c3dbf26d1032c030e9bfb554dc/yarl-1.17.1-cp313-cp313-win32.whl", hash = "sha256:2e7ba4c9377e48fb7b20dedbd473cbcbc13e72e1826917c185157a137dac9df2", size = 308904 }, + { url = "https://files.pythonhosted.org/packages/f3/27/f084d9a5668853c1f3b246620269b14ee871ef3c3cc4f3a1dd53645b68ec/yarl-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:949681f68e0e3c25377462be4b658500e85ca24323d9619fdc41f68d46a1ffda", size = 314637 }, + { url = "https://files.pythonhosted.org/packages/52/ad/1fe7ff5f3e8869d4c5070f47b96bac2b4d15e67c100a8278d8e7876329fc/yarl-1.17.1-py3-none-any.whl", hash = "sha256:f1790a4b1e8e8e028c391175433b9c8122c39b46e1663228158e61e6f915bf06", size = 44352 }, ] diff --git a/libraries/python/context/context/context.py b/libraries/python/context/context/context.py index 256199b7..5f3dfb8e 100644 --- a/libraries/python/context/context/context.py +++ b/libraries/python/context/context/context.py @@ -27,7 +27,7 @@ class ContextProtocol(Protocol): # The emit function is used to send events to the event bus. The component # that creates this context object will be responsible for instantiating an # event bus and handling the events sent to it with this function. - emit: Optional[Callable[[EventProtocol], None]] + emit: Callable[[EventProtocol], None] class LogEmitter: @@ -38,7 +38,7 @@ def emit(self, event: EventProtocol) -> None: logging.info(event.to_json()) -class Context: +class Context(ContextProtocol): """A default context object that implements the ContextProtocol. The context object that is passed to all components (functions, action, routines, etc.). The context object is used to pass information between these components, diff --git a/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb b/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb index 9ee658ee..cbc18ebf 100644 --- a/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb +++ b/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb @@ -126,9 +126,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'id': 'chatcmpl-AQga9wXFldlhHVce3CfXMQ7jXo9L9', 'choices': [{'finish_reason': 'stop', 'index': 0, 'logprobs': None, 'message': {'content': 'This is a test.', 'refusal': None, 'role': 'assistant', 'function_call': None, 'tool_calls': None}}], 'created': 1730923577, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': {'completion_tokens': 5, 'prompt_tokens': 12, 'total_tokens': 17, 'completion_tokens_details': None, 'prompt_tokens_details': None}}\n" + ] + } + ], "source": [ "completion = client.chat.completions.create(\n", " messages=[\n", @@ -151,9 +159,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ChatCompletion(id='chatcmpl-AQgaCid05i8dGgUHijQsvPAsMYbv4', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='This is a test.', refusal=None, role='assistant', function_call=None, tool_calls=None))], created=1730923580, model='gpt-4o-2024-08-06', object='chat.completion', service_tier=None, system_fingerprint='fp_d54531d9eb', usage=CompletionUsage(completion_tokens=5, prompt_tokens=12, total_tokens=17, completion_tokens_details=None, prompt_tokens_details=None))\n" + ] + } + ], "source": [ "response = await async_client.chat.completions.create(\n", " messages=[\n", @@ -176,9 +192,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': '', 'function_call': None, 'refusal': None, 'role': 'assistant', 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': 'This', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': ' is', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': ' a', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': ' test', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': '.', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': None, 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': 'stop', 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n" + ] + } + ], "source": [ "stream = await async_client.chat.completions.create(\n", " messages=[\n", @@ -227,7 +257,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -236,7 +266,7 @@ "text": [ "conversation-id-1000\n", "\n", - "Hello, Paul! How can I assist you today?\n", + "Hello Paul! How can I assist you today?\n", "\n", "Commands:\n", "help(): Return this help message.\n", @@ -246,15 +276,16 @@ "\n", "conversation-id-1000: Hi, my name is Paul.\n", "\n", - "The contents of the file 123.txt are: \"The purpose of life is to be happy.\" If you need any further assistance or information, feel free to ask!\n", + "The content of \"123.txt\" is: \"The purpose of life is to be happy.\"\n", "\n", "{\n", - " \"id\": \"0222a092-6bfd-4523-9cf8-d895070c554b\",\n", + " \"id\": \"9444f8f2-aa5a-4c19-9bf4-d36b6bfa9ba4\",\n", " \"session_id\": null,\n", - " \"timestamp\": \"2024-10-10T17:20:00.290438\",\n", - " \"message\": \"The contents of the file 123.txt are: \\\"The purpose of life is to be happy.\\\" If you need any further assistance or information, feel free to ask!\",\n", + " \"timestamp\": \"2024-11-06T20:06:27.777169\",\n", + " \"message\": \"The content of \\\"123.txt\\\" is: \\\"The purpose of life is to be happy.\\\"\",\n", " \"metadata\": {\n", " \"completion_args\": {\n", + " \"model\": \"gpt-4o\",\n", " \"messages\": [\n", " {\n", " \"role\": \"system\",\n", @@ -265,27 +296,25 @@ " \"content\": \"Hi, my name is Paul.\"\n", " },\n", " {\n", - " \"content\": \"Hello, Paul! How can I assist you today?\",\n", - " \"refusal\": null,\n", " \"role\": \"assistant\",\n", - " \"function_call\": null,\n", - " \"tool_calls\": null\n", + " \"content\": \"Hello Paul! How can I assist you today?\"\n", " },\n", " {\n", " \"role\": \"user\",\n", " \"content\": \"Please tell me what's in file 123.txt.\"\n", " }\n", " ],\n", - " \"model\": \"gpt-4o\",\n", " \"tools\": [\n", " {\n", " \"type\": \"function\",\n", " \"function\": {\n", " \"name\": \"help\",\n", " \"description\": \"Return this help message.\",\n", + " \"strict\": true,\n", " \"parameters\": {\n", " \"type\": \"object\",\n", - " \"properties\": {}\n", + " \"properties\": {},\n", + " \"additionalProperties\": false\n", " }\n", " }\n", " },\n", @@ -294,17 +323,19 @@ " \"function\": {\n", " \"name\": \"erase\",\n", " \"description\": \"Erases a stored value.\",\n", + " \"strict\": true,\n", " \"parameters\": {\n", " \"type\": \"object\",\n", " \"properties\": {\n", " \"name\": {\n", " \"type\": \"string\"\n", " }\n", - " }\n", - " },\n", - " \"required\": [\n", - " \"name\"\n", - " ]\n", + " },\n", + " \"additionalProperties\": false,\n", + " \"required\": [\n", + " \"name\"\n", + " ]\n", + " }\n", " }\n", " },\n", " {\n", @@ -312,17 +343,19 @@ " \"function\": {\n", " \"name\": \"echo\",\n", " \"description\": \"Return the text.\",\n", + " \"strict\": true,\n", " \"parameters\": {\n", " \"type\": \"object\",\n", " \"properties\": {\n", " \"text\": {\n", " \"type\": \"string\"\n", " }\n", - " }\n", - " },\n", - " \"required\": [\n", - " \"text\"\n", - " ]\n", + " },\n", + " \"additionalProperties\": false,\n", + " \"required\": [\n", + " \"text\"\n", + " ]\n", + " }\n", " }\n", " },\n", " {\n", @@ -330,26 +363,29 @@ " \"function\": {\n", " \"name\": \"get_file_contents\",\n", " \"description\": \"Return the contents of a file.\",\n", + " \"strict\": true,\n", " \"parameters\": {\n", " \"type\": \"object\",\n", " \"properties\": {\n", " \"file_path\": {\n", " \"type\": \"string\"\n", " }\n", - " }\n", - " },\n", - " \"required\": [\n", - " \"file_path\"\n", - " ]\n", + " },\n", + " \"additionalProperties\": false,\n", + " \"required\": [\n", + " \"file_path\"\n", + " ]\n", + " }\n", " }\n", " }\n", " ],\n", + " \"tool_choice\": null,\n", " \"response_format\": {\n", " \"type\": \"text\"\n", " }\n", " },\n", - " \"completion_response\": {\n", - " \"id\": \"chatcmpl-AGr7Pmberc78CWRv24nypSR0ALAJv\",\n", + " \"completion\": {\n", + " \"id\": \"chatcmpl-AQgaIFjYmKV3PUaYNUoYOKQ9LraYg\",\n", " \"choices\": [\n", " {\n", " \"finish_reason\": \"tool_calls\",\n", @@ -362,52 +398,36 @@ " \"function_call\": null,\n", " \"tool_calls\": [\n", " {\n", - " \"id\": \"call_Nbica1hw3v0FSis7aUPQ5Zvy\",\n", + " \"id\": \"call_hCAzGLjdWGTBMVbJDi3ZYs2Z\",\n", " \"function\": {\n", " \"arguments\": \"{\\\"file_path\\\":\\\"123.txt\\\"}\",\n", - " \"name\": \"get_file_contents\"\n", + " \"name\": \"get_file_contents\",\n", + " \"parsed_arguments\": {\n", + " \"file_path\": \"123.txt\"\n", + " }\n", " },\n", " \"type\": \"function\"\n", " }\n", - " ]\n", + " ],\n", + " \"parsed\": null\n", " }\n", " }\n", " ],\n", - " \"created\": 1728580799,\n", - " \"model\": \"gpt-4o-mini\",\n", + " \"created\": 1730923586,\n", + " \"model\": \"gpt-4o-2024-08-06\",\n", " \"object\": \"chat.completion\",\n", " \"service_tier\": null,\n", - " \"system_fingerprint\": \"fp_878413d04d\",\n", + " \"system_fingerprint\": \"fp_d54531d9eb\",\n", " \"usage\": {\n", " \"completion_tokens\": 17,\n", - " \"prompt_tokens\": 136,\n", - " \"total_tokens\": 153,\n", + " \"prompt_tokens\": 135,\n", + " \"total_tokens\": 152,\n", " \"completion_tokens_details\": null,\n", " \"prompt_tokens_details\": null\n", " }\n", " },\n", - " \"assistant_response\": {\n", - " \"content\": null,\n", - " \"refusal\": null,\n", - " \"role\": \"assistant\",\n", - " \"function_call\": null,\n", - " \"tool_calls\": [\n", - " {\n", - " \"id\": \"call_Nbica1hw3v0FSis7aUPQ5Zvy\",\n", - " \"function\": {\n", - " \"arguments\": \"{\\\"file_path\\\":\\\"123.txt\\\"}\",\n", - " \"name\": \"get_file_contents\"\n", - " },\n", - " \"type\": \"function\"\n", - " }\n", - " ]\n", - " },\n", - " \"function_call_result_message\": {\n", - " \"role\": \"tool\",\n", - " \"content\": \"The purpose of life is to be happy.\",\n", - " \"tool_call_id\": \"call_Nbica1hw3v0FSis7aUPQ5Zvy\"\n", - " },\n", - " \"assistant_tool_completion_args\": {\n", + " \"tool_completion_args\": {\n", + " \"model\": \"gpt-4o\",\n", " \"messages\": [\n", " {\n", " \"role\": \"system\",\n", @@ -418,27 +438,24 @@ " \"content\": \"Hi, my name is Paul.\"\n", " },\n", " {\n", - " \"content\": \"Hello, Paul! How can I assist you today?\",\n", - " \"refusal\": null,\n", " \"role\": \"assistant\",\n", - " \"function_call\": null,\n", - " \"tool_calls\": null\n", + " \"content\": \"Hello Paul! How can I assist you today?\"\n", " },\n", " {\n", " \"role\": \"user\",\n", " \"content\": \"Please tell me what's in file 123.txt.\"\n", " },\n", " {\n", - " \"content\": null,\n", - " \"refusal\": null,\n", " \"role\": \"assistant\",\n", - " \"function_call\": null,\n", " \"tool_calls\": [\n", " {\n", - " \"id\": \"call_Nbica1hw3v0FSis7aUPQ5Zvy\",\n", + " \"id\": \"call_hCAzGLjdWGTBMVbJDi3ZYs2Z\",\n", " \"function\": {\n", " \"arguments\": \"{\\\"file_path\\\":\\\"123.txt\\\"}\",\n", - " \"name\": \"get_file_contents\"\n", + " \"name\": \"get_file_contents\",\n", + " \"parsed_arguments\": {\n", + " \"file_path\": \"123.txt\"\n", + " }\n", " },\n", " \"type\": \"function\"\n", " }\n", @@ -447,17 +464,12 @@ " {\n", " \"role\": \"tool\",\n", " \"content\": \"The purpose of life is to be happy.\",\n", - " \"tool_call_id\": \"call_Nbica1hw3v0FSis7aUPQ5Zvy\"\n", + " \"tool_call_id\": \"call_hCAzGLjdWGTBMVbJDi3ZYs2Z\"\n", " }\n", " ],\n", - " \"model\": \"gpt-4o\"\n", - " },\n", - " \"assistant_tool_response\": {\n", - " \"content\": \"The contents of the file 123.txt are: \\\"The purpose of life is to be happy.\\\" If you need any further assistance or information, feel free to ask!\",\n", - " \"refusal\": null,\n", - " \"role\": \"assistant\",\n", - " \"function_call\": null,\n", - " \"tool_calls\": null\n", + " \"response_format\": {\n", + " \"type\": \"text\"\n", + " }\n", " }\n", " }\n", "}\n" @@ -565,9 +577,18 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "User: /echo(\"hello world\")\n", + "Assistant: hello world\n" + ] + } + ], "source": [ "from typing import Any\n", "from chat_driver import ChatDriverConfig, ChatDriver\n", @@ -586,7 +607,7 @@ " return f\"{context.session_id}: {name} erased\"\n", "\n", "\n", - "def echo(context: Context, value: Any) -> str:\n", + "def echo(context: Context, value: Any) -> str: # noqa: F811\n", " \"\"\"Echos a value as a string.\"\"\"\n", " match value:\n", " case str():\n", diff --git a/libraries/python/skills/notebooks/uv.lock b/libraries/python/skills/notebooks/uv.lock index ee75007c..2d936f1f 100644 --- a/libraries/python/skills/notebooks/uv.lock +++ b/libraries/python/skills/notebooks/uv.lock @@ -1718,6 +1718,7 @@ name = "skill-library" version = "0.1.0" source = { editable = "../skill-library" } dependencies = [ + { name = "assistant-drive" }, { name = "chat-driver" }, { name = "context" }, { name = "events" }, @@ -1732,6 +1733,7 @@ dependencies = [ [package.metadata] requires-dist = [ + { name = "assistant-drive", editable = "../../assistant-drive" }, { name = "chat-driver", editable = "../../chat-driver" }, { name = "context", editable = "../../context" }, { name = "events", editable = "../../events" }, @@ -1744,6 +1746,13 @@ requires-dist = [ { name = "tiktoken", specifier = ">=0.7.0" }, ] +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.1" }, + { name = "pytest-asyncio", specifier = ">=0.23.8" }, + { name = "pytest-repeat", specifier = ">=0.9.3" }, +] + [[package]] name = "skill-notebooks" version = "0.1.0" diff --git a/libraries/python/skills/skill-library/skill_library/routine_runners/instruction_routine_runner.py b/libraries/python/skills/skill-library/skill_library/routine_runners/instruction_routine_runner.py index 49aa53dd..09a366fc 100644 --- a/libraries/python/skills/skill-library/skill_library/routine_runners/instruction_routine_runner.py +++ b/libraries/python/skills/skill-library/skill_library/routine_runners/instruction_routine_runner.py @@ -10,9 +10,7 @@ class InstructionRoutineRunner: def __init__(self) -> None: pass - async def run( - self, context: RunContext, routine: InstructionRoutine, vars: dict[str, Any] | None = None - ) -> Any: + async def run(self, context: RunContext, routine: InstructionRoutine, vars: dict[str, Any] | None = None) -> Any: """ Run an Instruction routine. This just runs through the steps of a routine, sending each one to a skill's response endpoint. Note, this diff --git a/libraries/python/skills/skill-library/skill_library/run_context.py b/libraries/python/skills/skill-library/skill_library/run_context.py index f407ff10..e8e7e390 100644 --- a/libraries/python/skills/skill-library/skill_library/run_context.py +++ b/libraries/python/skills/skill-library/skill_library/run_context.py @@ -24,9 +24,7 @@ def __init__( session_id: str, assistant_drive: Drive, emit: Callable[[EventProtocol], None], - run_routine: Callable[ - ["RunContext", str, Optional[dict[str, Any]]], Coroutine[Any, Any, Any] - ], + run_routine: Callable[["RunContext", str, Optional[dict[str, Any]]], Coroutine[Any, Any, Any]], drive_root: PathLike | None = None, ) -> None: # A session id is useful for maintaining consistent session state across all @@ -48,7 +46,7 @@ def __init__( # The emit function is used to send events to the event bus. The component # that creates this context object will be responsible for instantiating an # event bus and handling the events sent to it with this function. - self.emit = emit + self.emit = emit or LogEmitter().emit # A metadrive to be used for managing assistant metadata. This can be # useful for storing session data, logs, and other information that diff --git a/libraries/python/skills/skill-library/skill_library/skill.py b/libraries/python/skills/skill-library/skill_library/skill.py index ac6283cc..b1e312fb 100644 --- a/libraries/python/skills/skill-library/skill_library/skill.py +++ b/libraries/python/skills/skill-library/skill_library/skill.py @@ -1,6 +1,6 @@ from typing import Any, Callable -from chat_driver import TEXT_RESPONSE_FORMAT, ChatDriver, ChatDriverConfig +from chat_driver import TEXT_RESPONSE_FORMAT, ChatDriver, ChatDriverConfig, ContextProtocol from events import BaseEvent from function_registry import FunctionRegistry from openai.types.chat.completion_create_params import ResponseFormat @@ -18,6 +18,7 @@ def __init__( self, name: str, description: str, + context: ContextProtocol, chat_driver_config: ChatDriverConfig | None = None, skill_actions: list[Callable] = [], # Functions to be registered as skill actions. routines: list[RoutineTypes] = [], @@ -45,7 +46,7 @@ def __init__( self.openai_client = chat_driver_config.openai_client if chat_driver_config else None # Register all provided actions with the action registry. - self.action_registry = FunctionRegistry(skill_actions) + self.action_registry = FunctionRegistry(context, skill_actions) # Also, register any commands provided by the chat driver. All # commands will be available to the skill. diff --git a/libraries/python/skills/skill-library/skill_library/skill_registry.py b/libraries/python/skills/skill-library/skill_library/skill_registry.py index 01caeffd..d788989e 100644 --- a/libraries/python/skills/skill-library/skill_library/skill_registry.py +++ b/libraries/python/skills/skill-library/skill_library/skill_registry.py @@ -95,9 +95,7 @@ def get_routine(self, routine_name: str) -> RoutineTypes | None: return None return skill.get_routine(routine) - async def run_routine_by_name( - self, context: RunContext, name: str, vars: dict[str, Any] | None = None - ) -> Any: + async def run_routine_by_name(self, context: RunContext, name: str, vars: dict[str, Any] | None = None) -> Any: """ Run an assistant routine by name (.). """ @@ -107,9 +105,7 @@ async def run_routine_by_name( response = await self.run_routine(context, routine, vars) return response - async def run_routine( - self, context: RunContext, routine: RoutineTypes, vars: dict[str, Any] | None = None - ) -> Any: + async def run_routine(self, context: RunContext, routine: RoutineTypes, vars: dict[str, Any] | None = None) -> Any: """ Run an assistant routine. This is going to be much of the magic of the assistant. Currently, is just runs through the diff --git a/libraries/python/skills/skill-library/uv.lock b/libraries/python/skills/skill-library/uv.lock index f5883a95..04f4a194 100644 --- a/libraries/python/skills/skill-library/uv.lock +++ b/libraries/python/skills/skill-library/uv.lock @@ -6,12 +6,85 @@ resolution-markers = [ ] [[package]] -name = "aiofiles" -version = "24.1.0" +name = "aiohappyeyeballs" +version = "2.4.3" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/03/a88171e277e8caa88a4c77808c20ebb04ba74cc4681bf1e9416c862de237/aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c", size = 30247 } +sdist = { url = "https://files.pythonhosted.org/packages/bc/69/2f6d5a019bd02e920a3417689a89887b39ad1e350b562f9955693d900c40/aiohappyeyeballs-2.4.3.tar.gz", hash = "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586", size = 21809 } wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5", size = 15896 }, + { url = "https://files.pythonhosted.org/packages/f7/d8/120cd0fe3e8530df0539e71ba9683eade12cae103dd7543e50d15f737917/aiohappyeyeballs-2.4.3-py3-none-any.whl", hash = "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572", size = 14742 }, +] + +[[package]] +name = "aiohttp" +version = "3.10.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/17/7e/16e57e6cf20eb62481a2f9ce8674328407187950ccc602ad07c685279141/aiohttp-3.10.10.tar.gz", hash = "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a", size = 7542993 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/31/3c351d17596194e5a38ef169a4da76458952b2497b4b54645b9d483cbbb0/aiohttp-3.10.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c30a0eafc89d28e7f959281b58198a9fa5e99405f716c0289b7892ca345fe45f", size = 586501 }, + { url = "https://files.pythonhosted.org/packages/a4/a8/a559d09eb08478cdead6b7ce05b0c4a133ba27fcdfa91e05d2e62867300d/aiohttp-3.10.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:258c5dd01afc10015866114e210fb7365f0d02d9d059c3c3415382ab633fcbcb", size = 398993 }, + { url = "https://files.pythonhosted.org/packages/c5/47/7736d4174613feef61d25332c3bd1a4f8ff5591fbd7331988238a7299485/aiohttp-3.10.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:15ecd889a709b0080f02721255b3f80bb261c2293d3c748151274dfea93ac871", size = 390647 }, + { url = "https://files.pythonhosted.org/packages/27/21/e9ba192a04b7160f5a8952c98a1de7cf8072ad150fa3abd454ead1ab1d7f/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3935f82f6f4a3820270842e90456ebad3af15810cf65932bd24da4463bc0a4c", size = 1306481 }, + { url = "https://files.pythonhosted.org/packages/cf/50/f364c01c8d0def1dc34747b2470969e216f5a37c7ece00fe558810f37013/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:413251f6fcf552a33c981c4709a6bba37b12710982fec8e558ae944bfb2abd38", size = 1344652 }, + { url = "https://files.pythonhosted.org/packages/1d/c2/74f608e984e9b585649e2e83883facad6fa3fc1d021de87b20cc67e8e5ae/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1720b4f14c78a3089562b8875b53e36b51c97c51adc53325a69b79b4b48ebcb", size = 1378498 }, + { url = "https://files.pythonhosted.org/packages/9f/a7/05a48c7c0a7a80a5591b1203bf1b64ca2ed6a2050af918d09c05852dc42b/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:679abe5d3858b33c2cf74faec299fda60ea9de62916e8b67e625d65bf069a3b7", size = 1292718 }, + { url = "https://files.pythonhosted.org/packages/7d/78/a925655018747e9790350180330032e27d6e0d7ed30bde545fae42f8c49c/aiohttp-3.10.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79019094f87c9fb44f8d769e41dbb664d6e8fcfd62f665ccce36762deaa0e911", size = 1251776 }, + { url = "https://files.pythonhosted.org/packages/47/9d/85c6b69f702351d1236594745a4fdc042fc43f494c247a98dac17e004026/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe2fb38c2ed905a2582948e2de560675e9dfbee94c6d5ccdb1301c6d0a5bf092", size = 1271716 }, + { url = "https://files.pythonhosted.org/packages/7f/a7/55fc805ff9b14af818903882ece08e2235b12b73b867b521b92994c52b14/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a3f00003de6eba42d6e94fabb4125600d6e484846dbf90ea8e48a800430cc142", size = 1266263 }, + { url = "https://files.pythonhosted.org/packages/1f/ec/d2be2ca7b063e4f91519d550dbc9c1cb43040174a322470deed90b3d3333/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1bbb122c557a16fafc10354b9d99ebf2f2808a660d78202f10ba9d50786384b9", size = 1321617 }, + { url = "https://files.pythonhosted.org/packages/c9/a3/b29f7920e1cd0a9a68a45dd3eb16140074d2efb1518d2e1f3e140357dc37/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:30ca7c3b94708a9d7ae76ff281b2f47d8eaf2579cd05971b5dc681db8caac6e1", size = 1339227 }, + { url = "https://files.pythonhosted.org/packages/8a/81/34b67235c47e232d807b4bbc42ba9b927c7ce9476872372fddcfd1e41b3d/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:df9270660711670e68803107d55c2b5949c2e0f2e4896da176e1ecfc068b974a", size = 1299068 }, + { url = "https://files.pythonhosted.org/packages/04/1f/26a7fe11b6ad3184f214733428353c89ae9fe3e4f605a657f5245c5e720c/aiohttp-3.10.10-cp311-cp311-win32.whl", hash = "sha256:aafc8ee9b742ce75044ae9a4d3e60e3d918d15a4c2e08a6c3c3e38fa59b92d94", size = 362223 }, + { url = "https://files.pythonhosted.org/packages/10/91/85dcd93f64011434359ce2666bece981f08d31bc49df33261e625b28595d/aiohttp-3.10.10-cp311-cp311-win_amd64.whl", hash = "sha256:362f641f9071e5f3ee6f8e7d37d5ed0d95aae656adf4ef578313ee585b585959", size = 381576 }, + { url = "https://files.pythonhosted.org/packages/ae/99/4c5aefe5ad06a1baf206aed6598c7cdcbc7c044c46801cd0d1ecb758cae3/aiohttp-3.10.10-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9294bbb581f92770e6ed5c19559e1e99255e4ca604a22c5c6397b2f9dd3ee42c", size = 583536 }, + { url = "https://files.pythonhosted.org/packages/a9/36/8b3bc49b49cb6d2da40ee61ff15dbcc44fd345a3e6ab5bb20844df929821/aiohttp-3.10.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a8fa23fe62c436ccf23ff930149c047f060c7126eae3ccea005f0483f27b2e28", size = 395693 }, + { url = "https://files.pythonhosted.org/packages/e1/77/0aa8660dcf11fa65d61712dbb458c4989de220a844bd69778dff25f2d50b/aiohttp-3.10.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c6a5b8c7926ba5d8545c7dd22961a107526562da31a7a32fa2456baf040939f", size = 390898 }, + { url = "https://files.pythonhosted.org/packages/38/d2/b833d95deb48c75db85bf6646de0a697e7fb5d87bd27cbade4f9746b48b1/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:007ec22fbc573e5eb2fb7dec4198ef8f6bf2fe4ce20020798b2eb5d0abda6138", size = 1312060 }, + { url = "https://files.pythonhosted.org/packages/aa/5f/29fd5113165a0893de8efedf9b4737e0ba92dfcd791415a528f947d10299/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9627cc1a10c8c409b5822a92d57a77f383b554463d1884008e051c32ab1b3742", size = 1350553 }, + { url = "https://files.pythonhosted.org/packages/ad/cc/f835f74b7d344428469200105236d44606cfa448be1e7c95ca52880d9bac/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:50edbcad60d8f0e3eccc68da67f37268b5144ecc34d59f27a02f9611c1d4eec7", size = 1392646 }, + { url = "https://files.pythonhosted.org/packages/bf/fe/1332409d845ca601893bbf2d76935e0b93d41686e5f333841c7d7a4a770d/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a45d85cf20b5e0d0aa5a8dca27cce8eddef3292bc29d72dcad1641f4ed50aa16", size = 1306310 }, + { url = "https://files.pythonhosted.org/packages/e4/a1/25a7633a5a513278a9892e333501e2e69c83e50be4b57a62285fb7a008c3/aiohttp-3.10.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b00807e2605f16e1e198f33a53ce3c4523114059b0c09c337209ae55e3823a8", size = 1260255 }, + { url = "https://files.pythonhosted.org/packages/f2/39/30eafe89e0e2a06c25e4762844c8214c0c0cd0fd9ffc3471694a7986f421/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f2d4324a98062be0525d16f768a03e0bbb3b9fe301ceee99611dc9a7953124e6", size = 1271141 }, + { url = "https://files.pythonhosted.org/packages/5b/fc/33125df728b48391ef1fcb512dfb02072158cc10d041414fb79803463020/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:438cd072f75bb6612f2aca29f8bd7cdf6e35e8f160bc312e49fbecab77c99e3a", size = 1280244 }, + { url = "https://files.pythonhosted.org/packages/3b/61/e42bf2c2934b5caa4e2ec0b5e5fd86989adb022b5ee60c2572a9d77cf6fe/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:baa42524a82f75303f714108fea528ccacf0386af429b69fff141ffef1c534f9", size = 1316805 }, + { url = "https://files.pythonhosted.org/packages/18/32/f52a5e2ae9ad3bba10e026a63a7a23abfa37c7d97aeeb9004eaa98df3ce3/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a7d8d14fe962153fc681f6366bdec33d4356f98a3e3567782aac1b6e0e40109a", size = 1343930 }, + { url = "https://files.pythonhosted.org/packages/05/be/6a403b464dcab3631fe8e27b0f1d906d9e45c5e92aca97ee007e5a895560/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205", size = 1306186 }, + { url = "https://files.pythonhosted.org/packages/8e/fd/bb50fe781068a736a02bf5c7ad5f3ab53e39f1d1e63110da6d30f7605edc/aiohttp-3.10.10-cp312-cp312-win32.whl", hash = "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628", size = 359289 }, + { url = "https://files.pythonhosted.org/packages/70/9e/5add7e240f77ef67c275c82cc1d08afbca57b77593118c1f6e920ae8ad3f/aiohttp-3.10.10-cp312-cp312-win_amd64.whl", hash = "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf", size = 379313 }, + { url = "https://files.pythonhosted.org/packages/b1/eb/618b1b76c7fe8082a71c9d62e3fe84c5b9af6703078caa9ec57850a12080/aiohttp-3.10.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28", size = 576114 }, + { url = "https://files.pythonhosted.org/packages/aa/37/3126995d7869f8b30d05381b81a2d4fb4ec6ad313db788e009bc6d39c211/aiohttp-3.10.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d", size = 391901 }, + { url = "https://files.pythonhosted.org/packages/3e/f2/8fdfc845be1f811c31ceb797968523813f8e1263ee3e9120d61253f6848f/aiohttp-3.10.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79", size = 387418 }, + { url = "https://files.pythonhosted.org/packages/60/d5/33d2061d36bf07e80286e04b7e0a4de37ce04b5ebfed72dba67659a05250/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e", size = 1287073 }, + { url = "https://files.pythonhosted.org/packages/00/52/affb55be16a4747740bd630b4c002dac6c5eac42f9bb64202fc3cf3f1930/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6", size = 1323612 }, + { url = "https://files.pythonhosted.org/packages/94/f2/cddb69b975387daa2182a8442566971d6410b8a0179bb4540d81c97b1611/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42", size = 1368406 }, + { url = "https://files.pythonhosted.org/packages/c1/e4/afba7327da4d932da8c6e29aecaf855f9d52dace53ac15bfc8030a246f1b/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e", size = 1282761 }, + { url = "https://files.pythonhosted.org/packages/9f/6b/364856faa0c9031ea76e24ef0f7fef79cddd9fa8e7dba9a1771c6acc56b5/aiohttp-3.10.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc", size = 1236518 }, + { url = "https://files.pythonhosted.org/packages/46/af/c382846f8356fe64a7b5908bb9b477457aa23b71be7ed551013b7b7d4d87/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a", size = 1250344 }, + { url = "https://files.pythonhosted.org/packages/87/53/294f87fc086fd0772d0ab82497beb9df67f0f27a8b3dd5742a2656db2bc6/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414", size = 1248956 }, + { url = "https://files.pythonhosted.org/packages/86/30/7d746717fe11bdfefb88bb6c09c5fc985d85c4632da8bb6018e273899254/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3", size = 1293379 }, + { url = "https://files.pythonhosted.org/packages/48/b9/45d670a834458db67a24258e9139ba61fa3bd7d69b98ecf3650c22806f8f/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67", size = 1320108 }, + { url = "https://files.pythonhosted.org/packages/72/8c/804bb2e837a175635d2000a0659eafc15b2e9d92d3d81c8f69e141ecd0b0/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b", size = 1281546 }, + { url = "https://files.pythonhosted.org/packages/89/c0/862e6a9de3d6eeb126cd9d9ea388243b70df9b871ce1a42b193b7a4a77fc/aiohttp-3.10.10-cp313-cp313-win32.whl", hash = "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8", size = 357516 }, + { url = "https://files.pythonhosted.org/packages/ae/63/3e1aee3e554263f3f1011cca50d78a4894ae16ce99bf78101ac3a2f0ef74/aiohttp-3.10.10-cp313-cp313-win_amd64.whl", hash = "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151", size = 376785 }, +] + +[[package]] +name = "aiosignal" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/67/0952ed97a9793b4958e5736f6d2b346b414a2cd63e82d05940032f45b32f/aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", size = 19422 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17", size = 7617 }, ] [[package]] @@ -25,15 +98,28 @@ wheels = [ [[package]] name = "anyio" -version = "4.6.0" +version = "4.6.2.post1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "sniffio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/78/49/f3f17ec11c4a91fe79275c426658e509b07547f874b14c1a526d86a83fc8/anyio-4.6.0.tar.gz", hash = "sha256:137b4559cbb034c477165047febb6ff83f390fc3b20bf181c1fc0a728cb8beeb", size = 170983 } +sdist = { url = "https://files.pythonhosted.org/packages/9f/09/45b9b7a6d4e45c6bcb5bf61d19e3ab87df68e0601fa8c5293de3542546cc/anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c", size = 173422 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/ef/7a4f225581a0d7886ea28359179cb861d7fbcdefad29663fc1167b86f69f/anyio-4.6.0-py3-none-any.whl", hash = "sha256:c7d2e9d63e31599eeb636c8c5c03a7e108d73b345f064f1c19fdc87b79036a9a", size = 89631 }, + { url = "https://files.pythonhosted.org/packages/e4/f5/f2b75d2fc6f1a260f340f0e7c6a060f4dd2961cc16884ed851b0d18da06a/anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d", size = 90377 }, +] + +[[package]] +name = "asgi-correlation-id" +version = "4.3.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "starlette" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f4/ff/a6538245ac1eaa7733ec6740774e9d5add019e2c63caa29e758c16c0afdd/asgi_correlation_id-4.3.4.tar.gz", hash = "sha256:ea6bc310380373cb9f731dc2e8b2b6fb978a76afe33f7a2384f697b8d6cd811d", size = 20075 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/ab/6936e2663c47a926e0659437b9333ad87d1ff49b1375d239026e0a268eba/asgi_correlation_id-4.3.4-py3-none-any.whl", hash = "sha256:36ce69b06c7d96b4acb89c7556a4c4f01a972463d3d49c675026cbbd08e9a0a2", size = 15262 }, ] [[package]] @@ -41,7 +127,6 @@ name = "assistant-drive" version = "0.1.0" source = { editable = "../../assistant-drive" } dependencies = [ - { name = "aiofiles" }, { name = "context" }, { name = "pydantic" }, { name = "pydantic-settings" }, @@ -49,7 +134,6 @@ dependencies = [ [package.metadata] requires-dist = [ - { name = "aiofiles", specifier = ">=24.1.0" }, { name = "context", editable = "../../context" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.5.2" }, @@ -63,18 +147,40 @@ dev = [ { name = "pytest-repeat", specifier = ">=0.9.3" }, ] +[[package]] +name = "attrs" +version = "24.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/0f/aafca9af9315aee06a89ffde799a10a582fe8de76c563ee80bbcdc08b3fb/attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", size = 792678 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2", size = 63001 }, +] + +[[package]] +name = "azure-ai-contentsafety" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "azure-core" }, + { name = "isodate" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/08/e9/c069efade0e4976d96208306f1cf0803838cdb0b60e00a2a96bd20806bff/azure-ai-contentsafety-1.0.0.tar.gz", hash = "sha256:052731bd1419a720fa00910f46bf3428c4e5bd05280da7393d0c8106d46cc6d7", size = 63806 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/39/cbb3ff28ad09434a1be7803b2846077bc3b23a8232beb489962fc818fe21/azure_ai_contentsafety-1.0.0-py3-none-any.whl", hash = "sha256:e1c5574a541f9290fdd071d23535e14b1f463af231a6f0ac0f917e125f0463cf", size = 61328 }, +] + [[package]] name = "azure-core" -version = "1.31.0" +version = "1.32.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, { name = "six" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/03/7a/f79ad135a276a37e61168495697c14ba1721a52c3eab4dae2941929c79f8/azure_core-1.31.0.tar.gz", hash = "sha256:656a0dd61e1869b1506b7c6a3b31d62f15984b1a573d6326f6aa2f3e4123284b", size = 277147 } +sdist = { url = "https://files.pythonhosted.org/packages/cc/ee/668328306a9e963a5ad9f152cd98c7adad86c822729fd1d2a01613ad1e67/azure_core-1.32.0.tar.gz", hash = "sha256:22b3c35d6b2dae14990f6c1be2912bf23ffe50b220e708a28ab1bb92b1c730e5", size = 279128 } wheels = [ - { url = "https://files.pythonhosted.org/packages/01/8e/fcb6a77d3029d2a7356f38dbc77cf7daa113b81ddab76b5593d23321e44c/azure_core-1.31.0-py3-none-any.whl", hash = "sha256:22954de3777e0250029360ef31d80448ef1be13b80a459bff80ba7073379e2cd", size = 197399 }, + { url = "https://files.pythonhosted.org/packages/39/83/325bf5e02504dbd8b4faa98197a44cdf8a325ef259b48326a2b6f17f8383/azure_core-1.32.0-py3-none-any.whl", hash = "sha256:eac191a0efb23bfa83fddf321b27b122b4ec847befa3091fa736a5c32c50d7b4", size = 198855 }, ] [package.optional-dependencies] @@ -84,7 +190,7 @@ aio = [ [[package]] name = "azure-identity" -version = "1.18.0" +version = "1.19.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "azure-core" }, @@ -93,9 +199,9 @@ dependencies = [ { name = "msal-extensions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b3/5d/1c7da35dd640b4a95a38f980bb6b0b56c4e91d5b3d518ac11a2c4ebf5f62/azure_identity-1.18.0.tar.gz", hash = "sha256:f567579a65d8932fa913c76eddf3305101a15e5727a5e4aa5df649a0f553d4c3", size = 263322 } +sdist = { url = "https://files.pythonhosted.org/packages/aa/91/cbaeff9eb0b838f0d35b4607ac1c6195c735c8eb17db235f8f60e622934c/azure_identity-1.19.0.tar.gz", hash = "sha256:500144dc18197d7019b81501165d4fa92225f03778f17d7ca8a2a180129a9c83", size = 263058 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/71/1d1bb387b6acaa5daa3e703c70dde3d54823ccd229bd6730de6e724f296e/azure_identity-1.18.0-py3-none-any.whl", hash = "sha256:bccf6106245b49ff41d0c4cd7b72851c5a2ba3a32cef7589da246f5727f26f02", size = 187179 }, + { url = "https://files.pythonhosted.org/packages/f0/d5/3995ed12f941f4a41a273d9b1709282e825ef87ed8eab3833038fee54d59/azure_identity-1.19.0-py3-none-any.whl", hash = "sha256:e3f6558c181692d7509f09de10cca527c7dce426776454fb97df512a46527e81", size = 187587 }, ] [[package]] @@ -163,41 +269,56 @@ wheels = [ [[package]] name = "charset-normalizer" -version = "3.3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/63/09/c1bc53dab74b1816a00d8d030de5bf98f724c52c1635e07681d312f20be8/charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", size = 104809 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/77/02839016f6fbbf808e8b38601df6e0e66c17bbab76dff4613f7511413597/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", size = 191647 }, - { url = "https://files.pythonhosted.org/packages/3e/33/21a875a61057165e92227466e54ee076b73af1e21fe1b31f1e292251aa1e/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", size = 121434 }, - { url = "https://files.pythonhosted.org/packages/dd/51/68b61b90b24ca35495956b718f35a9756ef7d3dd4b3c1508056fa98d1a1b/charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", size = 118979 }, - { url = "https://files.pythonhosted.org/packages/e4/a6/7ee57823d46331ddc37dd00749c95b0edec2c79b15fc0d6e6efb532e89ac/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", size = 136582 }, - { url = "https://files.pythonhosted.org/packages/74/f1/0d9fe69ac441467b737ba7f48c68241487df2f4522dd7246d9426e7c690e/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", size = 146645 }, - { url = "https://files.pythonhosted.org/packages/05/31/e1f51c76db7be1d4aef220d29fbfa5dbb4a99165d9833dcbf166753b6dc0/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", size = 139398 }, - { url = "https://files.pythonhosted.org/packages/40/26/f35951c45070edc957ba40a5b1db3cf60a9dbb1b350c2d5bef03e01e61de/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", size = 140273 }, - { url = "https://files.pythonhosted.org/packages/07/07/7e554f2bbce3295e191f7e653ff15d55309a9ca40d0362fcdab36f01063c/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", size = 142577 }, - { url = "https://files.pythonhosted.org/packages/d8/b5/eb705c313100defa57da79277d9207dc8d8e45931035862fa64b625bfead/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", size = 137747 }, - { url = "https://files.pythonhosted.org/packages/19/28/573147271fd041d351b438a5665be8223f1dd92f273713cb882ddafe214c/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", size = 143375 }, - { url = "https://files.pythonhosted.org/packages/cf/7c/f3b682fa053cc21373c9a839e6beba7705857075686a05c72e0f8c4980ca/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", size = 148474 }, - { url = "https://files.pythonhosted.org/packages/1e/49/7ab74d4ac537ece3bc3334ee08645e231f39f7d6df6347b29a74b0537103/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", size = 140232 }, - { url = "https://files.pythonhosted.org/packages/2d/dc/9dacba68c9ac0ae781d40e1a0c0058e26302ea0660e574ddf6797a0347f7/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", size = 140859 }, - { url = "https://files.pythonhosted.org/packages/6c/c2/4a583f800c0708dd22096298e49f887b49d9746d0e78bfc1d7e29816614c/charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", size = 92509 }, - { url = "https://files.pythonhosted.org/packages/57/ec/80c8d48ac8b1741d5b963797b7c0c869335619e13d4744ca2f67fc11c6fc/charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", size = 99870 }, - { url = "https://files.pythonhosted.org/packages/d1/b2/fcedc8255ec42afee97f9e6f0145c734bbe104aac28300214593eb326f1d/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", size = 192892 }, - { url = "https://files.pythonhosted.org/packages/2e/7d/2259318c202f3d17f3fe6438149b3b9e706d1070fe3fcbb28049730bb25c/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", size = 122213 }, - { url = "https://files.pythonhosted.org/packages/3a/52/9f9d17c3b54dc238de384c4cb5a2ef0e27985b42a0e5cc8e8a31d918d48d/charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", size = 119404 }, - { url = "https://files.pythonhosted.org/packages/99/b0/9c365f6d79a9f0f3c379ddb40a256a67aa69c59609608fe7feb6235896e1/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", size = 137275 }, - { url = "https://files.pythonhosted.org/packages/91/33/749df346e93d7a30cdcb90cbfdd41a06026317bfbfb62cd68307c1a3c543/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", size = 147518 }, - { url = "https://files.pythonhosted.org/packages/72/1a/641d5c9f59e6af4c7b53da463d07600a695b9824e20849cb6eea8a627761/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", size = 140182 }, - { url = "https://files.pythonhosted.org/packages/ee/fb/14d30eb4956408ee3ae09ad34299131fb383c47df355ddb428a7331cfa1e/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", size = 141869 }, - { url = "https://files.pythonhosted.org/packages/df/3e/a06b18788ca2eb6695c9b22325b6fde7dde0f1d1838b1792a0076f58fe9d/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", size = 144042 }, - { url = "https://files.pythonhosted.org/packages/45/59/3d27019d3b447a88fe7e7d004a1e04be220227760264cc41b405e863891b/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", size = 138275 }, - { url = "https://files.pythonhosted.org/packages/7b/ef/5eb105530b4da8ae37d506ccfa25057961b7b63d581def6f99165ea89c7e/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", size = 144819 }, - { url = "https://files.pythonhosted.org/packages/a2/51/e5023f937d7f307c948ed3e5c29c4b7a3e42ed2ee0b8cdf8f3a706089bf0/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", size = 149415 }, - { url = "https://files.pythonhosted.org/packages/24/9d/2e3ef673dfd5be0154b20363c5cdcc5606f35666544381bee15af3778239/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", size = 141212 }, - { url = "https://files.pythonhosted.org/packages/5b/ae/ce2c12fcac59cb3860b2e2d76dc405253a4475436b1861d95fe75bdea520/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", size = 142167 }, - { url = "https://files.pythonhosted.org/packages/ed/3a/a448bf035dce5da359daf9ae8a16b8a39623cc395a2ffb1620aa1bce62b0/charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", size = 93041 }, - { url = "https://files.pythonhosted.org/packages/b6/7c/8debebb4f90174074b827c63242c23851bdf00a532489fba57fef3416e40/charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", size = 100397 }, - { url = "https://files.pythonhosted.org/packages/28/76/e6222113b83e3622caa4bb41032d0b1bf785250607392e1b778aca0b8a7d/charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", size = 48543 }, +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/4f/e1808dc01273379acc506d18f1504eb2d299bd4131743b9fc54d7be4df1e/charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", size = 106620 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/61/73589dcc7a719582bf56aae309b6103d2762b526bffe189d635a7fcfd998/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c", size = 193339 }, + { url = "https://files.pythonhosted.org/packages/77/d5/8c982d58144de49f59571f940e329ad6e8615e1e82ef84584c5eeb5e1d72/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944", size = 124366 }, + { url = "https://files.pythonhosted.org/packages/bf/19/411a64f01ee971bed3231111b69eb56f9331a769072de479eae7de52296d/charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee", size = 118874 }, + { url = "https://files.pythonhosted.org/packages/4c/92/97509850f0d00e9f14a46bc751daabd0ad7765cff29cdfb66c68b6dad57f/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c", size = 138243 }, + { url = "https://files.pythonhosted.org/packages/e2/29/d227805bff72ed6d6cb1ce08eec707f7cfbd9868044893617eb331f16295/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6", size = 148676 }, + { url = "https://files.pythonhosted.org/packages/13/bc/87c2c9f2c144bedfa62f894c3007cd4530ba4b5351acb10dc786428a50f0/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea", size = 141289 }, + { url = "https://files.pythonhosted.org/packages/eb/5b/6f10bad0f6461fa272bfbbdf5d0023b5fb9bc6217c92bf068fa5a99820f5/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc", size = 142585 }, + { url = "https://files.pythonhosted.org/packages/3b/a0/a68980ab8a1f45a36d9745d35049c1af57d27255eff8c907e3add84cf68f/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5", size = 144408 }, + { url = "https://files.pythonhosted.org/packages/d7/a1/493919799446464ed0299c8eef3c3fad0daf1c3cd48bff9263c731b0d9e2/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594", size = 139076 }, + { url = "https://files.pythonhosted.org/packages/fb/9d/9c13753a5a6e0db4a0a6edb1cef7aee39859177b64e1a1e748a6e3ba62c2/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c", size = 146874 }, + { url = "https://files.pythonhosted.org/packages/75/d2/0ab54463d3410709c09266dfb416d032a08f97fd7d60e94b8c6ef54ae14b/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365", size = 150871 }, + { url = "https://files.pythonhosted.org/packages/8d/c9/27e41d481557be53d51e60750b85aa40eaf52b841946b3cdeff363105737/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129", size = 148546 }, + { url = "https://files.pythonhosted.org/packages/ee/44/4f62042ca8cdc0cabf87c0fc00ae27cd8b53ab68be3605ba6d071f742ad3/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236", size = 143048 }, + { url = "https://files.pythonhosted.org/packages/01/f8/38842422988b795220eb8038745d27a675ce066e2ada79516c118f291f07/charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99", size = 94389 }, + { url = "https://files.pythonhosted.org/packages/0b/6e/b13bd47fa9023b3699e94abf565b5a2f0b0be6e9ddac9812182596ee62e4/charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27", size = 101752 }, + { url = "https://files.pythonhosted.org/packages/d3/0b/4b7a70987abf9b8196845806198975b6aab4ce016632f817ad758a5aa056/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6", size = 194445 }, + { url = "https://files.pythonhosted.org/packages/50/89/354cc56cf4dd2449715bc9a0f54f3aef3dc700d2d62d1fa5bbea53b13426/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf", size = 125275 }, + { url = "https://files.pythonhosted.org/packages/fa/44/b730e2a2580110ced837ac083d8ad222343c96bb6b66e9e4e706e4d0b6df/charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db", size = 119020 }, + { url = "https://files.pythonhosted.org/packages/9d/e4/9263b8240ed9472a2ae7ddc3e516e71ef46617fe40eaa51221ccd4ad9a27/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1", size = 139128 }, + { url = "https://files.pythonhosted.org/packages/6b/e3/9f73e779315a54334240353eaea75854a9a690f3f580e4bd85d977cb2204/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03", size = 149277 }, + { url = "https://files.pythonhosted.org/packages/1a/cf/f1f50c2f295312edb8a548d3fa56a5c923b146cd3f24114d5adb7e7be558/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284", size = 142174 }, + { url = "https://files.pythonhosted.org/packages/16/92/92a76dc2ff3a12e69ba94e7e05168d37d0345fa08c87e1fe24d0c2a42223/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15", size = 143838 }, + { url = "https://files.pythonhosted.org/packages/a4/01/2117ff2b1dfc61695daf2babe4a874bca328489afa85952440b59819e9d7/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8", size = 146149 }, + { url = "https://files.pythonhosted.org/packages/f6/9b/93a332b8d25b347f6839ca0a61b7f0287b0930216994e8bf67a75d050255/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2", size = 140043 }, + { url = "https://files.pythonhosted.org/packages/ab/f6/7ac4a01adcdecbc7a7587767c776d53d369b8b971382b91211489535acf0/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719", size = 148229 }, + { url = "https://files.pythonhosted.org/packages/9d/be/5708ad18161dee7dc6a0f7e6cf3a88ea6279c3e8484844c0590e50e803ef/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631", size = 151556 }, + { url = "https://files.pythonhosted.org/packages/5a/bb/3d8bc22bacb9eb89785e83e6723f9888265f3a0de3b9ce724d66bd49884e/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b", size = 149772 }, + { url = "https://files.pythonhosted.org/packages/f7/fa/d3fc622de05a86f30beea5fc4e9ac46aead4731e73fd9055496732bcc0a4/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", size = 144800 }, + { url = "https://files.pythonhosted.org/packages/9a/65/bdb9bc496d7d190d725e96816e20e2ae3a6fa42a5cac99c3c3d6ff884118/charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", size = 94836 }, + { url = "https://files.pythonhosted.org/packages/3e/67/7b72b69d25b89c0b3cea583ee372c43aa24df15f0e0f8d3982c57804984b/charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", size = 102187 }, + { url = "https://files.pythonhosted.org/packages/f3/89/68a4c86f1a0002810a27f12e9a7b22feb198c59b2f05231349fbce5c06f4/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", size = 194617 }, + { url = "https://files.pythonhosted.org/packages/4f/cd/8947fe425e2ab0aa57aceb7807af13a0e4162cd21eee42ef5b053447edf5/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", size = 125310 }, + { url = "https://files.pythonhosted.org/packages/5b/f0/b5263e8668a4ee9becc2b451ed909e9c27058337fda5b8c49588183c267a/charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", size = 119126 }, + { url = "https://files.pythonhosted.org/packages/ff/6e/e445afe4f7fda27a533f3234b627b3e515a1b9429bc981c9a5e2aa5d97b6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", size = 139342 }, + { url = "https://files.pythonhosted.org/packages/a1/b2/4af9993b532d93270538ad4926c8e37dc29f2111c36f9c629840c57cd9b3/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", size = 149383 }, + { url = "https://files.pythonhosted.org/packages/fb/6f/4e78c3b97686b871db9be6f31d64e9264e889f8c9d7ab33c771f847f79b7/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", size = 142214 }, + { url = "https://files.pythonhosted.org/packages/2b/c9/1c8fe3ce05d30c87eff498592c89015b19fade13df42850aafae09e94f35/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", size = 144104 }, + { url = "https://files.pythonhosted.org/packages/ee/68/efad5dcb306bf37db7db338338e7bb8ebd8cf38ee5bbd5ceaaaa46f257e6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", size = 146255 }, + { url = "https://files.pythonhosted.org/packages/0c/75/1ed813c3ffd200b1f3e71121c95da3f79e6d2a96120163443b3ad1057505/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", size = 140251 }, + { url = "https://files.pythonhosted.org/packages/7d/0d/6f32255c1979653b448d3c709583557a4d24ff97ac4f3a5be156b2e6a210/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", size = 148474 }, + { url = "https://files.pythonhosted.org/packages/ac/a0/c1b5298de4670d997101fef95b97ac440e8c8d8b4efa5a4d1ef44af82f0d/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", size = 151849 }, + { url = "https://files.pythonhosted.org/packages/04/4f/b3961ba0c664989ba63e30595a3ed0875d6790ff26671e2aae2fdc28a399/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", size = 149781 }, + { url = "https://files.pythonhosted.org/packages/d8/90/6af4cd042066a4adad58ae25648a12c09c879efa4849c705719ba1b23d8c/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482", size = 144970 }, + { url = "https://files.pythonhosted.org/packages/cc/67/e5e7e0cbfefc4ca79025238b43cdf8a2037854195b37d6417f3d0895c4c2/charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", size = 94973 }, + { url = "https://files.pythonhosted.org/packages/65/97/fc9bbc54ee13d33dc54a7fcf17b26368b18505500fc01e228c27b5222d80/charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", size = 102308 }, + { url = "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", size = 49446 }, ] [[package]] @@ -214,7 +335,6 @@ dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, - { name = "python-liquid" }, { name = "requests" }, { name = "tiktoken" }, ] @@ -230,7 +350,6 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "python-liquid", specifier = ">=1.12.1" }, { name = "requests", specifier = ">=2.32.0" }, { name = "tiktoken", specifier = ">=0.7.0" }, ] @@ -276,31 +395,31 @@ dev = [ [[package]] name = "cryptography" -version = "43.0.1" +version = "43.0.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/de/ba/0664727028b37e249e73879348cc46d45c5c1a2a2e81e8166462953c5755/cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d", size = 686927 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/28/b92c98a04ba762f8cdeb54eba5c4c84e63cac037a7c5e70117d337b15ad6/cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d", size = 6223222 }, - { url = "https://files.pythonhosted.org/packages/33/13/1193774705783ba364121aa2a60132fa31a668b8ababd5edfa1662354ccd/cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062", size = 3794751 }, - { url = "https://files.pythonhosted.org/packages/5e/4b/39bb3c4c8cfb3e94e736b8d8859ce5c81536e91a1033b1d26770c4249000/cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962", size = 3981827 }, - { url = "https://files.pythonhosted.org/packages/ce/dc/1471d4d56608e1013237af334b8a4c35d53895694fbb73882d1c4fd3f55e/cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277", size = 3780034 }, - { url = "https://files.pythonhosted.org/packages/ad/43/7a9920135b0d5437cc2f8f529fa757431eb6a7736ddfadfdee1cc5890800/cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a", size = 3993407 }, - { url = "https://files.pythonhosted.org/packages/cc/42/9ab8467af6c0b76f3d9b8f01d1cf25b9c9f3f2151f4acfab888d21c55a72/cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042", size = 3886457 }, - { url = "https://files.pythonhosted.org/packages/a4/65/430509e31700286ec02868a2457d2111d03ccefc20349d24e58d171ae0a7/cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494", size = 4081499 }, - { url = "https://files.pythonhosted.org/packages/bb/18/a04b6467e6e09df8c73b91dcee8878f4a438a43a3603dc3cd6f8003b92d8/cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2", size = 2616504 }, - { url = "https://files.pythonhosted.org/packages/cc/73/0eacbdc437202edcbdc07f3576ed8fb8b0ab79d27bf2c5d822d758a72faa/cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d", size = 3067456 }, - { url = "https://files.pythonhosted.org/packages/8a/b6/bc54b371f02cffd35ff8dc6baba88304d7cf8e83632566b4b42e00383e03/cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d", size = 6225263 }, - { url = "https://files.pythonhosted.org/packages/00/0e/8217e348a1fa417ec4c78cd3cdf24154f5e76fd7597343a35bd403650dfd/cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806", size = 3794368 }, - { url = "https://files.pythonhosted.org/packages/3d/ed/38b6be7254d8f7251fde8054af597ee8afa14f911da67a9410a45f602fc3/cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85", size = 3981750 }, - { url = "https://files.pythonhosted.org/packages/64/f3/b7946c3887cf7436f002f4cbb1e6aec77b8d299b86be48eeadfefb937c4b/cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c", size = 3778925 }, - { url = "https://files.pythonhosted.org/packages/ac/7e/ebda4dd4ae098a0990753efbb4b50954f1d03003846b943ea85070782da7/cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1", size = 3993152 }, - { url = "https://files.pythonhosted.org/packages/43/f6/feebbd78a3e341e3913846a3bb2c29d0b09b1b3af1573c6baabc2533e147/cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa", size = 3886392 }, - { url = "https://files.pythonhosted.org/packages/bd/4c/ab0b9407d5247576290b4fd8abd06b7f51bd414f04eef0f2800675512d61/cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4", size = 4082606 }, - { url = "https://files.pythonhosted.org/packages/05/36/e532a671998d6fcfdb9122da16434347a58a6bae9465e527e450e0bc60a5/cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47", size = 2617948 }, - { url = "https://files.pythonhosted.org/packages/b3/c6/c09cee6968add5ff868525c3815e5dccc0e3c6e89eec58dc9135d3c40e88/cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb", size = 3070445 }, +sdist = { url = "https://files.pythonhosted.org/packages/0d/05/07b55d1fa21ac18c3a8c79f764e2514e6f6a9698f1be44994f5adf0d29db/cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805", size = 686989 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/f3/01fdf26701a26f4b4dbc337a26883ad5bccaa6f1bbbdd29cd89e22f18a1c/cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e", size = 6225303 }, + { url = "https://files.pythonhosted.org/packages/a3/01/4896f3d1b392025d4fcbecf40fdea92d3df8662123f6835d0af828d148fd/cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e", size = 3760905 }, + { url = "https://files.pythonhosted.org/packages/0a/be/f9a1f673f0ed4b7f6c643164e513dbad28dd4f2dcdf5715004f172ef24b6/cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f", size = 3977271 }, + { url = "https://files.pythonhosted.org/packages/4e/49/80c3a7b5514d1b416d7350830e8c422a4d667b6d9b16a9392ebfd4a5388a/cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6", size = 3746606 }, + { url = "https://files.pythonhosted.org/packages/0e/16/a28ddf78ac6e7e3f25ebcef69ab15c2c6be5ff9743dd0709a69a4f968472/cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18", size = 3986484 }, + { url = "https://files.pythonhosted.org/packages/01/f5/69ae8da70c19864a32b0315049866c4d411cce423ec169993d0434218762/cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd", size = 3852131 }, + { url = "https://files.pythonhosted.org/packages/fd/db/e74911d95c040f9afd3612b1f732e52b3e517cb80de8bf183be0b7d413c6/cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73", size = 4075647 }, + { url = "https://files.pythonhosted.org/packages/56/48/7b6b190f1462818b324e674fa20d1d5ef3e24f2328675b9b16189cbf0b3c/cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2", size = 2623873 }, + { url = "https://files.pythonhosted.org/packages/eb/b1/0ebff61a004f7f89e7b65ca95f2f2375679d43d0290672f7713ee3162aff/cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd", size = 3068039 }, + { url = "https://files.pythonhosted.org/packages/30/d5/c8b32c047e2e81dd172138f772e81d852c51f0f2ad2ae8a24f1122e9e9a7/cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984", size = 6222984 }, + { url = "https://files.pythonhosted.org/packages/2f/78/55356eb9075d0be6e81b59f45c7b48df87f76a20e73893872170471f3ee8/cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5", size = 3762968 }, + { url = "https://files.pythonhosted.org/packages/2a/2c/488776a3dc843f95f86d2f957ca0fc3407d0242b50bede7fad1e339be03f/cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4", size = 3977754 }, + { url = "https://files.pythonhosted.org/packages/7c/04/2345ca92f7a22f601a9c62961741ef7dd0127c39f7310dffa0041c80f16f/cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7", size = 3749458 }, + { url = "https://files.pythonhosted.org/packages/ac/25/e715fa0bc24ac2114ed69da33adf451a38abb6f3f24ec207908112e9ba53/cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405", size = 3988220 }, + { url = "https://files.pythonhosted.org/packages/21/ce/b9c9ff56c7164d8e2edfb6c9305045fbc0df4508ccfdb13ee66eb8c95b0e/cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16", size = 3853898 }, + { url = "https://files.pythonhosted.org/packages/2a/33/b3682992ab2e9476b9c81fff22f02c8b0a1e6e1d49ee1750a67d85fd7ed2/cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73", size = 4076592 }, + { url = "https://files.pythonhosted.org/packages/81/1e/ffcc41b3cebd64ca90b28fd58141c5f68c83d48563c88333ab660e002cd3/cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995", size = 2623145 }, + { url = "https://files.pythonhosted.org/packages/87/5c/3dab83cc4aba1f4b0e733e3f0c3e7d4386440d660ba5b1e3ff995feb734d/cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362", size = 3068026 }, ] [[package]] @@ -578,36 +697,69 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, ] +[[package]] +name = "isodate" +version = "0.7.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/4d/e940025e2ce31a8ce1202635910747e5a87cc3a6a6bb2d00973375014749/isodate-0.7.2.tar.gz", hash = "sha256:4cd1aa0f43ca76f4a6c6c0292a85f40b35ec2e43e315b59f06e6d32171a953e6", size = 29705 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/aa/0aca39a37d3c7eb941ba736ede56d689e7be91cab5d9ca846bde3999eba6/isodate-0.7.2-py3-none-any.whl", hash = "sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15", size = 22320 }, +] + +[[package]] +name = "jinja2" +version = "3.1.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ed/55/39036716d19cab0747a5020fc7e907f362fbf48c984b14e62127f7e68e5d/jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", size = 240245 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d", size = 133271 }, +] + [[package]] name = "jiter" -version = "0.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/1a/aa64be757afc614484b370a4d9fc1747dc9237b37ce464f7f9d9ca2a3d38/jiter-0.5.0.tar.gz", hash = "sha256:1d916ba875bcab5c5f7d927df998c4cb694d27dceddf3392e58beaf10563368a", size = 158300 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/5f/3ac960ed598726aae46edea916e6df4df7ff6fe084bc60774b95cf3154e6/jiter-0.5.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d4c8e1ed0ef31ad29cae5ea16b9e41529eb50a7fba70600008e9f8de6376d553", size = 284131 }, - { url = "https://files.pythonhosted.org/packages/03/eb/2308fa5f5c14c97c4c7720fef9465f1fa0771826cddb4eec9866bdd88846/jiter-0.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6f16e21276074a12d8421692515b3fd6d2ea9c94fd0734c39a12960a20e85f3", size = 299310 }, - { url = "https://files.pythonhosted.org/packages/3c/f6/dba34ca10b44715fa5302b8e8d2113f72eb00a9297ddf3fa0ae4fd22d1d1/jiter-0.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5280e68e7740c8c128d3ae5ab63335ce6d1fb6603d3b809637b11713487af9e6", size = 332282 }, - { url = "https://files.pythonhosted.org/packages/69/f7/64e0a7439790ec47f7681adb3871c9d9c45fff771102490bbee5e92c00b7/jiter-0.5.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:583c57fc30cc1fec360e66323aadd7fc3edeec01289bfafc35d3b9dcb29495e4", size = 342370 }, - { url = "https://files.pythonhosted.org/packages/55/31/1efbfff2ae8e4d919144c53db19b828049ad0622a670be3bbea94a86282c/jiter-0.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26351cc14507bdf466b5f99aba3df3143a59da75799bf64a53a3ad3155ecded9", size = 363591 }, - { url = "https://files.pythonhosted.org/packages/30/c3/7ab2ca2276426a7398c6dfb651e38dbc81954c79a3bfbc36c514d8599499/jiter-0.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4829df14d656b3fb87e50ae8b48253a8851c707da9f30d45aacab2aa2ba2d614", size = 378551 }, - { url = "https://files.pythonhosted.org/packages/47/e7/5d88031cd743c62199b125181a591b1671df3ff2f6e102df85c58d8f7d31/jiter-0.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a42a4bdcf7307b86cb863b2fb9bb55029b422d8f86276a50487982d99eed7c6e", size = 319152 }, - { url = "https://files.pythonhosted.org/packages/4c/2d/09ea58e1adca9f0359f3d41ef44a1a18e59518d7c43a21f4ece9e72e28c0/jiter-0.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04d461ad0aebf696f8da13c99bc1b3e06f66ecf6cfd56254cc402f6385231c06", size = 357377 }, - { url = "https://files.pythonhosted.org/packages/7d/2f/83ff1058cb56fc3ff73e0d3c6440703ddc9cdb7f759b00cfbde8228fc435/jiter-0.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e6375923c5f19888c9226582a124b77b622f8fd0018b843c45eeb19d9701c403", size = 511091 }, - { url = "https://files.pythonhosted.org/packages/ae/c9/4f85f97c9894382ab457382337aea0012711baaa17f2ed55c0ff25f3668a/jiter-0.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2cec323a853c24fd0472517113768c92ae0be8f8c384ef4441d3632da8baa646", size = 492948 }, - { url = "https://files.pythonhosted.org/packages/4d/f2/2e987e0eb465e064c5f52c2f29c8d955452e3b316746e326269263bfb1b7/jiter-0.5.0-cp311-none-win32.whl", hash = "sha256:aa1db0967130b5cab63dfe4d6ff547c88b2a394c3410db64744d491df7f069bb", size = 195183 }, - { url = "https://files.pythonhosted.org/packages/ab/59/05d1c3203c349b37c4dd28b02b9b4e5915a7bcbd9319173b4548a67d2e93/jiter-0.5.0-cp311-none-win_amd64.whl", hash = "sha256:aa9d2b85b2ed7dc7697597dcfaac66e63c1b3028652f751c81c65a9f220899ae", size = 191032 }, - { url = "https://files.pythonhosted.org/packages/aa/bd/c3950e2c478161e131bed8cb67c36aed418190e2a961a1c981e69954e54b/jiter-0.5.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9f664e7351604f91dcdd557603c57fc0d551bc65cc0a732fdacbf73ad335049a", size = 283511 }, - { url = "https://files.pythonhosted.org/packages/80/1c/8ce58d8c37a589eeaaa5d07d131fd31043886f5e77ab50c00a66d869a361/jiter-0.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:044f2f1148b5248ad2c8c3afb43430dccf676c5a5834d2f5089a4e6c5bbd64df", size = 296974 }, - { url = "https://files.pythonhosted.org/packages/4d/b8/6faeff9eed8952bed93a77ea1cffae7b946795b88eafd1a60e87a67b09e0/jiter-0.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:702e3520384c88b6e270c55c772d4bd6d7b150608dcc94dea87ceba1b6391248", size = 331897 }, - { url = "https://files.pythonhosted.org/packages/4f/54/1d9a2209b46d39ce6f0cef3ad87c462f9c50312ab84585e6bd5541292b35/jiter-0.5.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:528d742dcde73fad9d63e8242c036ab4a84389a56e04efd854062b660f559544", size = 342962 }, - { url = "https://files.pythonhosted.org/packages/2a/de/90360be7fc54b2b4c2dfe79eb4ed1f659fce9c96682e6a0be4bbe71371f7/jiter-0.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8cf80e5fe6ab582c82f0c3331df27a7e1565e2dcf06265afd5173d809cdbf9ba", size = 363844 }, - { url = "https://files.pythonhosted.org/packages/ba/ad/ef32b173191b7a53ea8a6757b80723cba321f8469834825e8c71c96bde17/jiter-0.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:44dfc9ddfb9b51a5626568ef4e55ada462b7328996294fe4d36de02fce42721f", size = 378709 }, - { url = "https://files.pythonhosted.org/packages/07/de/353ce53743c0defbbbd652e89c106a97dbbac4eb42c95920b74b5056b93a/jiter-0.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c451f7922992751a936b96c5f5b9bb9312243d9b754c34b33d0cb72c84669f4e", size = 319038 }, - { url = "https://files.pythonhosted.org/packages/3f/92/42d47310bf9530b9dece9e2d7c6d51cf419af5586ededaf5e66622d160e2/jiter-0.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:308fce789a2f093dca1ff91ac391f11a9f99c35369117ad5a5c6c4903e1b3e3a", size = 357763 }, - { url = "https://files.pythonhosted.org/packages/bd/8c/2bb76a9a84474d48fdd133d3445db8a4413da4e87c23879d917e000a9d87/jiter-0.5.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7f5ad4a7c6b0d90776fdefa294f662e8a86871e601309643de30bf94bb93a64e", size = 511031 }, - { url = "https://files.pythonhosted.org/packages/33/4f/9f23d79c0795e0a8e56e7988e8785c2dcda27e0ed37977256d50c77c6a19/jiter-0.5.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ea189db75f8eca08807d02ae27929e890c7d47599ce3d0a6a5d41f2419ecf338", size = 493042 }, - { url = "https://files.pythonhosted.org/packages/df/67/8a4f975aa834b8aecdb6b131422390173928fd47f42f269dcc32034ab432/jiter-0.5.0-cp312-none-win32.whl", hash = "sha256:e3bbe3910c724b877846186c25fe3c802e105a2c1fc2b57d6688b9f8772026e4", size = 195405 }, - { url = "https://files.pythonhosted.org/packages/15/81/296b1e25c43db67848728cdab34ac3eb5c5cbb4955ceb3f51ae60d4a5e3d/jiter-0.5.0-cp312-none-win_amd64.whl", hash = "sha256:a586832f70c3f1481732919215f36d41c59ca080fa27a65cf23d9490e75b2ef5", size = 189720 }, +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ac/3d/4ca1c6b8d1d15ea747da474891f9879c0f0777e2e44e87c0be81657ed016/jiter-0.7.0.tar.gz", hash = "sha256:c061d9738535497b5509f8970584f20de1e900806b239a39a9994fc191dad630", size = 162154 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/01/ac41fe6d402da0ff454e2abaee6b8cc29ad2c97cf985f503e46ca7724aca/jiter-0.7.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:91cec0ad755bd786c9f769ce8d843af955df6a8e56b17658771b2d5cb34a3ff8", size = 292667 }, + { url = "https://files.pythonhosted.org/packages/9d/cb/d2e612729676cbe022ad732aaed9c842ac459a70808a927f7f845cfc6dc1/jiter-0.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:feba70a28a27d962e353e978dbb6afd798e711c04cb0b4c5e77e9d3779033a1a", size = 306403 }, + { url = "https://files.pythonhosted.org/packages/e9/db/d88002c550f6405dbf98962cc3dc1c8e66de9c4f3246abebe1582b2f919f/jiter-0.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9d866ec066c3616cacb8535dbda38bb1d470b17b25f0317c4540182bc886ce2", size = 329020 }, + { url = "https://files.pythonhosted.org/packages/18/42/54d6527bcdea2909396849491b96a6fe595bd97ec43bdc522399c534ed33/jiter-0.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8e7a7a00b6f9f18289dd563596f97ecaba6c777501a8ba04bf98e03087bcbc60", size = 347638 }, + { url = "https://files.pythonhosted.org/packages/ec/12/a3c43061d5e189def91c07472e64a569196687f60c2f86150e29a5692ce7/jiter-0.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9aaf564094c7db8687f2660605e099f3d3e6ea5e7135498486674fcb78e29165", size = 373916 }, + { url = "https://files.pythonhosted.org/packages/32/08/2c7432ed26d194927ec07c1dfc08cdae5b6d302369df7fdda320d6393736/jiter-0.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a4d27e09825c1b3c7a667adb500ce8b840e8fc9f630da8454b44cdd4fb0081bb", size = 390942 }, + { url = "https://files.pythonhosted.org/packages/65/9b/70f3ecbd3f18ef19e50fbe5a51bdb1c520282720896c16ae1a68b90675b8/jiter-0.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ca7c287da9c1d56dda88da1d08855a787dbb09a7e2bd13c66a2e288700bd7c7", size = 327315 }, + { url = "https://files.pythonhosted.org/packages/2c/30/ba97e50e5fe1f58a1012257e0cfac0cc09e548b63f81982546c6dac8f1e7/jiter-0.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db19a6d160f093cbc8cd5ea2abad420b686f6c0e5fb4f7b41941ebc6a4f83cda", size = 367159 }, + { url = "https://files.pythonhosted.org/packages/a1/6d/73bb48ca87951c6c01b902258d0b792ed9404980bafceb1aa87ac43eb925/jiter-0.7.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6e46a63c7f877cf7441ffc821c28287cfb9f533ae6ed707bde15e7d4dfafa7ae", size = 514891 }, + { url = "https://files.pythonhosted.org/packages/6f/03/50c665a3d9067c5e384604310d67a184ae3176f27f677ca0c2670bb061ac/jiter-0.7.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7ba426fa7ff21cb119fa544b75dd3fbee6a70e55a5829709c0338d07ccd30e6d", size = 498039 }, + { url = "https://files.pythonhosted.org/packages/85/35/9fb7c7fea9b9c159d2089ea9b5ff4e3e56e2d42069456e3568dadf904e99/jiter-0.7.0-cp311-none-win32.whl", hash = "sha256:c07f55a64912b0c7982377831210836d2ea92b7bd343fca67a32212dd72e38e0", size = 198533 }, + { url = "https://files.pythonhosted.org/packages/96/19/e9b32c69c6dea404d983847e92cf86c3287b0f2f3e7621180a544c0ff153/jiter-0.7.0-cp311-none-win_amd64.whl", hash = "sha256:ed27b2c43e1b5f6c7fedc5c11d4d8bfa627de42d1143d87e39e2e83ddefd861a", size = 205728 }, + { url = "https://files.pythonhosted.org/packages/d9/7b/ed881a65e8f0989913408643b68a3a0913365c5c3884e85bae01a9679dd5/jiter-0.7.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ac7930bcaaeb1e229e35c91c04ed2e9f39025b86ee9fc3141706bbf6fff4aeeb", size = 292762 }, + { url = "https://files.pythonhosted.org/packages/d8/44/d0409912bc28508abffd99b9d55baba869592c1d27f9ee1cc035ef62371e/jiter-0.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:571feae3e7c901a8eedde9fd2865b0dfc1432fb15cab8c675a8444f7d11b7c5d", size = 302790 }, + { url = "https://files.pythonhosted.org/packages/8d/4f/38d0e87c8863c1b1f2dbac48acca8da85f6931a7b735e7163781843170a5/jiter-0.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8af4df8a262fa2778b68c2a03b6e9d1cb4d43d02bea6976d46be77a3a331af1", size = 329246 }, + { url = "https://files.pythonhosted.org/packages/88/3c/1af75094cbeba25df672b3f772dc717203be843e08248a0e03ef0ca382bc/jiter-0.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd028d4165097a611eb0c7494d8c1f2aebd46f73ca3200f02a175a9c9a6f22f5", size = 347808 }, + { url = "https://files.pythonhosted.org/packages/0b/74/55f00ca01223665e1418bec76cdeebb17a5f9ffae94e886da5c9bef5abd2/jiter-0.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6b487247c7836810091e9455efe56a52ec51bfa3a222237e1587d04d3e04527", size = 374011 }, + { url = "https://files.pythonhosted.org/packages/f7/ae/c1c892861796aa0adb720da75c59de5dbcf74ad51243c2aeea46681dcb16/jiter-0.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6d28a92f28814e1a9f2824dc11f4e17e1df1f44dc4fdeb94c5450d34bcb2602", size = 388863 }, + { url = "https://files.pythonhosted.org/packages/9d/a2/914587a68cba16920b1f979267a4e5c19f6977cac8fb8a6fbbd00035d0ed/jiter-0.7.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90443994bbafe134f0b34201dad3ebe1c769f0599004084e046fb249ad912425", size = 326765 }, + { url = "https://files.pythonhosted.org/packages/c8/ea/79abc48a6c9ba9ee3ccb0c194ec4cc1dd62e523c7c7003189380d00e5f16/jiter-0.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f9abf464f9faac652542ce8360cea8e68fba2b78350e8a170248f9bcc228702a", size = 367756 }, + { url = "https://files.pythonhosted.org/packages/4b/eb/ddc874819382081f9ad71cf681ee76450b17ac981f78a8db6408e7e28f34/jiter-0.7.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db7a8d99fc5f842f7d2852f06ccaed066532292c41723e5dff670c339b649f88", size = 515349 }, + { url = "https://files.pythonhosted.org/packages/af/9d/816d2d7f19070b72cf0133437cbacf99a9202f6fbbc2cfa2111fb686b0e0/jiter-0.7.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:15cf691ebd8693b70c94627d6b748f01e6d697d9a6e9f2bc310934fcfb7cf25e", size = 498050 }, + { url = "https://files.pythonhosted.org/packages/3e/a5/d0afb758c02d2d3c8ac3214a5be26579594d790944eaee7a47af06915e0e/jiter-0.7.0-cp312-none-win32.whl", hash = "sha256:9dcd54fa422fb66ca398bec296fed5f58e756aa0589496011cfea2abb5be38a5", size = 198912 }, + { url = "https://files.pythonhosted.org/packages/d0/8e/80b2afd0391a3530966d8fc2f9c104955ba41093b3c319ae40b25e68e323/jiter-0.7.0-cp312-none-win_amd64.whl", hash = "sha256:cc989951f73f9375b8eacd571baaa057f3d7d11b7ce6f67b9d54642e7475bfad", size = 199942 }, + { url = "https://files.pythonhosted.org/packages/50/bb/82c7180dc126687ddcc25386727b3a1688ab8eff496afe7838b69886fcc7/jiter-0.7.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:24cecd18df540963cd27c08ca5ce1d0179f229ff78066d9eecbe5add29361340", size = 292624 }, + { url = "https://files.pythonhosted.org/packages/11/c2/3b6d4596eab2ff81ebfe5bab779f457433cc2ffb8a2d1d6ab5ac187f26f6/jiter-0.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d41b46236b90b043cca73785674c23d2a67d16f226394079d0953f94e765ed76", size = 304723 }, + { url = "https://files.pythonhosted.org/packages/49/65/56f78dfccfb22e43815cad4a468b4360f8cfebecc024edb5e2a625b83a04/jiter-0.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b160db0987171365c153e406a45dcab0ee613ae3508a77bfff42515cb4ce4d6e", size = 328319 }, + { url = "https://files.pythonhosted.org/packages/fd/f2/9e3ed9ac0b122dd65250fc83cd0f0979da82f055ef6041411191f6301284/jiter-0.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1c8d91e0f0bd78602eaa081332e8ee4f512c000716f5bc54e9a037306d693a7", size = 347323 }, + { url = "https://files.pythonhosted.org/packages/42/18/24517f9f8575daf36fdac9dd53fcecde3d4c5bdd9f7b97a55e26ed2555b5/jiter-0.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997706c683195eeff192d2e5285ce64d2a610414f37da3a3f2625dcf8517cf90", size = 374073 }, + { url = "https://files.pythonhosted.org/packages/a1/b1/b368ccdeff3eabb4b293a21a94317a6f717ecc5bfbfca4eecd12ff39da3f/jiter-0.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ea52a8a0ff0229ab2920284079becd2bae0688d432fca94857ece83bb49c541", size = 388224 }, + { url = "https://files.pythonhosted.org/packages/92/1e/cc3d0655bcbc026e4b7746cb1ccab10d6eb2c29ffa64e574072db4d55f73/jiter-0.7.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d77449d2738cf74752bb35d75ee431af457e741124d1db5e112890023572c7c", size = 326145 }, + { url = "https://files.pythonhosted.org/packages/bb/24/d410c732326738d4f392689621ff14e10d3717efe7de9ecb97c44d8765a3/jiter-0.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8203519907a1d81d6cb00902c98e27c2d0bf25ce0323c50ca594d30f5f1fbcf", size = 366857 }, + { url = "https://files.pythonhosted.org/packages/14/a1/53df95b8248968936e7ba9eb5839918e3cfd183e56356d2961b9b29a49fc/jiter-0.7.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41d15ccc53931c822dd7f1aebf09faa3cda2d7b48a76ef304c7dbc19d1302e51", size = 514972 }, + { url = "https://files.pythonhosted.org/packages/97/c8/1876add533606ff1204450dd2564638cac7f164ff90844cb921cdf25cf68/jiter-0.7.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:febf3179b2fabf71fbd2fd52acb8594163bb173348b388649567a548f356dbf6", size = 497728 }, + { url = "https://files.pythonhosted.org/packages/94/31/1e59f246e264414b004864b63783e54aa3397be88f53dda3b01db3ae4251/jiter-0.7.0-cp313-none-win32.whl", hash = "sha256:4a8e2d866e7eda19f012444e01b55079d8e1c4c30346aaac4b97e80c54e2d6d3", size = 198660 }, + { url = "https://files.pythonhosted.org/packages/ca/96/58b3d260e212add0087563672931b1176e70bef1225839a4470ec66157a5/jiter-0.7.0-cp313-none-win_amd64.whl", hash = "sha256:7417c2b928062c496f381fb0cb50412eee5ad1d8b53dbc0e011ce45bb2de522c", size = 199305 }, ] [[package]] @@ -762,7 +914,7 @@ wheels = [ [[package]] name = "openai" -version = "1.51.0" +version = "1.54.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -774,11 +926,43 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/28/af/cc59b1447f5a02bb1f25b9b0cd94b607aa2c969a81d9a244d4067f91f6fe/openai-1.51.0.tar.gz", hash = "sha256:8dc4f9d75ccdd5466fc8c99a952186eddceb9fd6ba694044773f3736a847149d", size = 306880 } +sdist = { url = "https://files.pythonhosted.org/packages/da/26/f1a79d8332ac5ed38fdc347701aa4a7ad8f8f66ec3f9880122c455d7ffb1/openai-1.54.2.tar.gz", hash = "sha256:0dbb8f2bb36f7ff1d200d103b9f95c35773ed3248e3a697b02f5a39015627e5e", size = 312551 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/08/9f22356d4fbd273f734db1e6663b7ca6987943080567f5580471022e57ca/openai-1.51.0-py3-none-any.whl", hash = "sha256:d9affafb7e51e5a27dce78589d4964ce4d6f6d560307265933a94b2e3f3c5d2c", size = 383533 }, + { url = "https://files.pythonhosted.org/packages/f6/0f/ea8717dedbef16fa61a0bdeb0b7ae96ff574933ed5932102d3f5a4ce01a1/openai-1.54.2-py3-none-any.whl", hash = "sha256:77010b439e69d37f67cc2f44eaa62b2b6d5a60add2d8636e4603c0e762982708", size = 389315 }, +] + +[[package]] +name = "openai-client" +version = "0.1.0" +source = { editable = "../../openai-client" } +dependencies = [ + { name = "azure-ai-contentsafety" }, + { name = "azure-core", extra = ["aio"] }, + { name = "azure-identity" }, + { name = "function-registry" }, + { name = "openai" }, + { name = "pillow" }, + { name = "python-liquid" }, + { name = "semantic-workbench-assistant" }, + { name = "tiktoken" }, +] + +[package.metadata] +requires-dist = [ + { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, + { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, + { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "function-registry", editable = "../../function-registry" }, + { name = "openai", specifier = ">=1.3.9" }, + { name = "pillow", specifier = ">=11.0.0" }, + { name = "python-liquid", specifier = ">=1.12.1" }, + { name = "semantic-workbench-assistant", editable = "../../semantic-workbench-assistant" }, + { name = "tiktoken", specifier = ">=0.7.0" }, ] +[package.metadata.requires-dev] +dev = [{ name = "pytest", specifier = ">=8.3.3" }] + [[package]] name = "packaging" version = "24.1" @@ -788,6 +972,55 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124", size = 53985 }, ] +[[package]] +name = "pillow" +version = "11.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/26/0d95c04c868f6bdb0c447e3ee2de5564411845e36a858cfd63766bc7b563/pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739", size = 46737780 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f0/eb/f7e21b113dd48a9c97d364e0915b3988c6a0b6207652f5a92372871b7aa4/pillow-11.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1c1d72714f429a521d8d2d018badc42414c3077eb187a59579f28e4270b4b0fc", size = 3154705 }, + { url = "https://files.pythonhosted.org/packages/25/b3/2b54a1d541accebe6bd8b1358b34ceb2c509f51cb7dcda8687362490da5b/pillow-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:499c3a1b0d6fc8213519e193796eb1a86a1be4b1877d678b30f83fd979811d1a", size = 2979222 }, + { url = "https://files.pythonhosted.org/packages/20/12/1a41eddad8265c5c19dda8fb6c269ce15ee25e0b9f8f26286e6202df6693/pillow-11.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8b2351c85d855293a299038e1f89db92a2f35e8d2f783489c6f0b2b5f3fe8a3", size = 4190220 }, + { url = "https://files.pythonhosted.org/packages/a9/9b/8a8c4d07d77447b7457164b861d18f5a31ae6418ef5c07f6f878fa09039a/pillow-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4dba50cfa56f910241eb7f883c20f1e7b1d8f7d91c750cd0b318bad443f4d5", size = 4291399 }, + { url = "https://files.pythonhosted.org/packages/fc/e4/130c5fab4a54d3991129800dd2801feeb4b118d7630148cd67f0e6269d4c/pillow-11.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5ddbfd761ee00c12ee1be86c9c0683ecf5bb14c9772ddbd782085779a63dd55b", size = 4202709 }, + { url = "https://files.pythonhosted.org/packages/39/63/b3fc299528d7df1f678b0666002b37affe6b8751225c3d9c12cf530e73ed/pillow-11.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa", size = 4372556 }, + { url = "https://files.pythonhosted.org/packages/c6/a6/694122c55b855b586c26c694937d36bb8d3b09c735ff41b2f315c6e66a10/pillow-11.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b4fd7bd29610a83a8c9b564d457cf5bd92b4e11e79a4ee4716a63c959699b306", size = 4287187 }, + { url = "https://files.pythonhosted.org/packages/ba/a9/f9d763e2671a8acd53d29b1e284ca298bc10a595527f6be30233cdb9659d/pillow-11.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cb929ca942d0ec4fac404cbf520ee6cac37bf35be479b970c4ffadf2b6a1cad9", size = 4418468 }, + { url = "https://files.pythonhosted.org/packages/6e/0e/b5cbad2621377f11313a94aeb44ca55a9639adabcaaa073597a1925f8c26/pillow-11.0.0-cp311-cp311-win32.whl", hash = "sha256:006bcdd307cc47ba43e924099a038cbf9591062e6c50e570819743f5607404f5", size = 2249249 }, + { url = "https://files.pythonhosted.org/packages/dc/83/1470c220a4ff06cd75fc609068f6605e567ea51df70557555c2ab6516b2c/pillow-11.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:52a2d8323a465f84faaba5236567d212c3668f2ab53e1c74c15583cf507a0291", size = 2566769 }, + { url = "https://files.pythonhosted.org/packages/52/98/def78c3a23acee2bcdb2e52005fb2810ed54305602ec1bfcfab2bda6f49f/pillow-11.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:16095692a253047fe3ec028e951fa4221a1f3ed3d80c397e83541a3037ff67c9", size = 2254611 }, + { url = "https://files.pythonhosted.org/packages/1c/a3/26e606ff0b2daaf120543e537311fa3ae2eb6bf061490e4fea51771540be/pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923", size = 3147642 }, + { url = "https://files.pythonhosted.org/packages/4f/d5/1caabedd8863526a6cfa44ee7a833bd97f945dc1d56824d6d76e11731939/pillow-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903", size = 2978999 }, + { url = "https://files.pythonhosted.org/packages/d9/ff/5a45000826a1aa1ac6874b3ec5a856474821a1b59d838c4f6ce2ee518fe9/pillow-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4", size = 4196794 }, + { url = "https://files.pythonhosted.org/packages/9d/21/84c9f287d17180f26263b5f5c8fb201de0f88b1afddf8a2597a5c9fe787f/pillow-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f", size = 4300762 }, + { url = "https://files.pythonhosted.org/packages/84/39/63fb87cd07cc541438b448b1fed467c4d687ad18aa786a7f8e67b255d1aa/pillow-11.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9", size = 4210468 }, + { url = "https://files.pythonhosted.org/packages/7f/42/6e0f2c2d5c60f499aa29be14f860dd4539de322cd8fb84ee01553493fb4d/pillow-11.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7", size = 4381824 }, + { url = "https://files.pythonhosted.org/packages/31/69/1ef0fb9d2f8d2d114db982b78ca4eeb9db9a29f7477821e160b8c1253f67/pillow-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6", size = 4296436 }, + { url = "https://files.pythonhosted.org/packages/44/ea/dad2818c675c44f6012289a7c4f46068c548768bc6c7f4e8c4ae5bbbc811/pillow-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc", size = 4429714 }, + { url = "https://files.pythonhosted.org/packages/af/3a/da80224a6eb15bba7a0dcb2346e2b686bb9bf98378c0b4353cd88e62b171/pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6", size = 2249631 }, + { url = "https://files.pythonhosted.org/packages/57/97/73f756c338c1d86bb802ee88c3cab015ad7ce4b838f8a24f16b676b1ac7c/pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47", size = 2567533 }, + { url = "https://files.pythonhosted.org/packages/0b/30/2b61876e2722374558b871dfbfcbe4e406626d63f4f6ed92e9c8e24cac37/pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25", size = 2254890 }, + { url = "https://files.pythonhosted.org/packages/63/24/e2e15e392d00fcf4215907465d8ec2a2f23bcec1481a8ebe4ae760459995/pillow-11.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699", size = 3147300 }, + { url = "https://files.pythonhosted.org/packages/43/72/92ad4afaa2afc233dc44184adff289c2e77e8cd916b3ddb72ac69495bda3/pillow-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38", size = 2978742 }, + { url = "https://files.pythonhosted.org/packages/9e/da/c8d69c5bc85d72a8523fe862f05ababdc52c0a755cfe3d362656bb86552b/pillow-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2", size = 4194349 }, + { url = "https://files.pythonhosted.org/packages/cd/e8/686d0caeed6b998351d57796496a70185376ed9c8ec7d99e1d19ad591fc6/pillow-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2", size = 4298714 }, + { url = "https://files.pythonhosted.org/packages/ec/da/430015cec620d622f06854be67fd2f6721f52fc17fca8ac34b32e2d60739/pillow-11.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527", size = 4208514 }, + { url = "https://files.pythonhosted.org/packages/44/ae/7e4f6662a9b1cb5f92b9cc9cab8321c381ffbee309210940e57432a4063a/pillow-11.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa", size = 4380055 }, + { url = "https://files.pythonhosted.org/packages/74/d5/1a807779ac8a0eeed57f2b92a3c32ea1b696e6140c15bd42eaf908a261cd/pillow-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f", size = 4296751 }, + { url = "https://files.pythonhosted.org/packages/38/8c/5fa3385163ee7080bc13026d59656267daaaaf3c728c233d530e2c2757c8/pillow-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb", size = 4430378 }, + { url = "https://files.pythonhosted.org/packages/ca/1d/ad9c14811133977ff87035bf426875b93097fb50af747793f013979facdb/pillow-11.0.0-cp313-cp313-win32.whl", hash = "sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798", size = 2249588 }, + { url = "https://files.pythonhosted.org/packages/fb/01/3755ba287dac715e6afdb333cb1f6d69740a7475220b4637b5ce3d78cec2/pillow-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de", size = 2567509 }, + { url = "https://files.pythonhosted.org/packages/c0/98/2c7d727079b6be1aba82d195767d35fcc2d32204c7a5820f822df5330152/pillow-11.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84", size = 2254791 }, + { url = "https://files.pythonhosted.org/packages/eb/38/998b04cc6f474e78b563716b20eecf42a2fa16a84589d23c8898e64b0ffd/pillow-11.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b", size = 3150854 }, + { url = "https://files.pythonhosted.org/packages/13/8e/be23a96292113c6cb26b2aa3c8b3681ec62b44ed5c2bd0b258bd59503d3c/pillow-11.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003", size = 2982369 }, + { url = "https://files.pythonhosted.org/packages/97/8a/3db4eaabb7a2ae8203cd3a332a005e4aba00067fc514aaaf3e9721be31f1/pillow-11.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2", size = 4333703 }, + { url = "https://files.pythonhosted.org/packages/28/ac/629ffc84ff67b9228fe87a97272ab125bbd4dc462745f35f192d37b822f1/pillow-11.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a", size = 4412550 }, + { url = "https://files.pythonhosted.org/packages/d6/07/a505921d36bb2df6868806eaf56ef58699c16c388e378b0dcdb6e5b2fb36/pillow-11.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8", size = 4461038 }, + { url = "https://files.pythonhosted.org/packages/d6/b9/fb620dd47fc7cc9678af8f8bd8c772034ca4977237049287e99dda360b66/pillow-11.0.0-cp313-cp313t-win32.whl", hash = "sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8", size = 2253197 }, + { url = "https://files.pythonhosted.org/packages/df/86/25dde85c06c89d7fc5db17940f07aae0a56ac69aa9ccb5eb0f09798862a8/pillow-11.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904", size = 2572169 }, + { url = "https://files.pythonhosted.org/packages/51/85/9c33f2517add612e17f3381aee7c4072779130c634921a756c97bc29fb49/pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3", size = 2256828 }, +] + [[package]] name = "pluggy" version = "1.5.0" @@ -938,15 +1171,15 @@ wheels = [ [[package]] name = "pydantic-settings" -version = "2.5.2" +version = "2.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/68/27/0bed9dd26b93328b60a1402febc780e7be72b42847fa8b5c94b7d0aeb6d1/pydantic_settings-2.5.2.tar.gz", hash = "sha256:f90b139682bee4d2065273d5185d71d37ea46cfe57e1b5ae184fc6a0b2484ca0", size = 70938 } +sdist = { url = "https://files.pythonhosted.org/packages/b5/d4/9dfbe238f45ad8b168f5c96ee49a3df0598ce18a0795a983b419949ce65b/pydantic_settings-2.6.1.tar.gz", hash = "sha256:e0f92546d8a9923cb8941689abf85d6601a8c19a23e97a34b2964a2e3f813ca0", size = 75646 } wheels = [ - { url = "https://files.pythonhosted.org/packages/29/8d/29e82e333f32d9e2051c10764b906c2a6cd140992910b5f49762790911ba/pydantic_settings-2.5.2-py3-none-any.whl", hash = "sha256:2c912e55fd5794a59bf8c832b9de832dcfdf4778d79ff79b708744eed499a907", size = 26864 }, + { url = "https://files.pythonhosted.org/packages/5e/f9/ff95fd7d760af42f647ea87f9b8a383d891cdb5e5dbd4613edaeb094252a/pydantic_settings-2.6.1-py3-none-any.whl", hash = "sha256:7fb0637c786a558d3103436278a7c4f1cfd29ba8973238a50c5bb9a55387da87", size = 28595 }, ] [[package]] @@ -1032,6 +1265,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 }, ] +[[package]] +name = "python-json-logger" +version = "2.0.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/da/95963cebfc578dabd323d7263958dfb68898617912bb09327dd30e9c8d13/python-json-logger-2.0.7.tar.gz", hash = "sha256:23e7ec02d34237c5aa1e29a070193a4ea87583bb4e7f8fd06d3de8264c4b2e1c", size = 10508 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/a6/145655273568ee78a581e734cf35beb9e33a370b29c5d3c8fee3744de29f/python_json_logger-2.0.7-py3-none-any.whl", hash = "sha256:f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd", size = 8067 }, +] + [[package]] name = "python-liquid" version = "1.12.1" @@ -1046,17 +1288,29 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2c/6e/bfd01926e28f6cf355a7a8460271ba135013870f5857b06f35dbf65ab237/python_liquid-1.12.1-py3-none-any.whl", hash = "sha256:2224312944be16c1a44406398eb8a07c7e57398d5c0ef15ff950946dbefe7c33", size = 206592 }, ] +[[package]] +name = "python-multipart" +version = "0.0.17" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/40/22/edea41c2d4a22e666c0c7db7acdcbf7bc8c1c1f7d3b3ca246ec982fec612/python_multipart-0.0.17.tar.gz", hash = "sha256:41330d831cae6e2f22902704ead2826ea038d0419530eadff3ea80175aec5538", size = 36452 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b4/fb/275137a799169392f1fa88fff2be92f16eee38e982720a8aaadefc4a36b2/python_multipart-0.0.17-py3-none-any.whl", hash = "sha256:15dc4f487e0a9476cc1201261188ee0940165cffc94429b6fc565c4d3045cb5d", size = 24453 }, +] + [[package]] name = "pywin32" -version = "306" +version = "308" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/1e/fc18ad83ca553e01b97aa8393ff10e33c1fb57801db05488b83282ee9913/pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407", size = 8507689 }, - { url = "https://files.pythonhosted.org/packages/7e/9e/ad6b1ae2a5ad1066dc509350e0fbf74d8d50251a51e420a2a8feaa0cecbd/pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e", size = 9227547 }, - { url = "https://files.pythonhosted.org/packages/91/20/f744bff1da8f43388498503634378dbbefbe493e65675f2cc52f7185c2c2/pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a", size = 10388324 }, - { url = "https://files.pythonhosted.org/packages/14/91/17e016d5923e178346aabda3dfec6629d1a26efe587d19667542105cf0a6/pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b", size = 8507705 }, - { url = "https://files.pythonhosted.org/packages/83/1c/25b79fc3ec99b19b0a0730cc47356f7e2959863bf9f3cd314332bddb4f68/pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e", size = 9227429 }, - { url = "https://files.pythonhosted.org/packages/1c/43/e3444dc9a12f8365d9603c2145d16bf0a2f8180f343cf87be47f5579e547/pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040", size = 10388145 }, + { url = "https://files.pythonhosted.org/packages/eb/e2/02652007469263fe1466e98439831d65d4ca80ea1a2df29abecedf7e47b7/pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a", size = 5928156 }, + { url = "https://files.pythonhosted.org/packages/48/ef/f4fb45e2196bc7ffe09cad0542d9aff66b0e33f6c0954b43e49c33cad7bd/pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b", size = 6559559 }, + { url = "https://files.pythonhosted.org/packages/79/ef/68bb6aa865c5c9b11a35771329e95917b5559845bd75b65549407f9fc6b4/pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6", size = 7972495 }, + { url = "https://files.pythonhosted.org/packages/00/7c/d00d6bdd96de4344e06c4afbf218bc86b54436a94c01c71a8701f613aa56/pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897", size = 5939729 }, + { url = "https://files.pythonhosted.org/packages/21/27/0c8811fbc3ca188f93b5354e7c286eb91f80a53afa4e11007ef661afa746/pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47", size = 6543015 }, + { url = "https://files.pythonhosted.org/packages/9d/0f/d40f8373608caed2255781a3ad9a51d03a594a1248cd632d6a298daca693/pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091", size = 7976033 }, + { url = "https://files.pythonhosted.org/packages/a9/a4/aa562d8935e3df5e49c161b427a3a2efad2ed4e9cf81c3de636f1fdddfd0/pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed", size = 5938579 }, + { url = "https://files.pythonhosted.org/packages/c7/50/b0efb8bb66210da67a53ab95fd7a98826a97ee21f1d22949863e6d588b22/pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4", size = 6542056 }, + { url = "https://files.pythonhosted.org/packages/26/df/2b63e3e4f2df0224f8aaf6d131f54fe4e8c96400eb9df563e2aae2e1a1f9/pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd", size = 7974986 }, ] [[package]] @@ -1313,40 +1567,44 @@ wheels = [ [[package]] name = "tiktoken" -version = "0.7.0" +version = "0.8.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "regex" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c4/4a/abaec53e93e3ef37224a4dd9e2fc6bb871e7a538c2b6b9d2a6397271daf4/tiktoken-0.7.0.tar.gz", hash = "sha256:1077266e949c24e0291f6c350433c6f0971365ece2b173a23bc3b9f9defef6b6", size = 33437 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/eb/57492b2568eea1d546da5cc1ae7559d924275280db80ba07e6f9b89a914b/tiktoken-0.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:10c7674f81e6e350fcbed7c09a65bca9356eaab27fb2dac65a1e440f2bcfe30f", size = 961468 }, - { url = "https://files.pythonhosted.org/packages/30/ef/e07dbfcb2f85c84abaa1b035a9279575a8da0236305491dc22ae099327f7/tiktoken-0.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:084cec29713bc9d4189a937f8a35dbdfa785bd1235a34c1124fe2323821ee93f", size = 907005 }, - { url = "https://files.pythonhosted.org/packages/ea/9b/f36db825b1e9904c3a2646439cb9923fc1e09208e2e071c6d9dd64ead131/tiktoken-0.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:811229fde1652fedcca7c6dfe76724d0908775b353556d8a71ed74d866f73f7b", size = 1049183 }, - { url = "https://files.pythonhosted.org/packages/61/b4/b80d1fe33015e782074e96bbbf4108ccd283b8deea86fb43c15d18b7c351/tiktoken-0.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86b6e7dc2e7ad1b3757e8a24597415bafcfb454cebf9a33a01f2e6ba2e663992", size = 1080830 }, - { url = "https://files.pythonhosted.org/packages/2a/40/c66ff3a21af6d62a7e0ff428d12002c4e0389f776d3ff96dcaa0bb354eee/tiktoken-0.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1063c5748be36344c7e18c7913c53e2cca116764c2080177e57d62c7ad4576d1", size = 1092967 }, - { url = "https://files.pythonhosted.org/packages/2e/80/f4c9e255ff236e6a69ce44b927629cefc1b63d3a00e2d1c9ed540c9492d2/tiktoken-0.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:20295d21419bfcca092644f7e2f2138ff947a6eb8cfc732c09cc7d76988d4a89", size = 1142682 }, - { url = "https://files.pythonhosted.org/packages/b1/10/c04b4ff592a5f46b28ebf4c2353f735c02ae7f0ce1b165d00748ced6467e/tiktoken-0.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:959d993749b083acc57a317cbc643fb85c014d055b2119b739487288f4e5d1cb", size = 799009 }, - { url = "https://files.pythonhosted.org/packages/1d/46/4cdda4186ce900608f522da34acf442363346688c71b938a90a52d7b84cc/tiktoken-0.7.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:71c55d066388c55a9c00f61d2c456a6086673ab7dec22dd739c23f77195b1908", size = 960446 }, - { url = "https://files.pythonhosted.org/packages/b6/30/09ced367d280072d7a3e21f34263dfbbf6378661e7a0f6414e7c18971083/tiktoken-0.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:09ed925bccaa8043e34c519fbb2f99110bd07c6fd67714793c21ac298e449410", size = 906652 }, - { url = "https://files.pythonhosted.org/packages/e6/7b/c949e4954441a879a67626963dff69096e3c774758b9f2bb0853f7b4e1e7/tiktoken-0.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03c6c40ff1db0f48a7b4d2dafeae73a5607aacb472fa11f125e7baf9dce73704", size = 1047904 }, - { url = "https://files.pythonhosted.org/packages/50/81/1842a22f15586072280364c2ab1e40835adaf64e42fe80e52aff921ee021/tiktoken-0.7.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d20b5c6af30e621b4aca094ee61777a44118f52d886dbe4f02b70dfe05c15350", size = 1079836 }, - { url = "https://files.pythonhosted.org/packages/6d/87/51a133a3d5307cf7ae3754249b0faaa91d3414b85c3d36f80b54d6817aa6/tiktoken-0.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d427614c3e074004efa2f2411e16c826f9df427d3c70a54725cae860f09e4bf4", size = 1092472 }, - { url = "https://files.pythonhosted.org/packages/a5/1f/c93517dc6d3b2c9e988b8e24f87a8b2d4a4ab28920a3a3f3ea338397ae0c/tiktoken-0.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8c46d7af7b8c6987fac9b9f61041b452afe92eb087d29c9ce54951280f899a97", size = 1141881 }, - { url = "https://files.pythonhosted.org/packages/bf/4b/48ca098cb580c099b5058bf62c4cb5e90ca6130fa43ef4df27088536245b/tiktoken-0.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:0bc603c30b9e371e7c4c7935aba02af5994a909fc3c0fe66e7004070858d3f8f", size = 799281 }, +sdist = { url = "https://files.pythonhosted.org/packages/37/02/576ff3a6639e755c4f70997b2d315f56d6d71e0d046f4fb64cb81a3fb099/tiktoken-0.8.0.tar.gz", hash = "sha256:9ccbb2740f24542534369c5635cfd9b2b3c2490754a78ac8831d99f89f94eeb2", size = 35107 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/1e/ca48e7bfeeccaf76f3a501bd84db1fa28b3c22c9d1a1f41af9fb7579c5f6/tiktoken-0.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d622d8011e6d6f239297efa42a2657043aaed06c4f68833550cac9e9bc723ef1", size = 1039700 }, + { url = "https://files.pythonhosted.org/packages/8c/f8/f0101d98d661b34534769c3818f5af631e59c36ac6d07268fbfc89e539ce/tiktoken-0.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2efaf6199717b4485031b4d6edb94075e4d79177a172f38dd934d911b588d54a", size = 982413 }, + { url = "https://files.pythonhosted.org/packages/ac/3c/2b95391d9bd520a73830469f80a96e3790e6c0a5ac2444f80f20b4b31051/tiktoken-0.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5637e425ce1fc49cf716d88df3092048359a4b3bbb7da762840426e937ada06d", size = 1144242 }, + { url = "https://files.pythonhosted.org/packages/01/c4/c4a4360de845217b6aa9709c15773484b50479f36bb50419c443204e5de9/tiktoken-0.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fb0e352d1dbe15aba082883058b3cce9e48d33101bdaac1eccf66424feb5b47", size = 1176588 }, + { url = "https://files.pythonhosted.org/packages/f8/a3/ef984e976822cd6c2227c854f74d2e60cf4cd6fbfca46251199914746f78/tiktoken-0.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:56edfefe896c8f10aba372ab5706b9e3558e78db39dd497c940b47bf228bc419", size = 1237261 }, + { url = "https://files.pythonhosted.org/packages/1e/86/eea2309dc258fb86c7d9b10db536434fc16420feaa3b6113df18b23db7c2/tiktoken-0.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:326624128590def898775b722ccc327e90b073714227175ea8febbc920ac0a99", size = 884537 }, + { url = "https://files.pythonhosted.org/packages/c1/22/34b2e136a6f4af186b6640cbfd6f93400783c9ef6cd550d9eab80628d9de/tiktoken-0.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:881839cfeae051b3628d9823b2e56b5cc93a9e2efb435f4cf15f17dc45f21586", size = 1039357 }, + { url = "https://files.pythonhosted.org/packages/04/d2/c793cf49c20f5855fd6ce05d080c0537d7418f22c58e71f392d5e8c8dbf7/tiktoken-0.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fe9399bdc3f29d428f16a2f86c3c8ec20be3eac5f53693ce4980371c3245729b", size = 982616 }, + { url = "https://files.pythonhosted.org/packages/b3/a1/79846e5ef911cd5d75c844de3fa496a10c91b4b5f550aad695c5df153d72/tiktoken-0.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a58deb7075d5b69237a3ff4bb51a726670419db6ea62bdcd8bd80c78497d7ab", size = 1144011 }, + { url = "https://files.pythonhosted.org/packages/26/32/e0e3a859136e95c85a572e4806dc58bf1ddf651108ae8b97d5f3ebe1a244/tiktoken-0.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2908c0d043a7d03ebd80347266b0e58440bdef5564f84f4d29fb235b5df3b04", size = 1175432 }, + { url = "https://files.pythonhosted.org/packages/c7/89/926b66e9025b97e9fbabeaa59048a736fe3c3e4530a204109571104f921c/tiktoken-0.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:294440d21a2a51e12d4238e68a5972095534fe9878be57d905c476017bff99fc", size = 1236576 }, + { url = "https://files.pythonhosted.org/packages/45/e2/39d4aa02a52bba73b2cd21ba4533c84425ff8786cc63c511d68c8897376e/tiktoken-0.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:d8f3192733ac4d77977432947d563d7e1b310b96497acd3c196c9bddb36ed9db", size = 883824 }, + { url = "https://files.pythonhosted.org/packages/e3/38/802e79ba0ee5fcbf240cd624143f57744e5d411d2e9d9ad2db70d8395986/tiktoken-0.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:02be1666096aff7da6cbd7cdaa8e7917bfed3467cd64b38b1f112e96d3b06a24", size = 1039648 }, + { url = "https://files.pythonhosted.org/packages/b1/da/24cdbfc302c98663fbea66f5866f7fa1048405c7564ab88483aea97c3b1a/tiktoken-0.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94ff53c5c74b535b2cbf431d907fc13c678bbd009ee633a2aca269a04389f9a", size = 982763 }, + { url = "https://files.pythonhosted.org/packages/e4/f0/0ecf79a279dfa41fc97d00adccf976ecc2556d3c08ef3e25e45eb31f665b/tiktoken-0.8.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b231f5e8982c245ee3065cd84a4712d64692348bc609d84467c57b4b72dcbc5", size = 1144417 }, + { url = "https://files.pythonhosted.org/packages/ab/d3/155d2d4514f3471a25dc1d6d20549ef254e2aa9bb5b1060809b1d3b03d3a/tiktoken-0.8.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4177faa809bd55f699e88c96d9bb4635d22e3f59d635ba6fd9ffedf7150b9953", size = 1175108 }, + { url = "https://files.pythonhosted.org/packages/19/eb/5989e16821ee8300ef8ee13c16effc20dfc26c777d05fbb6825e3c037b81/tiktoken-0.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5376b6f8dc4753cd81ead935c5f518fa0fbe7e133d9e25f648d8c4dabdd4bad7", size = 1236520 }, + { url = "https://files.pythonhosted.org/packages/40/59/14b20465f1d1cb89cfbc96ec27e5617b2d41c79da12b5e04e96d689be2a7/tiktoken-0.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:18228d624807d66c87acd8f25fc135665617cab220671eb65b50f5d70fa51f69", size = 883849 }, ] [[package]] name = "tqdm" -version = "4.66.5" +version = "4.67.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "platform_system == 'Windows'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/83/6ba9844a41128c62e810fddddd72473201f3eacde02046066142a2d96cc5/tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad", size = 169504 } +sdist = { url = "https://files.pythonhosted.org/packages/e8/4f/0153c21dc5779a49a0598c445b1978126b1344bab9ee71e53e44877e14e0/tqdm-4.67.0.tar.gz", hash = "sha256:fe5a6f95e6fe0b9755e9469b77b9c3cf850048224ecaa8293d7d2d31f97d869a", size = 169739 } wheels = [ - { url = "https://files.pythonhosted.org/packages/48/5d/acf5905c36149bbaec41ccf7f2b68814647347b72075ac0b1fe3022fdc73/tqdm-4.66.5-py3-none-any.whl", hash = "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd", size = 78351 }, + { url = "https://files.pythonhosted.org/packages/2b/78/57043611a16c655c8350b4c01b8d6abfb38cc2acb475238b62c2146186d7/tqdm-4.67.0-py3-none-any.whl", hash = "sha256:0cd8af9d56911acab92182e88d763100d4788bdf421d251616040cc4d44863be", size = 78590 }, ] [[package]] diff --git a/libraries/python/skills/skills/document-skill/document_skill/document_skill.py b/libraries/python/skills/skills/document-skill/document_skill/document_skill.py index b57d8f21..8604bee1 100644 --- a/libraries/python/skills/skills/document-skill/document_skill/document_skill.py +++ b/libraries/python/skills/skills/document-skill/document_skill/document_skill.py @@ -1,4 +1,4 @@ -from chat_driver import ChatDriverConfig +from chat_driver import ChatDriverConfig, ContextProtocol from context import Context from pydantic import BaseModel # temp to have something to experiment with from skill_library import RoutineTypes, Skill @@ -41,7 +41,7 @@ def __init__(self) -> None: class DocumentSkill(Skill): def __init__( self, - context: Context, + context: ContextProtocol, chat_driver_config: ChatDriverConfig, ) -> None: self.document_skill_context: DocumentSkillContext = DocumentSkillContext() @@ -97,6 +97,7 @@ def test_instruction_routine(self) -> InstructionRoutine: name="test_instruction_routine", description="Description of what the routine does.", routine=("test_action"), + skill=self, ) def template_example_routine(self) -> ProgramRoutine: @@ -107,6 +108,7 @@ def template_example_routine(self) -> ProgramRoutine: name="template_example_routine", description="Description of what the routine does.", program=("TBD"), + skill=self, ) ################################## diff --git a/libraries/python/skills/skills/document-skill/uv.lock b/libraries/python/skills/skills/document-skill/uv.lock index 07901257..2a8ddd7d 100644 --- a/libraries/python/skills/skills/document-skill/uv.lock +++ b/libraries/python/skills/skills/document-skill/uv.lock @@ -122,6 +122,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d9/ab/6936e2663c47a926e0659437b9333ad87d1ff49b1375d239026e0a268eba/asgi_correlation_id-4.3.4-py3-none-any.whl", hash = "sha256:36ce69b06c7d96b4acb89c7556a4c4f01a972463d3d49c675026cbbd08e9a0a2", size = 15262 }, ] +[[package]] +name = "assistant-drive" +version = "0.1.0" +source = { editable = "../../../assistant-drive" } +dependencies = [ + { name = "context" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, +] + +[package.metadata] +requires-dist = [ + { name = "context", editable = "../../../context" }, + { name = "pydantic", specifier = ">=2.6.1" }, + { name = "pydantic-settings", specifier = ">=2.5.2" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "ipykernel", specifier = ">=6.29.5" }, + { name = "pytest", specifier = ">=8.3.1" }, + { name = "pytest-asyncio", specifier = ">=0.23.8" }, + { name = "pytest-repeat", specifier = ">=0.9.3" }, +] + [[package]] name = "attrs" version = "24.2.0" @@ -1409,6 +1434,7 @@ name = "skill-library" version = "0.1.0" source = { editable = "../../skill-library" } dependencies = [ + { name = "assistant-drive" }, { name = "chat-driver" }, { name = "context" }, { name = "events" }, @@ -1423,6 +1449,7 @@ dependencies = [ [package.metadata] requires-dist = [ + { name = "assistant-drive", editable = "../../../assistant-drive" }, { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, @@ -1435,6 +1462,13 @@ requires-dist = [ { name = "tiktoken", specifier = ">=0.7.0" }, ] +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.1" }, + { name = "pytest-asyncio", specifier = ">=0.23.8" }, + { name = "pytest-repeat", specifier = ">=0.9.3" }, +] + [[package]] name = "sniffio" version = "1.3.1" diff --git a/libraries/python/skills/skills/posix-skill/posix_skill/posix_skill.py b/libraries/python/skills/skills/posix-skill/posix_skill/posix_skill.py index 718c1500..0bb628e0 100644 --- a/libraries/python/skills/skills/posix-skill/posix_skill/posix_skill.py +++ b/libraries/python/skills/skills/posix-skill/posix_skill/posix_skill.py @@ -1,8 +1,10 @@ from pathlib import Path -from skill_library import Skill, InstructionRoutine, RoutineTypes + from chat_driver import ChatDriverConfig +from context import ContextProtocol +from skill_library import InstructionRoutine, RoutineTypes, Skill + from .sandbox_shell import SandboxShell -from context import Context NAME = "posix" CLASS_NAME = "PosixSkill" @@ -14,7 +16,7 @@ class PosixSkill(Skill): def __init__( self, - context: Context, + context: ContextProtocol, sandbox_dir: Path, chat_driver_config: ChatDriverConfig, mount_dir: str = "/mnt/data", @@ -78,13 +80,14 @@ def make_home_dir_routine(self) -> InstructionRoutine: "mkdir Pictures\n" "mkdir Videos\n" ), + skill=self, ) ################################## # Actions ################################## - def cd(self, context: Context, directory: str) -> str: + def cd(self, context: ContextProtocol, directory: str) -> str: """ Change the current working directory. """ @@ -94,60 +97,60 @@ def cd(self, context: Context, directory: str) -> str: except FileNotFoundError: return f"Directory {directory} not found." - def ls(self, context: Context, path: str = ".") -> list[str]: + def ls(self, context: ContextProtocol, path: str = ".") -> list[str]: """ List directory contents. """ return self.shell.ls(path) - def touch(self, context: Context, filename: str) -> str: + def touch(self, context: ContextProtocol, filename: str) -> str: """ Create an empty file. """ self.shell.touch(filename) return f"Created file {filename}." - def mkdir(self, context: Context, dirname: str) -> str: + def mkdir(self, context: ContextProtocol, dirname: str) -> str: """ Create a new directory. """ self.shell.mkdir(dirname) return f"Created directory {dirname}." - def mv(self, context: Context, src: str, dest: str) -> str: + def mv(self, context: ContextProtocol, src: str, dest: str) -> str: """ Move a file or directory. """ self.shell.mv(src, dest) return f"Moved {src} to {dest}." - def rm(self, context: Context, path: str) -> str: + def rm(self, context: ContextProtocol, path: str) -> str: """ Remove a file or directory. """ self.shell.rm(path) return f"Removed {path}." - def pwd(self, context: Context) -> str: + def pwd(self, context: ContextProtocol) -> str: """ Return the current directory. """ return self.shell.pwd() - def run_command(self, context: Context, command: str) -> str: + def run_command(self, context: ContextProtocol, command: str) -> str: """ Run a shell command in the current directory. """ stdout, stderr = self.shell.run_command(command) return f"Command output:\n{stdout}\nCommand errors:\n{stderr}" - def read_file(self, context: Context, filename: str) -> str: + def read_file(self, context: ContextProtocol, filename: str) -> str: """ Read the contents of a file. """ return self.shell.read_file(filename) - def write_file(self, context: Context, filename: str, content: str) -> str: + def write_file(self, context: ContextProtocol, filename: str, content: str) -> str: """ Write content to a file. """ diff --git a/libraries/python/skills/skills/posix-skill/uv.lock b/libraries/python/skills/skills/posix-skill/uv.lock index ef9776c5..ae772499 100644 --- a/libraries/python/skills/skills/posix-skill/uv.lock +++ b/libraries/python/skills/skills/posix-skill/uv.lock @@ -122,6 +122,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d9/ab/6936e2663c47a926e0659437b9333ad87d1ff49b1375d239026e0a268eba/asgi_correlation_id-4.3.4-py3-none-any.whl", hash = "sha256:36ce69b06c7d96b4acb89c7556a4c4f01a972463d3d49c675026cbbd08e9a0a2", size = 15262 }, ] +[[package]] +name = "assistant-drive" +version = "0.1.0" +source = { editable = "../../../assistant-drive" } +dependencies = [ + { name = "context" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, +] + +[package.metadata] +requires-dist = [ + { name = "context", editable = "../../../context" }, + { name = "pydantic", specifier = ">=2.6.1" }, + { name = "pydantic-settings", specifier = ">=2.5.2" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "ipykernel", specifier = ">=6.29.5" }, + { name = "pytest", specifier = ">=8.3.1" }, + { name = "pytest-asyncio", specifier = ">=0.23.8" }, + { name = "pytest-repeat", specifier = ">=0.9.3" }, +] + [[package]] name = "attrs" version = "24.2.0" @@ -1409,6 +1434,7 @@ name = "skill-library" version = "0.1.0" source = { editable = "../../skill-library" } dependencies = [ + { name = "assistant-drive" }, { name = "chat-driver" }, { name = "context" }, { name = "events" }, @@ -1423,6 +1449,7 @@ dependencies = [ [package.metadata] requires-dist = [ + { name = "assistant-drive", editable = "../../../assistant-drive" }, { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, @@ -1435,6 +1462,13 @@ requires-dist = [ { name = "tiktoken", specifier = ">=0.7.0" }, ] +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.1" }, + { name = "pytest-asyncio", specifier = ">=0.23.8" }, + { name = "pytest-repeat", specifier = ">=0.9.3" }, +] + [[package]] name = "sniffio" version = "1.3.1" diff --git a/libraries/python/skills/skills/prospector-skill/prospector_skill/skill.py b/libraries/python/skills/skills/prospector-skill/prospector_skill/skill.py index cc77eac9..70c4d143 100644 --- a/libraries/python/skills/skills/prospector-skill/prospector_skill/skill.py +++ b/libraries/python/skills/skills/prospector-skill/prospector_skill/skill.py @@ -1,5 +1,5 @@ from chat_driver import ChatDriverConfig -from context import Context +from context import ContextProtocol from skill_library import InstructionRoutine, RoutineTypes, Skill NAME = "prospector" @@ -12,7 +12,7 @@ class ProspectorSkill(Skill): def __init__( self, - context: Context, + context: ContextProtocol, chat_driver_config: ChatDriverConfig, ) -> None: # Add some actions. @@ -56,7 +56,8 @@ def draft_grant_proposal_routine(self) -> InstructionRoutine: return InstructionRoutine( "draft_grant_proposal", # name of routine "Draft a grant proposal.", # description of routine - routine=("gather_information_action\n" "create_draft_action\n"), + routine=("gather_information_action\ncreate_draft_action\n"), + skill=self, ) def example_routine(self) -> InstructionRoutine: @@ -66,32 +67,33 @@ def example_routine(self) -> InstructionRoutine: return InstructionRoutine( "template_example", # name of routine "Description of what the routine does.", - routine=("template_example_action\n" "template_example_with_parameters_action bar\n"), + routine=("template_example_action\ntemplate_example_with_parameters_action bar\n"), + skill=self, ) ################################## # Actions ################################## - def gather_information_action(self, context: Context) -> None: + def gather_information_action(self, context: ContextProtocol) -> None: """ Update this action description. """ pass - def create_draft_action(self, context: Context) -> None: + def create_draft_action(self, context: ContextProtocol) -> None: """ Update this action description. """ pass - def example_action(self, context: Context) -> None: + def example_action(self, context: ContextProtocol) -> None: """ Update this action description. """ pass - def example_with_parameters_action(self, context: Context, foo: str) -> None: + def example_with_parameters_action(self, context: ContextProtocol, foo: str) -> None: """ Update this action description. """ diff --git a/libraries/python/skills/skills/prospector-skill/uv.lock b/libraries/python/skills/skills/prospector-skill/uv.lock index ade64af0..fb7c57c0 100644 --- a/libraries/python/skills/skills/prospector-skill/uv.lock +++ b/libraries/python/skills/skills/prospector-skill/uv.lock @@ -122,6 +122,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d9/ab/6936e2663c47a926e0659437b9333ad87d1ff49b1375d239026e0a268eba/asgi_correlation_id-4.3.4-py3-none-any.whl", hash = "sha256:36ce69b06c7d96b4acb89c7556a4c4f01a972463d3d49c675026cbbd08e9a0a2", size = 15262 }, ] +[[package]] +name = "assistant-drive" +version = "0.1.0" +source = { editable = "../../../assistant-drive" } +dependencies = [ + { name = "context" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, +] + +[package.metadata] +requires-dist = [ + { name = "context", editable = "../../../context" }, + { name = "pydantic", specifier = ">=2.6.1" }, + { name = "pydantic-settings", specifier = ">=2.5.2" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "ipykernel", specifier = ">=6.29.5" }, + { name = "pytest", specifier = ">=8.3.1" }, + { name = "pytest-asyncio", specifier = ">=0.23.8" }, + { name = "pytest-repeat", specifier = ">=0.9.3" }, +] + [[package]] name = "attrs" version = "24.2.0" @@ -1409,6 +1434,7 @@ name = "skill-library" version = "0.1.0" source = { editable = "../../skill-library" } dependencies = [ + { name = "assistant-drive" }, { name = "chat-driver" }, { name = "context" }, { name = "events" }, @@ -1423,6 +1449,7 @@ dependencies = [ [package.metadata] requires-dist = [ + { name = "assistant-drive", editable = "../../../assistant-drive" }, { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, @@ -1435,6 +1462,13 @@ requires-dist = [ { name = "tiktoken", specifier = ">=0.7.0" }, ] +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.1" }, + { name = "pytest-asyncio", specifier = ">=0.23.8" }, + { name = "pytest-repeat", specifier = ">=0.9.3" }, +] + [[package]] name = "sniffio" version = "1.3.1" diff --git a/libraries/python/skills/skills/skill-template/uv.lock b/libraries/python/skills/skills/skill-template/uv.lock index 177ca9c6..bf6c6414 100644 --- a/libraries/python/skills/skills/skill-template/uv.lock +++ b/libraries/python/skills/skills/skill-template/uv.lock @@ -122,6 +122,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d9/ab/6936e2663c47a926e0659437b9333ad87d1ff49b1375d239026e0a268eba/asgi_correlation_id-4.3.4-py3-none-any.whl", hash = "sha256:36ce69b06c7d96b4acb89c7556a4c4f01a972463d3d49c675026cbbd08e9a0a2", size = 15262 }, ] +[[package]] +name = "assistant-drive" +version = "0.1.0" +source = { editable = "../../../assistant-drive" } +dependencies = [ + { name = "context" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, +] + +[package.metadata] +requires-dist = [ + { name = "context", editable = "../../../context" }, + { name = "pydantic", specifier = ">=2.6.1" }, + { name = "pydantic-settings", specifier = ">=2.5.2" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "ipykernel", specifier = ">=6.29.5" }, + { name = "pytest", specifier = ">=8.3.1" }, + { name = "pytest-asyncio", specifier = ">=0.23.8" }, + { name = "pytest-repeat", specifier = ">=0.9.3" }, +] + [[package]] name = "attrs" version = "24.2.0" @@ -1390,6 +1415,7 @@ name = "skill-library" version = "0.1.0" source = { editable = "../../skill-library" } dependencies = [ + { name = "assistant-drive" }, { name = "chat-driver" }, { name = "context" }, { name = "events" }, @@ -1404,6 +1430,7 @@ dependencies = [ [package.metadata] requires-dist = [ + { name = "assistant-drive", editable = "../../../assistant-drive" }, { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, @@ -1416,6 +1443,13 @@ requires-dist = [ { name = "tiktoken", specifier = ">=0.7.0" }, ] +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.1" }, + { name = "pytest-asyncio", specifier = ">=0.23.8" }, + { name = "pytest-repeat", specifier = ">=0.9.3" }, +] + [[package]] name = "sniffio" version = "1.3.1" diff --git a/libraries/python/skills/skills/skill-template/your_skill/skill.py b/libraries/python/skills/skills/skill-template/your_skill/skill.py index cccdd4b8..1a7f1b22 100644 --- a/libraries/python/skills/skills/skill-template/your_skill/skill.py +++ b/libraries/python/skills/skills/skill-template/your_skill/skill.py @@ -1,5 +1,5 @@ from chat_driver import ChatDriverConfig -from context import Context +from context import ContextProtocol from skill_library import InstructionRoutine, RoutineTypes, Skill NAME = "your" @@ -12,7 +12,7 @@ class YourSkill(Skill): def __init__( self, - context: Context, + context: ContextProtocol, chat_driver_config: ChatDriverConfig, ) -> None: # Add some actions. @@ -53,20 +53,21 @@ def example_routine(self) -> InstructionRoutine: return InstructionRoutine( "template_example", # name of routine "Description of what the routine does.", - routine=("template_example_action\n" "template_example_with_parameters_action bar\n"), + routine=("template_example_action\ntemplate_example_with_parameters_action bar\n"), + skill=self, ) ################################## # Actions ################################## - def example_action(self, context: Context) -> None: + def example_action(self, context: ContextProtocol) -> None: """ Update this action description. """ pass - def example_with_parameters_action(self, context: Context, foo: str) -> None: + def example_with_parameters_action(self, context: ContextProtocol, foo: str) -> None: """ Update this action description. """ From c7b2b12915c28b875cf9ee385bb8d2a32f3dfebd Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Fri, 25 Oct 2024 22:58:53 +0000 Subject: [PATCH 03/14] Adds chat driver in-memory history and liquid templates. --- .../local_message_history_provider.py | 28 +--- .../tests/formatted_instructions_test.py | 76 +++++++++ libraries/python/chat-driver/uv.lock | 151 ++++++++++-------- 3 files changed, 165 insertions(+), 90 deletions(-) create mode 100644 libraries/python/chat-driver/chat_driver/tests/formatted_instructions_test.py diff --git a/libraries/python/chat-driver/chat_driver/local_message_history_provider.py b/libraries/python/chat-driver/chat_driver/local_message_history_provider.py index ffa82045..d16d1889 100644 --- a/libraries/python/chat-driver/chat_driver/local_message_history_provider.py +++ b/libraries/python/chat-driver/chat_driver/local_message_history_provider.py @@ -2,20 +2,13 @@ from dataclasses import dataclass, field from os import PathLike from pathlib import Path -from typing import Any, Iterable +from typing import Any from context.context import ContextProtocol from openai.types.chat import ( ChatCompletionMessageParam, - ChatCompletionMessageToolCallParam, -) -from openai_client.messages import ( - MessageFormatter, - create_assistant_message, - create_system_message, - create_user_message, - format_with_dict, ) +from openai_client.messages import MessageFormatter, format_with_liquid from .message_history_provider import MessageHistoryProviderProtocol @@ -36,7 +29,7 @@ def __init__(self, config: LocalMessageHistoryProviderConfig) -> None: self.data_dir = DEFAULT_DATA_DIR / "chat_driver" / config.context.session_id else: self.data_dir = Path(config.data_dir) - self.formatter: MessageFormatter = config.formatter or format_with_dict + self.formatter = config.formatter or format_with_liquid # Create the messages file if it doesn't exist. if not self.data_dir.exists(): @@ -77,18 +70,3 @@ async def set(self, messages: list[ChatCompletionMessageParam], vars: dict[str, def delete_all(self) -> None: self.messages_file.write_text("[]") - - async def append_system_message(self, content: str, var: dict[str, Any] | None = None) -> None: - await self.append(create_system_message(content, var, self.formatter)) - - async def append_user_message(self, content: str, var: dict[str, Any] | None = None) -> None: - await self.append(create_user_message(content, var, self.formatter)) - - async def append_assistant_message( - self, - content: str, - refusal: str, - tool_calls: Iterable[ChatCompletionMessageToolCallParam] | None = None, - var: dict[str, Any] | None = None, - ) -> None: - await self.append(create_assistant_message(content, refusal, tool_calls, var, self.formatter)) diff --git a/libraries/python/chat-driver/chat_driver/tests/formatted_instructions_test.py b/libraries/python/chat-driver/chat_driver/tests/formatted_instructions_test.py new file mode 100644 index 00000000..0f9aad88 --- /dev/null +++ b/libraries/python/chat-driver/chat_driver/tests/formatted_instructions_test.py @@ -0,0 +1,76 @@ +from typing import Any + +from chat_driver.chat_driver import ChatDriver +from liquid import Template + + +def format_message(message: str, vars: dict[str, Any]) -> str: + """ + Format a message with the given variables. + """ + out = message + if not message: + return message + template = Template(message) + out = template.render(**vars) + return out + + +def test_formatted_instructions() -> None: + # Set instructions. + instructions = [ + ( + "Generate an outline for the document, including title. The outline should include the key points that will" + " be covered in the document. Consider the attachments, the rationale for why they were uploaded, and the" + " conversation that has taken place. The outline should be a hierarchical structure with multiple levels of" + " detail, and it should be clear and easy to understand. The outline should be generated in a way that is" + " consistent with the document that will be generated from it." + ), + "{{chat_history}}", + "{% for attachment in attachments %}{{attachment.filename}}{{attachment.content}}{% endfor %}", + "{{outline_versions.last}}", + "{{user_feedback}}", + ] + + # Set vars. + attachments = [ + {"filename": "filename1", "content": "content1"}, + {"filename": "filename2", "content": "content2"}, + ] + outline_versions = ["outline1", "outline2"] + user_feedback = "feedback" + chat_history = "history" + formatted_instructions = ChatDriver.format_instructions( + instructions=instructions, + vars={ + "attachments": attachments, + "outline_versions": outline_versions, + "user_feedback": user_feedback, + "chat_history": chat_history, + }, + formatter=format_message, + ) + + expected = [ + { + "role": "system", + "content": "Generate an outline for the document, including title. The outline should include the key points that will be covered in the document. Consider the attachments, the rationale for why they were uploaded, and the conversation that has taken place. The outline should be a hierarchical structure with multiple levels of detail, and it should be clear and easy to understand. The outline should be generated in a way that is consistent with the document that will be generated from it.", + }, + {"role": "system", "content": "history"}, + # { + # "role": "system", + # "content": "filename1content1", + # }, + # { + # "role": "system", + # "content": "filename2content2", + # }, + { + "role": "system", + "content": "filename1content1filename2content2", + }, + {"role": "system", "content": "outline2"}, + {"role": "system", "content": "feedback"}, + ] + + assert formatted_instructions == expected diff --git a/libraries/python/chat-driver/uv.lock b/libraries/python/chat-driver/uv.lock index d185b278..f471be1f 100644 --- a/libraries/python/chat-driver/uv.lock +++ b/libraries/python/chat-driver/uv.lock @@ -98,13 +98,13 @@ wheels = [ [[package]] name = "anyio" -version = "4.6.0" +version = "4.6.2.post1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "sniffio" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/78/49/f3f17ec11c4a91fe79275c426658e509b07547f874b14c1a526d86a83fc8/anyio-4.6.0.tar.gz", hash = "sha256:137b4559cbb034c477165047febb6ff83f390fc3b20bf181c1fc0a728cb8beeb", size = 170983 } +sdist = { url = "https://files.pythonhosted.org/packages/9f/09/45b9b7a6d4e45c6bcb5bf61d19e3ab87df68e0601fa8c5293de3542546cc/anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c", size = 173422 } wheels = [ { url = "https://files.pythonhosted.org/packages/9e/ef/7a4f225581a0d7886ea28359179cb861d7fbcdefad29663fc1167b86f69f/anyio-4.6.0-py3-none-any.whl", hash = "sha256:c7d2e9d63e31599eeb636c8c5c03a7e108d73b345f064f1c19fdc87b79036a9a", size = 89631 }, ] @@ -165,7 +165,7 @@ aio = [ [[package]] name = "azure-identity" -version = "1.18.0" +version = "1.19.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "azure-core" }, @@ -174,7 +174,7 @@ dependencies = [ { name = "msal-extensions" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b3/5d/1c7da35dd640b4a95a38f980bb6b0b56c4e91d5b3d518ac11a2c4ebf5f62/azure_identity-1.18.0.tar.gz", hash = "sha256:f567579a65d8932fa913c76eddf3305101a15e5727a5e4aa5df649a0f553d4c3", size = 263322 } +sdist = { url = "https://files.pythonhosted.org/packages/aa/91/cbaeff9eb0b838f0d35b4607ac1c6195c735c8eb17db235f8f60e622934c/azure_identity-1.19.0.tar.gz", hash = "sha256:500144dc18197d7019b81501165d4fa92225f03778f17d7ca8a2a180129a9c83", size = 263058 } wheels = [ { url = "https://files.pythonhosted.org/packages/b0/71/1d1bb387b6acaa5daa3e703c70dde3d54823ccd229bd6730de6e724f296e/azure_identity-1.18.0-py3-none-any.whl", hash = "sha256:bccf6106245b49ff41d0c4cd7b72851c5a2ba3a32cef7589da246f5727f26f02", size = 187179 }, ] @@ -244,41 +244,56 @@ wheels = [ [[package]] name = "charset-normalizer" -version = "3.3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/63/09/c1bc53dab74b1816a00d8d030de5bf98f724c52c1635e07681d312f20be8/charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", size = 104809 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/77/02839016f6fbbf808e8b38601df6e0e66c17bbab76dff4613f7511413597/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", size = 191647 }, - { url = "https://files.pythonhosted.org/packages/3e/33/21a875a61057165e92227466e54ee076b73af1e21fe1b31f1e292251aa1e/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", size = 121434 }, - { url = "https://files.pythonhosted.org/packages/dd/51/68b61b90b24ca35495956b718f35a9756ef7d3dd4b3c1508056fa98d1a1b/charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", size = 118979 }, - { url = "https://files.pythonhosted.org/packages/e4/a6/7ee57823d46331ddc37dd00749c95b0edec2c79b15fc0d6e6efb532e89ac/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", size = 136582 }, - { url = "https://files.pythonhosted.org/packages/74/f1/0d9fe69ac441467b737ba7f48c68241487df2f4522dd7246d9426e7c690e/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", size = 146645 }, - { url = "https://files.pythonhosted.org/packages/05/31/e1f51c76db7be1d4aef220d29fbfa5dbb4a99165d9833dcbf166753b6dc0/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", size = 139398 }, - { url = "https://files.pythonhosted.org/packages/40/26/f35951c45070edc957ba40a5b1db3cf60a9dbb1b350c2d5bef03e01e61de/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", size = 140273 }, - { url = "https://files.pythonhosted.org/packages/07/07/7e554f2bbce3295e191f7e653ff15d55309a9ca40d0362fcdab36f01063c/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", size = 142577 }, - { url = "https://files.pythonhosted.org/packages/d8/b5/eb705c313100defa57da79277d9207dc8d8e45931035862fa64b625bfead/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", size = 137747 }, - { url = "https://files.pythonhosted.org/packages/19/28/573147271fd041d351b438a5665be8223f1dd92f273713cb882ddafe214c/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", size = 143375 }, - { url = "https://files.pythonhosted.org/packages/cf/7c/f3b682fa053cc21373c9a839e6beba7705857075686a05c72e0f8c4980ca/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", size = 148474 }, - { url = "https://files.pythonhosted.org/packages/1e/49/7ab74d4ac537ece3bc3334ee08645e231f39f7d6df6347b29a74b0537103/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", size = 140232 }, - { url = "https://files.pythonhosted.org/packages/2d/dc/9dacba68c9ac0ae781d40e1a0c0058e26302ea0660e574ddf6797a0347f7/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", size = 140859 }, - { url = "https://files.pythonhosted.org/packages/6c/c2/4a583f800c0708dd22096298e49f887b49d9746d0e78bfc1d7e29816614c/charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", size = 92509 }, - { url = "https://files.pythonhosted.org/packages/57/ec/80c8d48ac8b1741d5b963797b7c0c869335619e13d4744ca2f67fc11c6fc/charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", size = 99870 }, - { url = "https://files.pythonhosted.org/packages/d1/b2/fcedc8255ec42afee97f9e6f0145c734bbe104aac28300214593eb326f1d/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", size = 192892 }, - { url = "https://files.pythonhosted.org/packages/2e/7d/2259318c202f3d17f3fe6438149b3b9e706d1070fe3fcbb28049730bb25c/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", size = 122213 }, - { url = "https://files.pythonhosted.org/packages/3a/52/9f9d17c3b54dc238de384c4cb5a2ef0e27985b42a0e5cc8e8a31d918d48d/charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", size = 119404 }, - { url = "https://files.pythonhosted.org/packages/99/b0/9c365f6d79a9f0f3c379ddb40a256a67aa69c59609608fe7feb6235896e1/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", size = 137275 }, - { url = "https://files.pythonhosted.org/packages/91/33/749df346e93d7a30cdcb90cbfdd41a06026317bfbfb62cd68307c1a3c543/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", size = 147518 }, - { url = "https://files.pythonhosted.org/packages/72/1a/641d5c9f59e6af4c7b53da463d07600a695b9824e20849cb6eea8a627761/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", size = 140182 }, - { url = "https://files.pythonhosted.org/packages/ee/fb/14d30eb4956408ee3ae09ad34299131fb383c47df355ddb428a7331cfa1e/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", size = 141869 }, - { url = "https://files.pythonhosted.org/packages/df/3e/a06b18788ca2eb6695c9b22325b6fde7dde0f1d1838b1792a0076f58fe9d/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", size = 144042 }, - { url = "https://files.pythonhosted.org/packages/45/59/3d27019d3b447a88fe7e7d004a1e04be220227760264cc41b405e863891b/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", size = 138275 }, - { url = "https://files.pythonhosted.org/packages/7b/ef/5eb105530b4da8ae37d506ccfa25057961b7b63d581def6f99165ea89c7e/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", size = 144819 }, - { url = "https://files.pythonhosted.org/packages/a2/51/e5023f937d7f307c948ed3e5c29c4b7a3e42ed2ee0b8cdf8f3a706089bf0/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", size = 149415 }, - { url = "https://files.pythonhosted.org/packages/24/9d/2e3ef673dfd5be0154b20363c5cdcc5606f35666544381bee15af3778239/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", size = 141212 }, - { url = "https://files.pythonhosted.org/packages/5b/ae/ce2c12fcac59cb3860b2e2d76dc405253a4475436b1861d95fe75bdea520/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", size = 142167 }, - { url = "https://files.pythonhosted.org/packages/ed/3a/a448bf035dce5da359daf9ae8a16b8a39623cc395a2ffb1620aa1bce62b0/charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", size = 93041 }, - { url = "https://files.pythonhosted.org/packages/b6/7c/8debebb4f90174074b827c63242c23851bdf00a532489fba57fef3416e40/charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", size = 100397 }, - { url = "https://files.pythonhosted.org/packages/28/76/e6222113b83e3622caa4bb41032d0b1bf785250607392e1b778aca0b8a7d/charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", size = 48543 }, +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/4f/e1808dc01273379acc506d18f1504eb2d299bd4131743b9fc54d7be4df1e/charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", size = 106620 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/61/73589dcc7a719582bf56aae309b6103d2762b526bffe189d635a7fcfd998/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c", size = 193339 }, + { url = "https://files.pythonhosted.org/packages/77/d5/8c982d58144de49f59571f940e329ad6e8615e1e82ef84584c5eeb5e1d72/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944", size = 124366 }, + { url = "https://files.pythonhosted.org/packages/bf/19/411a64f01ee971bed3231111b69eb56f9331a769072de479eae7de52296d/charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee", size = 118874 }, + { url = "https://files.pythonhosted.org/packages/4c/92/97509850f0d00e9f14a46bc751daabd0ad7765cff29cdfb66c68b6dad57f/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c", size = 138243 }, + { url = "https://files.pythonhosted.org/packages/e2/29/d227805bff72ed6d6cb1ce08eec707f7cfbd9868044893617eb331f16295/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6", size = 148676 }, + { url = "https://files.pythonhosted.org/packages/13/bc/87c2c9f2c144bedfa62f894c3007cd4530ba4b5351acb10dc786428a50f0/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea", size = 141289 }, + { url = "https://files.pythonhosted.org/packages/eb/5b/6f10bad0f6461fa272bfbbdf5d0023b5fb9bc6217c92bf068fa5a99820f5/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc", size = 142585 }, + { url = "https://files.pythonhosted.org/packages/3b/a0/a68980ab8a1f45a36d9745d35049c1af57d27255eff8c907e3add84cf68f/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5", size = 144408 }, + { url = "https://files.pythonhosted.org/packages/d7/a1/493919799446464ed0299c8eef3c3fad0daf1c3cd48bff9263c731b0d9e2/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594", size = 139076 }, + { url = "https://files.pythonhosted.org/packages/fb/9d/9c13753a5a6e0db4a0a6edb1cef7aee39859177b64e1a1e748a6e3ba62c2/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c", size = 146874 }, + { url = "https://files.pythonhosted.org/packages/75/d2/0ab54463d3410709c09266dfb416d032a08f97fd7d60e94b8c6ef54ae14b/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365", size = 150871 }, + { url = "https://files.pythonhosted.org/packages/8d/c9/27e41d481557be53d51e60750b85aa40eaf52b841946b3cdeff363105737/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129", size = 148546 }, + { url = "https://files.pythonhosted.org/packages/ee/44/4f62042ca8cdc0cabf87c0fc00ae27cd8b53ab68be3605ba6d071f742ad3/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236", size = 143048 }, + { url = "https://files.pythonhosted.org/packages/01/f8/38842422988b795220eb8038745d27a675ce066e2ada79516c118f291f07/charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99", size = 94389 }, + { url = "https://files.pythonhosted.org/packages/0b/6e/b13bd47fa9023b3699e94abf565b5a2f0b0be6e9ddac9812182596ee62e4/charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27", size = 101752 }, + { url = "https://files.pythonhosted.org/packages/d3/0b/4b7a70987abf9b8196845806198975b6aab4ce016632f817ad758a5aa056/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6", size = 194445 }, + { url = "https://files.pythonhosted.org/packages/50/89/354cc56cf4dd2449715bc9a0f54f3aef3dc700d2d62d1fa5bbea53b13426/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf", size = 125275 }, + { url = "https://files.pythonhosted.org/packages/fa/44/b730e2a2580110ced837ac083d8ad222343c96bb6b66e9e4e706e4d0b6df/charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db", size = 119020 }, + { url = "https://files.pythonhosted.org/packages/9d/e4/9263b8240ed9472a2ae7ddc3e516e71ef46617fe40eaa51221ccd4ad9a27/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1", size = 139128 }, + { url = "https://files.pythonhosted.org/packages/6b/e3/9f73e779315a54334240353eaea75854a9a690f3f580e4bd85d977cb2204/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03", size = 149277 }, + { url = "https://files.pythonhosted.org/packages/1a/cf/f1f50c2f295312edb8a548d3fa56a5c923b146cd3f24114d5adb7e7be558/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284", size = 142174 }, + { url = "https://files.pythonhosted.org/packages/16/92/92a76dc2ff3a12e69ba94e7e05168d37d0345fa08c87e1fe24d0c2a42223/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15", size = 143838 }, + { url = "https://files.pythonhosted.org/packages/a4/01/2117ff2b1dfc61695daf2babe4a874bca328489afa85952440b59819e9d7/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8", size = 146149 }, + { url = "https://files.pythonhosted.org/packages/f6/9b/93a332b8d25b347f6839ca0a61b7f0287b0930216994e8bf67a75d050255/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2", size = 140043 }, + { url = "https://files.pythonhosted.org/packages/ab/f6/7ac4a01adcdecbc7a7587767c776d53d369b8b971382b91211489535acf0/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719", size = 148229 }, + { url = "https://files.pythonhosted.org/packages/9d/be/5708ad18161dee7dc6a0f7e6cf3a88ea6279c3e8484844c0590e50e803ef/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631", size = 151556 }, + { url = "https://files.pythonhosted.org/packages/5a/bb/3d8bc22bacb9eb89785e83e6723f9888265f3a0de3b9ce724d66bd49884e/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b", size = 149772 }, + { url = "https://files.pythonhosted.org/packages/f7/fa/d3fc622de05a86f30beea5fc4e9ac46aead4731e73fd9055496732bcc0a4/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", size = 144800 }, + { url = "https://files.pythonhosted.org/packages/9a/65/bdb9bc496d7d190d725e96816e20e2ae3a6fa42a5cac99c3c3d6ff884118/charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", size = 94836 }, + { url = "https://files.pythonhosted.org/packages/3e/67/7b72b69d25b89c0b3cea583ee372c43aa24df15f0e0f8d3982c57804984b/charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", size = 102187 }, + { url = "https://files.pythonhosted.org/packages/f3/89/68a4c86f1a0002810a27f12e9a7b22feb198c59b2f05231349fbce5c06f4/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", size = 194617 }, + { url = "https://files.pythonhosted.org/packages/4f/cd/8947fe425e2ab0aa57aceb7807af13a0e4162cd21eee42ef5b053447edf5/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", size = 125310 }, + { url = "https://files.pythonhosted.org/packages/5b/f0/b5263e8668a4ee9becc2b451ed909e9c27058337fda5b8c49588183c267a/charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", size = 119126 }, + { url = "https://files.pythonhosted.org/packages/ff/6e/e445afe4f7fda27a533f3234b627b3e515a1b9429bc981c9a5e2aa5d97b6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", size = 139342 }, + { url = "https://files.pythonhosted.org/packages/a1/b2/4af9993b532d93270538ad4926c8e37dc29f2111c36f9c629840c57cd9b3/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", size = 149383 }, + { url = "https://files.pythonhosted.org/packages/fb/6f/4e78c3b97686b871db9be6f31d64e9264e889f8c9d7ab33c771f847f79b7/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", size = 142214 }, + { url = "https://files.pythonhosted.org/packages/2b/c9/1c8fe3ce05d30c87eff498592c89015b19fade13df42850aafae09e94f35/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", size = 144104 }, + { url = "https://files.pythonhosted.org/packages/ee/68/efad5dcb306bf37db7db338338e7bb8ebd8cf38ee5bbd5ceaaaa46f257e6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", size = 146255 }, + { url = "https://files.pythonhosted.org/packages/0c/75/1ed813c3ffd200b1f3e71121c95da3f79e6d2a96120163443b3ad1057505/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", size = 140251 }, + { url = "https://files.pythonhosted.org/packages/7d/0d/6f32255c1979653b448d3c709583557a4d24ff97ac4f3a5be156b2e6a210/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", size = 148474 }, + { url = "https://files.pythonhosted.org/packages/ac/a0/c1b5298de4670d997101fef95b97ac440e8c8d8b4efa5a4d1ef44af82f0d/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", size = 151849 }, + { url = "https://files.pythonhosted.org/packages/04/4f/b3961ba0c664989ba63e30595a3ed0875d6790ff26671e2aae2fdc28a399/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", size = 149781 }, + { url = "https://files.pythonhosted.org/packages/d8/90/6af4cd042066a4adad58ae25648a12c09c879efa4849c705719ba1b23d8c/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482", size = 144970 }, + { url = "https://files.pythonhosted.org/packages/cc/67/e5e7e0cbfefc4ca79025238b43cdf8a2037854195b37d6417f3d0895c4c2/charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", size = 94973 }, + { url = "https://files.pythonhosted.org/packages/65/97/fc9bbc54ee13d33dc54a7fcf17b26368b18505500fc01e228c27b5222d80/charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", size = 102308 }, + { url = "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", size = 49446 }, ] [[package]] @@ -295,6 +310,7 @@ dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, + { name = "python-liquid" }, { name = "requests" }, { name = "tiktoken" }, ] @@ -310,6 +326,7 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, + { name = "python-liquid", specifier = ">=1.12.1" }, { name = "requests", specifier = ">=2.32.0" }, { name = "tiktoken", specifier = ">=0.7.0" }, ] @@ -355,12 +372,12 @@ dev = [ [[package]] name = "cryptography" -version = "43.0.1" +version = "43.0.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/de/ba/0664727028b37e249e73879348cc46d45c5c1a2a2e81e8166462953c5755/cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d", size = 686927 } +sdist = { url = "https://files.pythonhosted.org/packages/0d/05/07b55d1fa21ac18c3a8c79f764e2514e6f6a9698f1be44994f5adf0d29db/cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805", size = 686989 } wheels = [ { url = "https://files.pythonhosted.org/packages/58/28/b92c98a04ba762f8cdeb54eba5c4c84e63cac037a7c5e70117d337b15ad6/cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d", size = 6223222 }, { url = "https://files.pythonhosted.org/packages/33/13/1193774705783ba364121aa2a60132fa31a668b8ababd5edfa1662354ccd/cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062", size = 3794751 }, @@ -671,9 +688,9 @@ wheels = [ [[package]] name = "jiter" -version = "0.5.0" +version = "0.6.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/1a/aa64be757afc614484b370a4d9fc1747dc9237b37ce464f7f9d9ca2a3d38/jiter-0.5.0.tar.gz", hash = "sha256:1d916ba875bcab5c5f7d927df998c4cb694d27dceddf3392e58beaf10563368a", size = 158300 } +sdist = { url = "https://files.pythonhosted.org/packages/26/ef/64458dfad180debd70d9dd1ca4f607e52bb6de748e5284d748556a0d5173/jiter-0.6.1.tar.gz", hash = "sha256:e19cd21221fc139fb032e4112986656cb2739e9fe6d84c13956ab30ccc7d4449", size = 161306 } wheels = [ { url = "https://files.pythonhosted.org/packages/94/5f/3ac960ed598726aae46edea916e6df4df7ff6fe084bc60774b95cf3154e6/jiter-0.5.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d4c8e1ed0ef31ad29cae5ea16b9e41529eb50a7fba70600008e9f8de6376d553", size = 284131 }, { url = "https://files.pythonhosted.org/packages/03/eb/2308fa5f5c14c97c4c7720fef9465f1fa0771826cddb4eec9866bdd88846/jiter-0.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6f16e21276074a12d8421692515b3fd6d2ea9c94fd0734c39a12960a20e85f3", size = 299310 }, @@ -853,7 +870,7 @@ wheels = [ [[package]] name = "openai" -version = "1.51.0" +version = "1.52.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -865,7 +882,7 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/28/af/cc59b1447f5a02bb1f25b9b0cd94b607aa2c969a81d9a244d4067f91f6fe/openai-1.51.0.tar.gz", hash = "sha256:8dc4f9d75ccdd5466fc8c99a952186eddceb9fd6ba694044773f3736a847149d", size = 306880 } +sdist = { url = "https://files.pythonhosted.org/packages/80/ac/54c76352d493866637756b7c0ecec44f0b5bafb8fe753d98472cf6cfe4ce/openai-1.52.1.tar.gz", hash = "sha256:383b96c7e937cbec23cad5bf5718085381e4313ca33c5c5896b54f8e1b19d144", size = 310069 } wheels = [ { url = "https://files.pythonhosted.org/packages/c7/08/9f22356d4fbd273f734db1e6663b7ca6987943080567f5580471022e57ca/openai-1.51.0-py3-none-any.whl", hash = "sha256:d9affafb7e51e5a27dce78589d4964ce4d6f6d560307265933a94b2e3f3c5d2c", size = 383533 }, ] @@ -1101,13 +1118,13 @@ wheels = [ [[package]] name = "pydantic-settings" -version = "2.5.2" +version = "2.6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/68/27/0bed9dd26b93328b60a1402febc780e7be72b42847fa8b5c94b7d0aeb6d1/pydantic_settings-2.5.2.tar.gz", hash = "sha256:f90b139682bee4d2065273d5185d71d37ea46cfe57e1b5ae184fc6a0b2484ca0", size = 70938 } +sdist = { url = "https://files.pythonhosted.org/packages/6c/66/5f1a9da10675bfb3b9da52f5b689c77e0a5612263fcce510cfac3e99a168/pydantic_settings-2.6.0.tar.gz", hash = "sha256:44a1804abffac9e6a30372bb45f6cafab945ef5af25e66b1c634c01dd39e0188", size = 75232 } wheels = [ { url = "https://files.pythonhosted.org/packages/29/8d/29e82e333f32d9e2051c10764b906c2a6cd140992910b5f49762790911ba/pydantic_settings-2.5.2-py3-none-any.whl", hash = "sha256:2c912e55fd5794a59bf8c832b9de832dcfdf4778d79ff79b708744eed499a907", size = 26864 }, ] @@ -1190,7 +1207,7 @@ wheels = [ [[package]] name = "pywin32" -version = "306" +version = "308" source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/8b/1e/fc18ad83ca553e01b97aa8393ff10e33c1fb57801db05488b83282ee9913/pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407", size = 8507689 }, @@ -1408,28 +1425,32 @@ wheels = [ [[package]] name = "tiktoken" -version = "0.7.0" +version = "0.8.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "regex" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c4/4a/abaec53e93e3ef37224a4dd9e2fc6bb871e7a538c2b6b9d2a6397271daf4/tiktoken-0.7.0.tar.gz", hash = "sha256:1077266e949c24e0291f6c350433c6f0971365ece2b173a23bc3b9f9defef6b6", size = 33437 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/eb/57492b2568eea1d546da5cc1ae7559d924275280db80ba07e6f9b89a914b/tiktoken-0.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:10c7674f81e6e350fcbed7c09a65bca9356eaab27fb2dac65a1e440f2bcfe30f", size = 961468 }, - { url = "https://files.pythonhosted.org/packages/30/ef/e07dbfcb2f85c84abaa1b035a9279575a8da0236305491dc22ae099327f7/tiktoken-0.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:084cec29713bc9d4189a937f8a35dbdfa785bd1235a34c1124fe2323821ee93f", size = 907005 }, - { url = "https://files.pythonhosted.org/packages/ea/9b/f36db825b1e9904c3a2646439cb9923fc1e09208e2e071c6d9dd64ead131/tiktoken-0.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:811229fde1652fedcca7c6dfe76724d0908775b353556d8a71ed74d866f73f7b", size = 1049183 }, - { url = "https://files.pythonhosted.org/packages/61/b4/b80d1fe33015e782074e96bbbf4108ccd283b8deea86fb43c15d18b7c351/tiktoken-0.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86b6e7dc2e7ad1b3757e8a24597415bafcfb454cebf9a33a01f2e6ba2e663992", size = 1080830 }, - { url = "https://files.pythonhosted.org/packages/2a/40/c66ff3a21af6d62a7e0ff428d12002c4e0389f776d3ff96dcaa0bb354eee/tiktoken-0.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1063c5748be36344c7e18c7913c53e2cca116764c2080177e57d62c7ad4576d1", size = 1092967 }, - { url = "https://files.pythonhosted.org/packages/2e/80/f4c9e255ff236e6a69ce44b927629cefc1b63d3a00e2d1c9ed540c9492d2/tiktoken-0.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:20295d21419bfcca092644f7e2f2138ff947a6eb8cfc732c09cc7d76988d4a89", size = 1142682 }, - { url = "https://files.pythonhosted.org/packages/b1/10/c04b4ff592a5f46b28ebf4c2353f735c02ae7f0ce1b165d00748ced6467e/tiktoken-0.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:959d993749b083acc57a317cbc643fb85c014d055b2119b739487288f4e5d1cb", size = 799009 }, - { url = "https://files.pythonhosted.org/packages/1d/46/4cdda4186ce900608f522da34acf442363346688c71b938a90a52d7b84cc/tiktoken-0.7.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:71c55d066388c55a9c00f61d2c456a6086673ab7dec22dd739c23f77195b1908", size = 960446 }, - { url = "https://files.pythonhosted.org/packages/b6/30/09ced367d280072d7a3e21f34263dfbbf6378661e7a0f6414e7c18971083/tiktoken-0.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:09ed925bccaa8043e34c519fbb2f99110bd07c6fd67714793c21ac298e449410", size = 906652 }, - { url = "https://files.pythonhosted.org/packages/e6/7b/c949e4954441a879a67626963dff69096e3c774758b9f2bb0853f7b4e1e7/tiktoken-0.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03c6c40ff1db0f48a7b4d2dafeae73a5607aacb472fa11f125e7baf9dce73704", size = 1047904 }, - { url = "https://files.pythonhosted.org/packages/50/81/1842a22f15586072280364c2ab1e40835adaf64e42fe80e52aff921ee021/tiktoken-0.7.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d20b5c6af30e621b4aca094ee61777a44118f52d886dbe4f02b70dfe05c15350", size = 1079836 }, - { url = "https://files.pythonhosted.org/packages/6d/87/51a133a3d5307cf7ae3754249b0faaa91d3414b85c3d36f80b54d6817aa6/tiktoken-0.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d427614c3e074004efa2f2411e16c826f9df427d3c70a54725cae860f09e4bf4", size = 1092472 }, - { url = "https://files.pythonhosted.org/packages/a5/1f/c93517dc6d3b2c9e988b8e24f87a8b2d4a4ab28920a3a3f3ea338397ae0c/tiktoken-0.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8c46d7af7b8c6987fac9b9f61041b452afe92eb087d29c9ce54951280f899a97", size = 1141881 }, - { url = "https://files.pythonhosted.org/packages/bf/4b/48ca098cb580c099b5058bf62c4cb5e90ca6130fa43ef4df27088536245b/tiktoken-0.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:0bc603c30b9e371e7c4c7935aba02af5994a909fc3c0fe66e7004070858d3f8f", size = 799281 }, +sdist = { url = "https://files.pythonhosted.org/packages/37/02/576ff3a6639e755c4f70997b2d315f56d6d71e0d046f4fb64cb81a3fb099/tiktoken-0.8.0.tar.gz", hash = "sha256:9ccbb2740f24542534369c5635cfd9b2b3c2490754a78ac8831d99f89f94eeb2", size = 35107 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/1e/ca48e7bfeeccaf76f3a501bd84db1fa28b3c22c9d1a1f41af9fb7579c5f6/tiktoken-0.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d622d8011e6d6f239297efa42a2657043aaed06c4f68833550cac9e9bc723ef1", size = 1039700 }, + { url = "https://files.pythonhosted.org/packages/8c/f8/f0101d98d661b34534769c3818f5af631e59c36ac6d07268fbfc89e539ce/tiktoken-0.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2efaf6199717b4485031b4d6edb94075e4d79177a172f38dd934d911b588d54a", size = 982413 }, + { url = "https://files.pythonhosted.org/packages/ac/3c/2b95391d9bd520a73830469f80a96e3790e6c0a5ac2444f80f20b4b31051/tiktoken-0.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5637e425ce1fc49cf716d88df3092048359a4b3bbb7da762840426e937ada06d", size = 1144242 }, + { url = "https://files.pythonhosted.org/packages/01/c4/c4a4360de845217b6aa9709c15773484b50479f36bb50419c443204e5de9/tiktoken-0.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fb0e352d1dbe15aba082883058b3cce9e48d33101bdaac1eccf66424feb5b47", size = 1176588 }, + { url = "https://files.pythonhosted.org/packages/f8/a3/ef984e976822cd6c2227c854f74d2e60cf4cd6fbfca46251199914746f78/tiktoken-0.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:56edfefe896c8f10aba372ab5706b9e3558e78db39dd497c940b47bf228bc419", size = 1237261 }, + { url = "https://files.pythonhosted.org/packages/1e/86/eea2309dc258fb86c7d9b10db536434fc16420feaa3b6113df18b23db7c2/tiktoken-0.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:326624128590def898775b722ccc327e90b073714227175ea8febbc920ac0a99", size = 884537 }, + { url = "https://files.pythonhosted.org/packages/c1/22/34b2e136a6f4af186b6640cbfd6f93400783c9ef6cd550d9eab80628d9de/tiktoken-0.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:881839cfeae051b3628d9823b2e56b5cc93a9e2efb435f4cf15f17dc45f21586", size = 1039357 }, + { url = "https://files.pythonhosted.org/packages/04/d2/c793cf49c20f5855fd6ce05d080c0537d7418f22c58e71f392d5e8c8dbf7/tiktoken-0.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fe9399bdc3f29d428f16a2f86c3c8ec20be3eac5f53693ce4980371c3245729b", size = 982616 }, + { url = "https://files.pythonhosted.org/packages/b3/a1/79846e5ef911cd5d75c844de3fa496a10c91b4b5f550aad695c5df153d72/tiktoken-0.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a58deb7075d5b69237a3ff4bb51a726670419db6ea62bdcd8bd80c78497d7ab", size = 1144011 }, + { url = "https://files.pythonhosted.org/packages/26/32/e0e3a859136e95c85a572e4806dc58bf1ddf651108ae8b97d5f3ebe1a244/tiktoken-0.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2908c0d043a7d03ebd80347266b0e58440bdef5564f84f4d29fb235b5df3b04", size = 1175432 }, + { url = "https://files.pythonhosted.org/packages/c7/89/926b66e9025b97e9fbabeaa59048a736fe3c3e4530a204109571104f921c/tiktoken-0.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:294440d21a2a51e12d4238e68a5972095534fe9878be57d905c476017bff99fc", size = 1236576 }, + { url = "https://files.pythonhosted.org/packages/45/e2/39d4aa02a52bba73b2cd21ba4533c84425ff8786cc63c511d68c8897376e/tiktoken-0.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:d8f3192733ac4d77977432947d563d7e1b310b96497acd3c196c9bddb36ed9db", size = 883824 }, + { url = "https://files.pythonhosted.org/packages/e3/38/802e79ba0ee5fcbf240cd624143f57744e5d411d2e9d9ad2db70d8395986/tiktoken-0.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:02be1666096aff7da6cbd7cdaa8e7917bfed3467cd64b38b1f112e96d3b06a24", size = 1039648 }, + { url = "https://files.pythonhosted.org/packages/b1/da/24cdbfc302c98663fbea66f5866f7fa1048405c7564ab88483aea97c3b1a/tiktoken-0.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94ff53c5c74b535b2cbf431d907fc13c678bbd009ee633a2aca269a04389f9a", size = 982763 }, + { url = "https://files.pythonhosted.org/packages/e4/f0/0ecf79a279dfa41fc97d00adccf976ecc2556d3c08ef3e25e45eb31f665b/tiktoken-0.8.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b231f5e8982c245ee3065cd84a4712d64692348bc609d84467c57b4b72dcbc5", size = 1144417 }, + { url = "https://files.pythonhosted.org/packages/ab/d3/155d2d4514f3471a25dc1d6d20549ef254e2aa9bb5b1060809b1d3b03d3a/tiktoken-0.8.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4177faa809bd55f699e88c96d9bb4635d22e3f59d635ba6fd9ffedf7150b9953", size = 1175108 }, + { url = "https://files.pythonhosted.org/packages/19/eb/5989e16821ee8300ef8ee13c16effc20dfc26c777d05fbb6825e3c037b81/tiktoken-0.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5376b6f8dc4753cd81ead935c5f518fa0fbe7e133d9e25f648d8c4dabdd4bad7", size = 1236520 }, + { url = "https://files.pythonhosted.org/packages/40/59/14b20465f1d1cb89cfbc96ec27e5617b2d41c79da12b5e04e96d689be2a7/tiktoken-0.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:18228d624807d66c87acd8f25fc135665617cab220671eb65b50f5d70fa51f69", size = 883849 }, ] [[package]] From fcf150a01d7f256143d093a36d1f3f8923f5dc08 Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Fri, 25 Oct 2024 23:01:29 +0000 Subject: [PATCH 04/14] Snapshot of form-filler work (doesn't work yet). --- .../form-filler-skill/.vscode/settings.json | 57 ++ .../skills/skills/form-filler-skill/Makefile | 2 + .../skills/skills/form-filler-skill/README.md | 7 + .../form_filler_skill/__init__.py | 3 + .../chat_drivers/gc_final_update.py | 86 ++ .../chat_drivers/gc_fix_agenda_error.py | 60 ++ .../chat_drivers/gc_update_agenda.py | 247 ++++++ .../chat_drivers/gc_update_artifact.py | 61 ++ .../chat_drivers/generate_filled_form.py | 0 .../chat_drivers/update_agenda.py | 0 .../chat_drivers/update_form.py | 0 .../form_filler_skill/form_filler_skill.py | 126 +++ .../guided_conversation/__init__.py | 0 .../guided_conversation/agenda.py | 208 +++++ .../guided_conversation/artifact.py | 479 +++++++++++ .../guided_conversation/base_model_llm.py | 45 + .../conversation_helpers.py | 165 ++++ .../guided_conversation/definition.py | 14 + .../openai_tool_calling.py | 167 ++++ .../guided_conversation/plugin_helpers.py | 69 ++ .../guided_conversation/resources.py | 254 ++++++ .../guided_conversation_skill.py | 132 +++ .../skills/form-filler-skill/pyproject.toml | 26 + .../skills/skills/form-filler-skill/uv.lock | 804 ++++++++++++++++++ 24 files changed, 3012 insertions(+) create mode 100644 libraries/python/skills/skills/form-filler-skill/.vscode/settings.json create mode 100644 libraries/python/skills/skills/form-filler-skill/Makefile create mode 100644 libraries/python/skills/skills/form-filler-skill/README.md create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/__init__.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_final_update.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_fix_agenda_error.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_update_agenda.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_update_artifact.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/generate_filled_form.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_agenda.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_form.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/form_filler_skill.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/__init__.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/agenda.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/artifact.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/base_model_llm.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/conversation_helpers.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/definition.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/openai_tool_calling.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/plugin_helpers.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/resources.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py create mode 100644 libraries/python/skills/skills/form-filler-skill/pyproject.toml create mode 100644 libraries/python/skills/skills/form-filler-skill/uv.lock diff --git a/libraries/python/skills/skills/form-filler-skill/.vscode/settings.json b/libraries/python/skills/skills/form-filler-skill/.vscode/settings.json new file mode 100644 index 00000000..7177a8e5 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/.vscode/settings.json @@ -0,0 +1,57 @@ +{ + "editor.bracketPairColorization.enabled": true, + "editor.codeActionsOnSave": { + "source.fixAll": "always", + "source.organizeImports": "always" + }, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnPaste": true, + "editor.formatOnSave": true, + "editor.formatOnType": true, + "editor.guides.bracketPairs": "active", + "files.eol": "\n", + "files.trimTrailingWhitespace": true, + "flake8.ignorePatterns": ["**/*.py"], // disable flake8 in favor of ruff + "jupyter.debugJustMyCode": false, + "python.analysis.autoFormatStrings": true, + "python.analysis.autoImportCompletions": true, + "python.analysis.diagnosticMode": "workspace", + "python.analysis.fixAll": ["source.unusedImports"], + "python.analysis.inlayHints.functionReturnTypes": true, + "python.analysis.typeCheckingMode": "basic", + "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python", + "python.testing.cwd": "${workspaceFolder}", + "search.exclude": { + "**/.venv": true, + "**/data": true + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, + "[jsonc]": { + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.formatOnSave": true + }, + "[python]": { + "editor.defaultFormatter": "charliermarsh.ruff", + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll": "explicit", + "source.unusedImports": "explicit", + "source.organizeImports": "explicit", + "source.formatDocument": "explicit" + } + }, + "ruff.nativeServer": "on", + "cSpell.words": [ + "dotenv", + "httpx", + "openai", + "posix", + "pydantic", + "pypdf", + "runtimes", + "tiktoken" + ] +} diff --git a/libraries/python/skills/skills/form-filler-skill/Makefile b/libraries/python/skills/skills/form-filler-skill/Makefile new file mode 100644 index 00000000..1ad4520a --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/Makefile @@ -0,0 +1,2 @@ +repo_root = $(shell git rev-parse --show-toplevel) +include $(repo_root)/tools/makefiles/python.mk diff --git a/libraries/python/skills/skills/form-filler-skill/README.md b/libraries/python/skills/skills/form-filler-skill/README.md new file mode 100644 index 00000000..5e19c5bd --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/README.md @@ -0,0 +1,7 @@ +# Posix Skill + +This is a skill that can be registered to an assistant in the [Skill Library](../../skill-library/README.md). + +This skill has been primarily created for demonstration purposes and you can see it in action in [this notebook](../../notebooks/notebooks/skills.ipynb). + +This skill gives your assistant the capability for running posix-style actions and routines to manage a filesystem. diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/__init__.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/__init__.py new file mode 100644 index 00000000..451e61dd --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/__init__.py @@ -0,0 +1,3 @@ +from form_filler_skill.form_filler_skill import FormFillerSkill + +export = FormFillerSkill diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_final_update.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_final_update.py new file mode 100644 index 00000000..33f964ba --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_final_update.py @@ -0,0 +1,86 @@ +import logging + +from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider +from chat_driver.message_formatter import liquid_format +from form_filler_skill.guided_conversation.artifact import Artifact +from form_filler_skill.guided_conversation.conversation_helpers import Conversation +from form_filler_skill.guided_conversation.definition import GCDefinition +from openai import AsyncAzureOpenAI, AsyncOpenAI + +logger = logging.getLogger(__name__) + + +final_update_template = """You are a helpful, thoughtful, and meticulous assistant. +You just finished a conversation with a user.{% if context %} Here is some additional context about the conversation: +{{ context }}{% endif %} + +Your goal is to complete an artifact as thoroughly and accurately as possible based on the conversation. + +This is the schema of the artifact: +{{ artifact_schema }} + +You will be given the current state of the artifact as well as the conversation history. +Note that if the value for a field in the artifact is 'Unanswered', it means that the field was not completed. \ +Some fields may have already been completed during the conversation. + +Your need to determine whether there are any fields that need to be updated, and if so, update them. +- You should only update a field if both of the following conditions are met: (a) the current state does NOT adequately reflect the conversation \ +and (b) you are able to submit a valid value for a field. \ +You are allowed to update completed fields, but you should only do so if the current state is inadequate, \ +e.g. the user corrected a mistake in their date of birth, but the artifact does not show the corrected version. \ +Remember that it's always an option to reset a field to "Unanswered" - this is often the best choice if the artifact contains incorrect information that cannot be corrected. \ +Do not submit a value that is identical to the current state of the field (e.g. if the field is already "Unanswered" and the user didn't provide any new information about it, you should not submit "Unanswered"). \ +- Make sure the value adheres to the constraints of the field as specified in the artifact schema. \ +If it's not possible to update a field with a valid value (e.g., the user provided an invalid date of birth), you should not update the field. +- If the artifact schema is open-ended (e.g. it asks you to rate how pressing the user's issue is, without specifying rules for doing so), \ +use your best judgment to determine whether you have enough information to complete the field based on the conversation. +- Prioritize accuracy over completion. You should never make up information or make assumptions in order to complete a field. \ +For example, if the field asks for a 10-digit phone number, and the user provided a 9-digit phone number, you should not add a digit to the phone number in order to complete the field. +- If the user wasn't able to provide all of the information needed to complete a field, \ +use your best judgment to determine if a partial answer is appropriate (assuming it adheres to the formatting requirements of the field). \ +For example, if the field asks for a description of symptoms along with details about when the symptoms started, but the user wasn't sure when their symptoms started, \ +it's better to record the information they do have rather than to leave the field unanswered (and to indicate that the user was unsure about the start date). +- It's possible to update multiple fields at once (assuming you're adhering to the above rules in all cases). It's also possible that no fields need to be updated. + +Your task is to state your step-by-step reasoning about what to update, followed by a final recommendation. +Someone else will be responsible for executing the updates and they will only have access to your output \ +(not any of the conversation history, artifact schema, or other context) so make sure to specify exactly which \ +fields to update and the values to update them with, or to state that no fields need to be updated. + + +Conversation history: +{{ conversation_history }} + +Current state of the artifact: +{{ artifact_state }}""" + + +async def final_update( + context: ContextProtocol, + open_ai_client: AsyncOpenAI | AsyncAzureOpenAI, + definition: GCDefinition, + chat_history: Conversation, + artifact: Artifact, +): + history = InMemoryMessageHistoryProvider(formatter=liquid_format) + + history.append_system_message( + final_update_template, + { + "conversation_history": chat_history.get_repr_for_prompt(), + "context": definition.conversation_context, + "artifact_schema": artifact.get_schema_for_prompt(), + "artifact_state": artifact.get_artifact_for_prompt(), + }, + ) + + config = ChatDriverConfig( + context=context, + openai_client=open_ai_client, + model="gpt-3.5-turbo", + message_provider=history, + ) + + chat_driver = ChatDriver(config) + return await chat_driver.respond() diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_fix_agenda_error.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_fix_agenda_error.py new file mode 100644 index 00000000..0638c62b --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_fix_agenda_error.py @@ -0,0 +1,60 @@ +import logging + +from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider +from chat_driver.message_formatter import liquid_format +from form_filler_skill.guided_conversation.conversation_helpers import Conversation, ConversationMessageType +from openai import AsyncAzureOpenAI, AsyncOpenAI + +logger = logging.getLogger(__name__) + +AGENDA_ERROR_CORRECTION_SYSTEM_TEMPLATE = """You are a helpful, thoughtful, and meticulous assistant. +You are conducting a conversation with a user. You tried to update the agenda, but the update was invalid. +You will be provided the history of your conversation with the user, \ +your previous attempt(s) at updating the agenda, and the error message(s) that resulted from your attempt(s). +Your task is to correct the update so that it is valid. \ +Your changes should be as minimal as possible - you are focused on fixing the error(s) that caused the update to be invalid. +Note that if the resource allocation is invalid, you must follow these rules: +1. You should not change the description of the first item (since it has already been executed), but you can change its resource allocation +2. For all other items, you can combine or split them, or assign them fewer or more resources, \ +but the content they cover collectively should not change (i.e. don't eliminate or add new topics). +For example, the invalid attempt was "item 1 = ask for date of birth (1 turn), item 2 = ask for phone number (1 turn), \ +item 3 = ask for phone type (1 turn), item 4 = explore treatment history (6 turns)", \ +and the error says you need to correct the total resource allocation to 7 turns. \ +A bad solution is "item 1 = ask for date of birth (1 turn), \ +item 2 = explore treatment history (6 turns)" because it eliminates the phone number and phone type topics. \ +A good solution is "item 1 = ask for date of birth (2 turns), item 2 = ask for phone number, phone type, +and treatment history (2 turns), item 3 = explore treatment history (3 turns)." + +Conversation history: +{{ conversation_history }} + +Previous attempts to update the agenda: +{{ previous_attempts }}""" + + +async def fix_agenda_error( + context: ContextProtocol, + openai_client: AsyncOpenAI | AsyncAzureOpenAI, + previous_attempts: str, + conversation: Conversation, +): + history = InMemoryMessageHistoryProvider(formatter=liquid_format) + + history.append_system_message( + AGENDA_ERROR_CORRECTION_SYSTEM_TEMPLATE, + { + "conversation_history": conversation.get_repr_for_prompt(exclude_types=[ConversationMessageType.REASONING]), + "previous_attempts": previous_attempts, + }, + ) + + config = ChatDriverConfig( + context=context, + openai_client=openai_client, + model="gpt-3.5-turbo", + message_provider=history, + ) + + chat_driver = ChatDriver(config) + return await chat_driver.respond() diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_update_agenda.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_update_agenda.py new file mode 100644 index 00000000..fd5a5e23 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_update_agenda.py @@ -0,0 +1,247 @@ +import logging + +from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider +from chat_driver.message_formatter import liquid_format +from form_filler_skill.guided_conversation.agenda import Agenda +from form_filler_skill.guided_conversation.definition import GCDefinition +from form_filler_skill.guided_conversation.resources import GCResource, ResourceConstraintMode +from openai import AsyncAzureOpenAI, AsyncOpenAI + +from ..guided_conversation.artifact import Artifact + +logger = logging.getLogger(__name__) + +conversation_plan_template = """You are a helpful, thoughtful, and meticulous assistant. +You are conducting a conversation with a user. \ +Your goal is to complete an artifact as thoroughly as possible by the end of the conversation, and to ensure a +smooth experience for the user. + +This is the schema of the artifact you are completing: +{{ artifact_schema }}{% if context %} + +Here is some additional context about the conversation: +{{ context }}{% endif %} + +Throughout the conversation, you must abide by these rules: +{{ rules }}{% if current_state_description %} + +Here's a description of the conversation flow: +{{ current_state_description }} +Follow this description, and exercise good judgment about when it is appropriate to deviate.{% endif %} + +You will be provided the history of your conversation with the user up until now and the current state of the artifact. +Note that if the value for a field in the artifact is 'Unanswered', it means that the field has not been completed. +You need to select the best possible action(s), given the state of the conversation and the artifact. +These are the possible actions you can take: + +{% if show_agenda %}Update agenda (required parameters: items) +- If the latest agenda is set to "None", you should always pick this action. +- You should pick this action if you need to change your plan for the conversation to make the best use of the +remaining turns available to you. \ +Consider how long it usually takes to get the information you need (which is a function of the quality and pace of +the user's responses), \ +the number, complexity, and importance of the remaining fields in the artifact, and the number of turns remaining +({{ remaining_resource }}). \ +Based on these factors, you might need to accelerate (e.g. combine several topics) or slow down the conversation +(e.g. spread out a topic), in which case you should update the agenda accordingly. \ +Note that skipping an artifact field is NOT a valid way to accelerate the conversation. +- You must provide an ordered list of items to be completed sequentially, where the first item contains everything +you will do in the current turn of the conversation (in addition to updating the agenda). \ +For example, if you choose to send a message to the user asking for their name and medical history, then you would +write "ask for name and medical history" as the first item. \ +If you think medical history will take longer than asking for the name, then you would write +"complete medical history" as the second item, with an estimate of how many turns you think it will take. \ +Do NOT include items that have already been completed. \ +Items must always represent a conversation topic (corresponding to the "Send message to user" action). Updating the +artifact (e.g. "update field X based on the discussion") or terminating the conversation is NOT a valid item. +- The latest agenda was created in the previous turn of the conversation. \ +Even if the total turns in the latest agenda equals the remaining turns, you should still update the agenda if you +think the current plan is suboptimal (e.g. the first item was completed, the order of items is not ideal, an item is +too broad or not a conversation topic, etc.). +- Each item must have a description and and your best guess for the number of turns required to complete it. Do not +provide a range of turns. \ +It is EXTREMELY important that the total turns allocated across all items in the updated agenda (including the first +item for the current turn) {{ total_resource_str }} \ +Everything in the agenda should be something you expect to complete in the remaining turns - there shouldn't be any +optional "buffer" items. \ +It can be helpful to include the cumulative turns allocated for each item in the agenda to ensure you adhere to this +rule, e.g. item 1 = 2 turns (cumulative total = 2), item 2 = 4 turns (cumulative total = 6), etc. +- Avoid high-level items like "ask follow-up questions" - be specific about what you need to do. +- Do NOT include wrap-up items such as "review and confirm all information with the user" (you should be doing this +throughout the conversation) or "thank the user for their time". \ +Do NOT repeat topics that have already been sufficiently addressed. {{ ample_time_str }}{% endif %} + +Send message to user (required parameters: message) +- If there is no conversation history, you should always pick this action. +- You should pick this action if (a) the user asked a question or made a statement that you need to respond to, \ +or (b) you need to follow-up with the user because the information they provided is incomplete, invalid, ambiguous, +or in some way insufficient to complete the artifact. \ +For example, if the artifact schema indicates that the "date of birth" field must be in the format "YYYY-MM-DD", but +the user has only provided the month and year, you should send a message to the user asking for the day. \ +Likewise, if the user claims that their date of birth is February 30, you should send a message to the user asking +for a valid date. \ +If the artifact schema is open-ended (e.g. it asks you to rate how pressing the user's issue is, without specifying +rules for doing so), use your best judgment to determine whether you have enough information or you need to continue +probing the user. \ +It's important to be thorough, but also to avoid asking the user for unnecessary information. + +Update artifact fields (required parameters: field, value) +- You should pick this action as soon as (a) the user provides new information that is not already reflected in the +current state of the artifact and (b) you are able to submit a valid value for a field in the artifact using this new +information. \ +If you have already updated a field in the artifact and there is no new information to update the field with, you +should not pick this action. +- Make sure the value adheres to the constraints of the field as specified in the artifact schema. +- If the user has provided all required information to complete a field (i.e. the criteria for "Send message to user" +are not satisfied) but the information is in the wrong format, you should not ask the user to reformat their response. \ +Instead, you should simply update the field with the correctly formatted value. For example, if the artifact asks for +the date of birth in the format "YYYY-MM-DD", and the user provides their date of birth as "June 15, 2000", you should +update the field with the value "2000-06-15". +- Prioritize accuracy over completion. You should never make up information or make assumptions in order to complete +a field. \ +For example, if the field asks for a 10-digit phone number, and the user provided a 9-digit phone number, you should +not add a digit to the phone number in order to complete the field. \ +Instead, you should follow-up with the user to ask for the correct phone number. If they still aren't able to provide +one, you should leave the field unanswered. +- If the user isn't able to provide all of the information needed to complete a field, \ +use your best judgment to determine if a partial answer is appropriate (assuming it adheres to the formatting +requirements of the field). \ +For example, if the field asks for a description of symptoms along with details about when the symptoms started, but +the user isn't sure when their symptoms started, \ +it's better to record the information they do have rather than to leave the field unanswered (and to indicate that +the user was unsure about the start date). +- If it's possible to update multiple fields at once (assuming you're adhering to the above rules in all cases), you +should do so. \ +For example, if the user provides their full name and date of birth in the same message, you should select the +"update artifact fields" action twice, once for each field. + +End conversation (required parameters: None) +{{ termination_instructions }} +{{ resource_instructions }} + +If you select the "Update artifact field" action or the "Update agenda" action, you should also select one of the +"Send message to user" or "End conversation" actions. \ +Note that artifact and updates updates will always be executed before a message is sent to the user or the +conversation is terminated. \ +Also note that only one message can be sent to the user at a time. + +Your task is to state your step-by-step reasoning for the best possible action(s), followed by a final recommendation +of which action(s) to take, including all required parameters. +Someone else will be responsible for executing the action(s) you select and they will only have access to your output \ +(not any of the conversation history, artifact schema, or other context) so it is EXTREMELY important \ +that you clearly specify the value of all required parameters for each action you select. + +Conversation history: +{{ chat_history }} + +Latest agenda: +{{ agenda_state }} + +Current state of the artifact: +{{ artifact_state }}""" + + +def _get_termination_instructions(resource: GCResource): + """ + Get the termination instructions for the conversation. This is contingent on the resources mode, + if any, that is available. + + Assumes we're always using turns as the resource unit. + + Args: + resource (GCResource): The resource object. + + Returns: + str: the termination instructions + """ + # Termination condition under no resource constraints + if resource.resource_constraint is None: + return ( + "- You should pick this action as soon as you have completed the artifact to the best of your ability, the" + " conversation has come to a natural conclusion, or the user is not cooperating so you cannot continue the" + " conversation." + ) + + # Termination condition under exact resource constraints + if resource.resource_constraint.mode == ResourceConstraintMode.EXACT: + return ( + "- You should only pick this action if the user is not cooperating so you cannot continue the conversation." + ) + + # Termination condition under maximum resource constraints + elif resource.resource_constraint.mode == ResourceConstraintMode.MAXIMUM: + return ( + "- You should pick this action as soon as you have completed the artifact to the best of your ability, the" + " conversation has come to a natural conclusion, or the user is not cooperating so you cannot continue the" + " conversation." + ) + + else: + logger.error("Invalid resource mode provided.") + return "" + + +async def update_agenda( + context: ContextProtocol, + open_ai_client: AsyncOpenAI | AsyncAzureOpenAI, + definition: GCDefinition, + chat_history: str, + agenda: Agenda, + artifact: Artifact, + resource: GCResource, +): + remaining_resource = resource.remaining_units if resource.remaining_units else 0 + resource_instructions = resource.get_resource_instructions() + total_resource_str = "" + ample_time_str = "" + + # if there is a resource constraint and there's more than one turn left, include the update agenda action + if (resource_instructions != "") and (remaining_resource > 1): + if resource.get_resource_mode() == ResourceConstraintMode.MAXIMUM: + total_resource_str = f"does not exceed the remaining turns ({remaining_resource})." + ample_time_str = "" + elif resource.get_resource_mode() == ResourceConstraintMode.EXACT: + total_resource_str = ( + f"is equal to the remaining turns ({remaining_resource}). Do not leave any turns unallocated." + ) + ample_time_str = """If you have many turns remaining, instead of including wrap-up items or repeating + topics, you should include items that increase the breadth and/or depth of the conversation \ +in a way that's directly relevant to the artifact (e.g. "collect additional details about X", "ask for clarification +about Y", "explore related topic Z", etc.).""" + else: + logger.error("Invalid resource mode.") + else: + total_resource_str = "" + ample_time_str = "" + + history = InMemoryMessageHistoryProvider(formatter=liquid_format) + + history.append_system_message( + conversation_plan_template, + { + "context": definition.conversation_context, + "artifact_schema": definition.artifact_schema, + "rules": definition.rules, + "current_state_description": definition.conversation_flow, + "show_agenda": True, + "remaining_resource": remaining_resource, + "total_resource_str": total_resource_str, + "ample_time_str": ample_time_str, + "termination_instructions": _get_termination_instructions(resource), + "resource_instructions": resource_instructions, + "chat_history": chat_history, + "agenda_state": agenda.get_agenda_for_prompt(), + "artifact_state": artifact.get_artifact_for_prompt(), + }, + ) + + config = ChatDriverConfig( + context=context, + openai_client=open_ai_client, + model="gpt-3.5-turbo", + message_provider=history, + ) + + chat_driver = ChatDriver(config) + return await chat_driver.respond() diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_update_artifact.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_update_artifact.py new file mode 100644 index 00000000..4677e33a --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_update_artifact.py @@ -0,0 +1,61 @@ +import logging + +from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider +from chat_driver.message_formatter import liquid_format +from openai import AsyncAzureOpenAI, AsyncOpenAI + +logger = logging.getLogger(__name__) + +execution_template = """You are a helpful, thoughtful, and meticulous assistant. +You are conducting a conversation with a user. Your goal is to complete an artifact as thoroughly as possible by the +end of the conversation. +You will be given some reasoning about the best possible action(s) to take next given the state of the conversation +as well as the artifact schema. +The reasoning is supposed to state the recommended action(s) to take next, along with all required parameters for each action. +Your task is to execute ALL actions recommended in the reasoning in the order they are listed. +If the reasoning's specification of an action is incomplete (e.g. it doesn't include all required parameters for the +action, \ +or some parameters are specified implicitly, such as "send a message that contains a greeting" instead of explicitly +providing \ +the value of the "message" parameter), do not execute the action. You should never fill in missing or imprecise +parameters yourself. +If the reasoning is not clear about which actions to take, or all actions are specified in an incomplete way, \ +return 'None' without selecting any action. + +Artifact schema: +{{ artifact_schema }} + +If the type in the schema is str, the "field_value" parameter in the action should be also be a string. +These are example parameters for the update_artifact action: {"field_name": "company_name", "field_value": "Contoso"} +DO NOT write JSON in the "field_value" parameter in this case. {"field_name": "company_name", "field_value": "{"value": "Contoso"}"} is INCORRECT. + +Reasoning: +{{ reasoning }}""" + + +async def update_artifact( + context: ContextProtocol, + open_ai_client: AsyncOpenAI | AsyncAzureOpenAI, + reasoning: str, + artifact_schema: str, +): + history = InMemoryMessageHistoryProvider(formatter=liquid_format) + + history.append_system_message( + execution_template, + { + "artifact_schema": artifact_schema, + "reasoning": reasoning, + }, + ) + + config = ChatDriverConfig( + context=context, + openai_client=open_ai_client, + model="gpt-3.5-turbo", + message_provider=history, + ) + + chat_driver = ChatDriver(config) + return await chat_driver.respond() diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/generate_filled_form.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/generate_filled_form.py new file mode 100644 index 00000000..e69de29b diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_agenda.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_agenda.py new file mode 100644 index 00000000..e69de29b diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_form.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_form.py new file mode 100644 index 00000000..e69de29b diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/form_filler_skill.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/form_filler_skill.py new file mode 100644 index 00000000..b0c9d94e --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/form_filler_skill.py @@ -0,0 +1,126 @@ +from typing import Any, Optional + +from chat_driver import ChatDriverConfig +from skill_library import FunctionRoutine, RoutineTypes, Skill +from skill_library.run_context import RunContext + +NAME = "form-filler" +CLASS_NAME = "FormFillerSkill" +DESCRIPTION = "Walks the user through uploading and filling out a form." +DEFAULT_MAX_RETRIES = 3 +INSTRUCTIONS = "You are an assistant." + + +class FormFillerSkill(Skill): + def __init__( + self, + chat_driver_config: ChatDriverConfig, + ) -> None: + # Put all functions in a group. We are going to use all these as (1) + # skill actions, but also as (2) chat functions and (3) chat commands. + # You can also put them in separate lists if you want to differentiate + # between these. + functions = [] + + # Add some skill routines. + routines: list[RoutineTypes] = [ + self.form_filler_routine(), + ] + + # Re-configure the skill's chat driver. + chat_driver_config.instructions = INSTRUCTIONS + chat_driver_config.commands = functions + chat_driver_config.functions = functions + + # Initialize the skill! + super().__init__( + name=NAME, + description=DESCRIPTION, + chat_driver_config=chat_driver_config, + skill_actions=functions, + routines=routines, + ) + + ################################## + # Routines + ################################## + + def form_filler_routine(self) -> FunctionRoutine: + return FunctionRoutine( + name="form_filler", + description="Run a form-filler routine.", + init_function=self.form_fill_init, + step_function=self.form_fill_step, + skill=self, + ) + + async def form_fill_init(self, context: RunContext, vars: dict[str, Any] | None = None): + # TODO: Use `vars` to config the form filler routine. + await self.form_fill_step(context) + + async def form_fill_step( + self, + context: RunContext, + message: Optional[str] = None, + ) -> str | None: + FormFiller = self + state = await context.state() + while True: + match state.get("mode"): + case None: + state["mode"] = "init" + case "init": + # Cede control to guided conversation if an artifact needs to be generated. + # How do we want to pass in all the GC definitions? Should they just be a simpler config object TYPE? + if not state["artifact"]: + if not state["gce_id"]: + guided_conversation_vars: dict[str, Any] = { + "definition_type": "upload_files", + "objective": "Upload a form to be filled out by the form filler recipe.", + } + gc_id = await context.run_routine( + context, "guided_conversation.doc_upload", guided_conversation_vars + ) + state["gc_id"] = gc_id + artifact = GuidedConversation.run(state["gce_id"], message) + if artifact: + state["artifact"] = artifact + else: + await context.update_state(state) + return + + agenda, is_done = FormFiller.update_agenda(context) + state["agenda"] = agenda + if is_done: + state["mode"] = "done" + state["mode"] = "conversation" + await context.update_state(state) + return agenda.last_message + case "conversation": + state["form"] = FormFiller.update_form(context) + agenda, is_done = FormFiller.update_agenda(context) + state["agenda"] = agenda + if is_done: + state["mode"] = "finalize" + await context.update_state(state) + return agenda.last_message + case "finalize": + message = FormFiller.generate_filled_form(context) + state["mode"] = "done" + await context.update_state(state) + return message + case "done": + return None + + ################################## + # Actions + ################################## + + def update_agenda(self, context: RunContext): + return "message", False + + def update_form(self, context: RunContext): + return "message", False + + def generate_filled_form(self, context: RunContext): + return "message" diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/__init__.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/agenda.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/agenda.py new file mode 100644 index 00000000..0bf202fd --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/agenda.py @@ -0,0 +1,208 @@ +# FIXME: Copied code from Semantic Kernel repo, using as-is despite type errors +# TODO: Search for and find the `# type: ignore` comments in the copied code and remove them + +import logging +from typing import Annotated + +from context import ContextProtocol +from openai import AsyncAzureOpenAI, AsyncOpenAI +from pydantic import Field, ValidationError + +from form_filler_skill.chat_drivers.gc_fix_agenda_error import fix_agenda_error +from form_filler_skill.guided_conversation.base_model_llm import BaseModelLLM +from form_filler_skill.guided_conversation.conversation_helpers import Conversation +from form_filler_skill.guided_conversation.openai_tool_calling import ToolValidationResult +from form_filler_skill.guided_conversation.plugin_helpers import PluginOutput, update_attempts +from form_filler_skill.guided_conversation.resources import ( + ResourceConstraintMode, + ResourceConstraintUnit, + format_resource, +) + +logger = logging.getLogger(__name__) + + +UPDATE_AGENDA_TOOL = "update_agenda" + + +class _BaseAgendaItem(BaseModelLLM): + title: str = Field(description="Brief description of the item") + resource: int = Field(description="Number of turns required for the item") + + +class _BaseAgenda(BaseModelLLM): + items: list[_BaseAgendaItem] = Field( + description="Ordered list of items to be completed in the remainder of the conversation", + default_factory=list, + ) + + +class Agenda: + """An abstraction to manage a conversation agenda. The expected use case is that another agent will generate an agenda. + This class will validate if it is valid, and help correct it if it is not. + + Args: + kernel (Kernel): The Semantic Kernel instance to use for calling the LLM. Don't forget to set your + req_settings since this class uses tool calling functionality from the Semantic Kernel. + service_id (str): The service ID to use for the Semantic Kernel tool calling. One kernel can have multiple + services. The service ID is used to identify which service to use for LLM calls. The Agenda object + assumes that the service has tool calling capabilities and is some flavor of chat completion. + resource_constraint_mode (ResourceConstraintMode): The mode for resource constraints. + max_agenda_retries (int): The maximum number of retries for updating the agenda. + """ + + def __init__( + self, + service_id: str, + resource_constraint_mode: ResourceConstraintMode | None, + max_agenda_retries: int = 2, + ) -> None: + self.id = "agenda_plugin" + self.service_id = service_id + + self.resource_constraint_mode = resource_constraint_mode + self.max_agenda_retries = max_agenda_retries + + self.agenda = _BaseAgenda() + + async def update_agenda( + self, + context: ContextProtocol, + openai_client: AsyncOpenAI | AsyncAzureOpenAI, + items: list[dict[str, str]], + remaining_turns: int, + conversation: Conversation, + ) -> PluginOutput: + """Updates the agenda model with the given items (generally generated by an LLM) and validates if the update is valid. + The agenda update reasons in terms of turns for validating the if the proposed agenda is valid. + If you wish to use a different resource unit, convert the value to turns in some way because + we found that LLMs do much better at reasoning in terms of turns. + + Args: + items (list[dict[str, str]]): A list of agenda items. + Each item should have the following keys: + - title (str): A brief description of the item. + - resource (int): The number of turns required for the item. + remaining_turns (int): The number of remaining turns. + conversation (Conversation): The conversation object. + + Returns: + PluginOutput: A PluginOutput object with the success status. Does not generate any messages. + """ + previous_attempts = [] + while True: + try: + # Try to update the agenda, and do extra validation checks + self.agenda.items = items # type: ignore + self._validate_agenda_update(items, remaining_turns) + logger.info(f"Agenda updated successfully: {self.get_agenda_for_prompt()}") + return PluginOutput(True, []) + except (ValidationError, ValueError) as e: + # Update the previous attempts and get instructions for the LLM + previous_attempts, llm_formatted_attempts = update_attempts( + error=e, + attempt_id=str(items), + previous_attempts=previous_attempts, + ) + + # If we have reached the maximum number of retries return a failure + if len(previous_attempts) > self.max_agenda_retries: + logger.warning(f"Failed to update agenda after {self.max_agenda_retries} attempts.") + return PluginOutput(False, []) + else: + logger.info(f"Attempting to fix the agenda error. Attempt {len(previous_attempts)}.") + response = await fix_agenda_error(context, openai_client, llm_formatted_attempts, conversation) + if response is None: + raise ValueError("Invalid response from the LLM.") + if response.metadata["validation_result"] != ToolValidationResult.SUCCESS: + logger.warning( + f"Failed to fix the agenda error due to a failure in the LLM tool call: {response.metadata['validation_result']}" + ) + return PluginOutput(False, []) + else: + # Use the result of the first tool call to try the update again + items = response.metadata["tool_args_list"][0]["items"] + + def get_agenda_for_prompt(self) -> str: + """Gets a string representation of the agenda for use in an LLM prompt. + + Returns: + str: A string representation of the agenda. + """ + agenda_json = self.agenda.model_dump() + agenda_items = agenda_json.get("items", []) + if len(agenda_items) == 0: + return "None" + agenda_str = "\n".join([ + f"{i + 1}. [{format_resource(item['resource'], ResourceConstraintUnit.TURNS)}] {item['title']}" + for i, item in enumerate(agenda_items) + ]) + total_resource = format_resource(sum([item["resource"] for item in agenda_items]), ResourceConstraintUnit.TURNS) + agenda_str += f"\nTotal = {total_resource}" + return agenda_str + + # The following is the kernel function that will be provided to the LLM call + class Items: + title: Annotated[str, "Description of the item"] + resource: Annotated[int, "Number of turns required for the item"] + + def update_agenda_items( + self, + items: Annotated[list[Items], "Ordered list of items to be completed in the remainder of the conversation"], + ): + pass + + def _validate_agenda_update(self, items: list[dict[str, str]], remaining_turns: int) -> None: + """Validates if any constraints were violated while performing the agenda update. + + Args: + items (list[dict[str, str]]): A list of agenda items. + remaining_turns (int): The number of remaining turns. + + Raises: + ValueError: If any validation checks fail. + """ + # The total, proposed allocation of resources. + total_resources = sum([item["resource"] for item in items]) # type: ignore + + violations = [] + # In maximum mode, the total resources should not exceed the remaining turns + if (self.resource_constraint_mode == ResourceConstraintMode.MAXIMUM) and (total_resources > remaining_turns): + total_resource_instruction = ( + f"The total turns allocated in the agenda must not exceed the remaining amount ({remaining_turns})" + ) + violations.append(f"{total_resource_instruction}; but the current total is {total_resources}.") + + # In exact mode if the total resources were not exactly equal to the remaining turns + if (self.resource_constraint_mode == ResourceConstraintMode.EXACT) and (total_resources != remaining_turns): + total_resource_instruction = ( + f"The total turns allocated in the agenda must equal the remaining amount ({remaining_turns})" + ) + violations.append(f"{total_resource_instruction}; but the current total is {total_resources}.") + + # Check if any item has a resource value of 0 + if any(item["resource"] <= 0 for item in items): # type: ignore + violations.append("All items must have a resource value greater than 0.") + + # Raise an error if any violations were found + if len(violations) > 0: + logger.debug(f"Agenda update failed due to the following violations: {violations}.") + raise ValueError(" ".join(violations)) + + def to_json(self) -> dict: + agenda_dict = self.agenda.model_dump() + return { + "agenda": agenda_dict, + } + + @classmethod + def from_json( + cls, + json_data: dict, + service_id: str, + resource_constraint_mode: ResourceConstraintMode | None, + max_agenda_retries: int = 2, + ) -> "Agenda": + agenda = cls(service_id, resource_constraint_mode, max_agenda_retries) + agenda.agenda.items = json_data["agenda"]["items"] + return agenda diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/artifact.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/artifact.py new file mode 100644 index 00000000..b4f29717 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/artifact.py @@ -0,0 +1,479 @@ +# Copyright (c) Microsoft. All rights reserved. + +# FIXME: Copied code from Semantic Kernel repo, using as-is despite type errors +# type: ignore + +import logging +from typing import Annotated, Any, Literal, get_args, get_origin, get_type_hints + +from guided_conversation.utils.base_model_llm import BaseModelLLM +from guided_conversation.utils.conversation_helpers import Conversation, ConversationMessageType +from guided_conversation.utils.openai_tool_calling import ToolValidationResult +from guided_conversation.utils.plugin_helpers import PluginOutput, fix_error, update_attempts +from pydantic import BaseModel, create_model +from semantic_kernel import Kernel +from semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior +from semantic_kernel.contents import AuthorRole, ChatMessageContent +from semantic_kernel.functions import KernelArguments +from semantic_kernel.functions.kernel_function_decorator import kernel_function + +ARTIFACT_ERROR_CORRECTION_SYSTEM_TEMPLATE = """You are a helpful, thoughtful, and meticulous assistant. +You are conducting a conversation with a user. Your goal is to complete an artifact as thoroughly as possible by the end of the conversation. +You have tried to update a field in the artifact, but the value you provided did not adhere \ +to the constraints of the field as specified in the artifact schema. +You will be provided the history of your conversation with the user, the schema for the field, \ +your previous attempt(s) at updating the field, and the error message(s) that resulted from your attempt(s). +Your task is to select the best possible action to take next: +1. Update artifact +- You should pick this action if you have a valid value to submit for the field in question. +2. Resume conversation +- You should pick this action if: (a) you do NOT have a valid value to submit for the field in question, and \ +(b) you need to ask the user for more information in order to obtain a valid value. \ +For example, if the user stated that their date of birth is June 2000, but the artifact field asks for the date of birth in the format \ +"YYYY-MM-DD", you should resume the conversation and ask the user for the day. + +Conversation history: +{{ conversation_history }} + +Schema: +{{ artifact_schema }} + +Previous attempts to update the field "{{ field_name }}" in the artifact: +{{ previous_attempts }}""" + +UPDATE_ARTIFACT_TOOL = "update_artifact_field" +RESUME_CONV_TOOL = "resume_conversation" + + +class Artifact: + """The Artifact plugin takes in a Pydantic base model, and robustly handles updating the fields of the model + A typical use case is as a form an agent must complete throughout a conversation. + Another use case is as a working memory for the agent. + + The primary interface is update_artifact, which takes in the field_name to update and its new value. + Additionally, the chat_history is passed in to help the agent make informed decisions in case an error occurs. + + The Artifact also exposes several functions to access internal state: + get_artifact_for_prompt, get_schema_for_prompt, and get_failed_fields. + """ + + def __init__(self, service_id: str, input_artifact: BaseModel, max_artifact_field_retries: int = 2) -> None: + """ + Initialize the Artifact plugin with the given Pydantic base model. + + Args: + kernel (Kernel): The Semantic Kernel instance to use for calling the LLM. Don't forget to set your + req_settings since this class uses tool calling functionality from the Semantic Kernel. + service_id (str): The service ID to use for the Semantic Kernel tool calling. One kernel can have multiple + services. The service ID is used to identify which service to use for LLM calls. The Artifact object + assumes that the service has tool calling capabilities and is some flavor of chat completion. + input_artifact (BaseModel): The Pydantic base model to use as the artifact + max_artifact_field_retries (int): The maximum number of times to retry updating a field in the artifact + """ + logger = logging.getLogger(__name__) + self.logger = logger + + self.id = "artifact_plugin" + self.service_id = service_id + self.max_artifact_field_retries = max_artifact_field_retries + + self.original_schema = input_artifact.model_json_schema() + self.artifact = self._initialize_artifact(input_artifact) + + # failed_artifact_fields maps a field name to a list of the history of the failed attempts to update it + # dict: key = field, value = list of tuple[attempt, error message] + self.failed_artifact_fields: dict[str, list[tuple[str, str]]] = {} + + # The following are the kernel functions that will be provided to the LLM call + @kernel_function( + name=UPDATE_ARTIFACT_TOOL, + description="Sets the value of a field in the artifact", + ) + def update_artifact_field( + self, + field: Annotated[str, "The name of the field to update in the artifact"], + value: Annotated[str, "The value to set the field to"], + ) -> None: + pass + + @kernel_function( + name=RESUME_CONV_TOOL, + description="Resumes conversation to get more information from the user ", + ) + def resume_conversation(self): + pass + + async def update_artifact(self, field_name: str, field_value: Any, conversation: Conversation) -> PluginOutput: + """The core interface for the Artifact plugin. + This function will attempt to update the given field_name to the given field_value. + If the field_value fails Pydantic validation, an LLM will determine one of two actions to take. + Given the conversation as additional context the two actions are: + - Retry the update the artifact by fixing the formatting using the previous failed attempts as guidance + - Take no action or in other words, resume the conversation to ask the user for more information because the user gave incomplete or incorrect information + + Args: + field_name (str): The name of the field to update in the artifact + field_value (Any): The value to set the field to + conversation (Conversation): The conversation object that contains the history of the conversation + + Returns: + PluginOutput: An object with two fields: a boolean indicating success + and a list of conversation messages that may have been generated. + + Several outcomes can happen: + - The update may have failed due to + - A field_name that is not valid in the artifact. + - The field_value failing Pydantic validation and all retries failed. + - The model failed to correctly call a tool. + In this case, the boolean will be False and the list may contain a message indicating the failure. + + - The agent may have successfully updated the artifact or fixed it. + In this case, the boolean will be True and the list will contain a message indicating the update and possibly intermediate messages. + + - The agent may have decided to resume the conversation. + In this case, the boolean will be True and the messages may only contain messages indicated previous errors. + """ + + conversation_messages: list[ChatMessageContent] = [] + + # Check if the field name is valid, and return with a failure message if not + is_valid_field, msg = self._is_valid_field(field_name) + if not is_valid_field: + conversation_messages.append(msg) + return PluginOutput(update_successful=False, messages=conversation_messages) + + # Try to update the field, and handle any errors that occur until the field is + # successfully updated or skipped according to max_artifact_field_retries + while True: + try: + # Check if there have been too many previous failed attempts to update the field + if len(self.failed_artifact_fields.get(field_name, [])) >= self.max_artifact_field_retries: + self.logger.warning(f"Updating field {field_name} has failed too many times. Skipping.") + return PluginOutput(False, conversation_messages) + + # Attempt to update the artifact + msg = self._execute_update_artifact(field_name, field_value) + conversation_messages.append(msg) + return PluginOutput(True, conversation_messages) + except Exception as e: + self.logger.warning(f"Error updating field {field_name}: {e}. Retrying...") + # Handle update error will increment failed_artifact_fields, once it has failed + # greater than self.max_artifact_field_retries the field will be skipped and the loop will break + success, new_field_value = await self._handle_update_error(field_name, field_value, conversation, e) + + # The agent has successfully fixed the field. + if success and new_field_value is not None: + self.logger.info(f"Agent successfully fixed field {field_name}. New value: {new_field_value}") + field_value = new_field_value + # This is the case where the agent has decided to resume the conversation. + elif success: + self.logger.info( + f"Agent could not fix the field itself & decided to resume conversation to fix field {field_name}" + ) + return PluginOutput(True, conversation_messages) + self.logger.warning(f"Agent failed to fix field {field_name}. Retrying...") + # Otherwise, the agent has failed and we will go through the loop again + + def get_artifact_for_prompt(self) -> str: + """Returns a formatted JSON-like representation of the current state of the fields artifact. + Any fields that were failed are completely omitted. + + Returns: + str: The string representation of the artifact. + """ + failed_fields = self.get_failed_fields() + return {k: v for k, v in self.artifact.model_dump().items() if k not in failed_fields} + + def get_schema_for_prompt(self, filter_one_field: str | None = None) -> str: + """Gets a clean version of the original artifact schema, optimized for use in an LLM prompt. + + Args: + filter_one_field (str | None): If this is provided, only the schema for this one field will be returned. + + Returns: + str: The cleaned schema + """ + + def _clean_properties(schema: dict, failed_fields: list[str]) -> str: + properties = schema.get("properties", {}) + clean_properties = {} + for name, property_dict in properties.items(): + if name not in failed_fields: + cleaned_property = {} + for k, v in property_dict.items(): + if k in ["title", "default"]: + continue + cleaned_property[k] = v + clean_properties[name] = cleaned_property + + clean_properties_str = str(clean_properties) + clean_properties_str = clean_properties_str.replace("$ref", "type") + clean_properties_str = clean_properties_str.replace("#/$defs/", "") + return clean_properties_str + + # If filter_one_field is provided, only get the schema for that one field + if filter_one_field: + if not self._is_valid_field(filter_one_field): + self.logger.error(f'Field "{filter_one_field}" is not a valid field in the artifact.') + raise ValueError(f'Field "{filter_one_field}" is not a valid field in the artifact.') + filtered_schema = {"properties": {filter_one_field: self.original_schema["properties"][filter_one_field]}} + filtered_schema.update((k, v) for k, v in self.original_schema.items() if k != "properties") + schema = filtered_schema + else: + schema = self.original_schema + + failed_fields = self.get_failed_fields() + properties = _clean_properties(schema, failed_fields) + if not properties: + self.logger.error("No properties found in the schema.") + raise ValueError("No properties found in the schema.") + + types_schema = schema.get("$defs", {}) + custom_types = [] + for type_name, type_info in types_schema.items(): + if f"'type': '{type_name}'" in properties: + clean_schema = _clean_properties(type_info, []) + if clean_schema != "{}": + custom_types.append(f"{type_name} = {clean_schema}") + + if custom_types: + explanation = f"If you wanted to create a {type_name} object, for example, you would make a JSON object \ +with the following keys: {', '.join(types_schema[type_name]['properties'].keys())}." + custom_types_str = "\n".join(custom_types) + return f"""{properties} + +Here are the definitions for the custom types referenced in the artifact schema: +{custom_types_str} + +{explanation} +Remember that when updating the artifact, the field will be the original field name in the artifact and the JSON object(s) will be the value.""" + else: + return properties + + def get_failed_fields(self) -> list[str]: + """Get a list of fields that have failed all attempts to update. + + Returns: + list[str]: A list of field names that have failed all attempts to update. + """ + fields = [] + for field, attempts in self.failed_artifact_fields.items(): + if len(attempts) >= self.max_artifact_field_retries: + fields.append(field) + return fields + + def _initialize_artifact(self, artifact_model: BaseModel) -> BaseModelLLM: + """Create a new artifact model based on the one provided by the user + with "Unanswered" set for all fields. + + Args: + artifact_model (BaseModel): The Pydantic class provided by the user + + Returns: + BaseModelLLM: The new artifact model with "Unanswered" set for all fields + """ + modified_classes = self._modify_classes(artifact_model) + artifact = self._modify_base_artifact(artifact_model, modified_classes) + return artifact() + + def _get_type_if_subtype(self, target_type: type[Any], base_type: type[Any]) -> type[Any] | None: + """Recursively checks the target_type to see if it is a subclass of base_type or a generic including base_type. + + Args: + target_type: The type to check. + base_type: The type to check against. + + Returns: + The class type if target_type is base_type, a subclass of base_type, or a generic including base_type; otherwise, None. + """ + origin = get_origin(target_type) + if origin is None: + if issubclass(target_type, base_type): + return target_type + else: + # Recursively check if any of the arguments are the target type + for arg in get_args(target_type): + result = self._get_type_if_subtype(arg, base_type) + if result is not None: + return result + return None + + def _modify_classes(self, artifact_class: BaseModel) -> dict[str, type[BaseModelLLM]]: + """Find all classes used as type hints in the artifact, and modify them to set 'Unanswered' as a default and valid value for all fields.""" + modified_classes = {} + # Find any instances of BaseModel in the artifact class in the first "level" of type hints + for field_name, field_type in get_type_hints(artifact_class).items(): + is_base_model = self._get_type_if_subtype(field_type, BaseModel) + if is_base_model is not None: + modified_classes[field_name] = self._modify_base_artifact(is_base_model) + + return modified_classes + + def _replace_type_annotations( + self, field_annotation: type[Any] | None, modified_classes: dict[str, type[BaseModelLLM]] + ) -> type: + """Recursively replace type annotations with modified classes where applicable.""" + # Get the origin of the field annotation, which is the base type for generic types (e.g., List[str] -> list, Dict[str, int] -> dict) + origin = get_origin(field_annotation) + # Get the type arguments of the generic type (e.g., List[str] -> str, Dict[str, int] -> str, int) + args = get_args(field_annotation) + + if origin is None: + # The type is not generic; check if it's a subclass that needs to be replaced + if isinstance(field_annotation, type) and issubclass(field_annotation, BaseModelLLM): + return modified_classes.get(field_annotation.__name__, field_annotation) + return field_annotation + else: + # The type is generic; recursively replace the type annotations of the arguments + new_args = tuple(self._replace_type_annotations(arg, modified_classes) for arg in args) + return origin[new_args] + + def _modify_base_artifact( + self, artifact_model: type[BaseModelLLM], modified_classes: dict[str, type[BaseModelLLM]] | None = None + ) -> type[BaseModelLLM]: + """Create a new artifact model with 'Unanswered' as a default and valid value for all fields.""" + for _, field_info in artifact_model.model_fields.items(): + # Replace original classes with modified version + if modified_classes is not None: + field_info.annotation = self._replace_type_annotations(field_info.annotation, modified_classes) + # This makes it possible to always set a field to "Unanswered" + field_info.annotation = field_info.annotation | Literal["Unanswered"] + # This sets the default value to "Unanswered" + field_info.default = "Unanswered" + # This adds "Unanswered" as a possible value to any regex patterns + metadata = field_info.metadata + for m in metadata: + if hasattr(m, "pattern"): + m.pattern += "|Unanswered" + field_definitions = { + name: (field_info.annotation, field_info) for name, field_info in artifact_model.model_fields.items() + } + artifact_model = create_model("Artifact", __base__=BaseModelLLM, **field_definitions) + return artifact_model + + def _is_valid_field(self, field_name: str) -> tuple[bool, ChatMessageContent]: + """Check if the field_name is a valid field in the artifact. Returns True if it is, False and an error message otherwise.""" + if field_name not in self.artifact.model_fields: + error_message = f'Field "{field_name}" is not a valid field in the artifact.' + msg = ChatMessageContent( + role=AuthorRole.ASSISTANT, + content=error_message, + metadata={"type": ConversationMessageType.ARTIFACT_UPDATE, "turn_number": None}, + ) + return False, msg + return True, None + + async def _fix_artifact_error( + self, + field_name: str, + previous_attempts: str, + conversation_repr: str, + artifact_schema_repr: str, + ) -> dict[str, Any]: + """Calls the LLM to fix an error in the artifact using Semantic Kernel kernel.""" + + req_settings = self.kernel.get_prompt_execution_settings_from_service_id(self.service_id) + req_settings.max_tokens = 2000 + + self.kernel.add_function(plugin_name=self.id, function=self.update_artifact_field) + self.kernel.add_function(plugin_name=self.id, function=self.resume_conversation) + filter = {"included_plugins": [self.id]} + req_settings.function_choice_behavior = FunctionChoiceBehavior.Auto(auto_invoke=False, filters=filter) + + arguments = KernelArguments( + field_name=field_name, + conversation_history=conversation_repr, + previous_attempts=previous_attempts, + artifact_schema=artifact_schema_repr, + settings=req_settings, + ) + + return await fix_error( + kernel=self.kernel, + prompt_template=ARTIFACT_ERROR_CORRECTION_SYSTEM_TEMPLATE, + req_settings=req_settings, + arguments=arguments, + ) + + def _execute_update_artifact( + self, + field_name: Annotated[str, "The name of the field to update in the artifact"], + field_value: Annotated[Any, "The value to set the field to"], + ) -> ChatMessageContent: + """Update a field in the artifact with a new value. This will raise an error if the field_value is invalid.""" + setattr(self.artifact, field_name, field_value) + msg = ChatMessageContent( + role=AuthorRole.ASSISTANT, + content=f"Assistant updated {field_name} to {field_value}", + metadata={"type": ConversationMessageType.ARTIFACT_UPDATE, "turn_number": None}, + ) + return msg + + async def _handle_update_error( + self, field_name: str, field_value: Any, conversation: Conversation, error: Exception + ) -> tuple[bool, Any]: + """ + Handles the logic for when an error occurs while updating a field. + Creates the appropriate context for the model and calls the LLM to fix the error. + + Args: + field_name (str): The name of the field to update in the artifact + field_value (Any): The value to set the field to + conversation (Conversation): The conversation object that contains the history of the conversation + error (Exception): The error that occurred while updating the field + + Returns: + tuple[bool, Any]: A tuple containing a boolean indicating success and the new field value if successful (if not, then None) + """ + # Update the failed attempts for the field + previous_attempts = self.failed_artifact_fields.get(field_name, []) + previous_attempts, llm_formatted_attempts = update_attempts( + error=error, attempt_id=str(field_value), previous_attempts=previous_attempts + ) + self.failed_artifact_fields[field_name] = previous_attempts + + # Call the LLM to fix the error + conversation_history_repr = conversation.get_repr_for_prompt(exclude_types=[ConversationMessageType.REASONING]) + artifact_schema_repr = self.get_schema_for_prompt(filter_one_field=field_name) + result = await self._fix_artifact_error( + field_name, llm_formatted_attempts, conversation_history_repr, artifact_schema_repr + ) + + # Handling the result of the LLM call + if result["validation_result"] != ToolValidationResult.SUCCESS: + return False, None + # Only consider the first tool call + tool_name = result["tool_names"][0] + tool_args = result["tool_args_list"][0] + if tool_name == f"{self.id}-{UPDATE_ARTIFACT_TOOL}": + field_value = tool_args["value"] + return True, field_value + elif tool_name == f"{self.id}-{RESUME_CONV_TOOL}": + return True, None + + def to_json(self) -> dict: + artifact_fields = self.artifact.model_dump() + return { + "artifact": artifact_fields, + "failed_fields": self.failed_artifact_fields, + } + + @classmethod + def from_json( + cls, + json_data: dict, + kernel: Kernel, + service_id: str, + input_artifact: BaseModel, + max_artifact_field_retries: int = 2, + ) -> "Artifact": + artifact = cls(kernel, service_id, input_artifact, max_artifact_field_retries) + + artifact.failed_artifact_fields = json_data["failed_fields"] + + # Iterate over artifact fields and set them to the values in the json data + # Skip any fields that are set as "Unanswered" + for field_name, field_value in json_data["artifact"].items(): + if field_value != "Unanswered": + setattr(artifact.artifact, field_name, field_value) + return artifact diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/base_model_llm.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/base_model_llm.py new file mode 100644 index 00000000..12085752 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/base_model_llm.py @@ -0,0 +1,45 @@ +# Copyright (c) Microsoft. All rights reserved. + +# FIXME: Copied code from Semantic Kernel repo, using as-is despite type errors +# type: ignore + +import ast +from types import NoneType +from typing import get_args + +from pydantic import BaseModel, ValidationInfo, field_validator + + +class BaseModelLLM(BaseModel): + """A Pydantic base class for use when an LLM is completing fields. Provides a custom field validator and Pydantic Config.""" + + @field_validator("*", mode="before") + def parse_literal_eval(cls, value: str, info: ValidationInfo): # noqa: N805 + """An LLM will always result in a string (e.g. '["x", "y"]'), so we need to parse it to the correct type""" + # Get the type hints for the field + annotation = cls.model_fields[info.field_name].annotation + typehints = get_args(annotation) + if len(typehints) == 0: + typehints = [annotation] + + # Usually fields that are NoneType have another type hint as well, e.g. str | None + # if the LLM returns "None" and the field allows NoneType, we should return None + # without this code, the next if-block would leave the string "None" as the value + if (NoneType in typehints) and (value == "None"): + return None + + # If the field allows strings, we don't parse it - otherwise a validation error might be raised + # e.g. phone_number = "1234567890" should not be converted to an int if the type hint is str + if str in typehints: + return value + try: + evaluated_value = ast.literal_eval(value) + return evaluated_value + except Exception: + return value + + class Config: + # Ensure that validation happens every time a field is updated, not just when the artifact is created + validate_assignment = True + # Do not allow extra fields to be added to the artifact + extra = "forbid" diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/conversation_helpers.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/conversation_helpers.py new file mode 100644 index 00000000..49662a21 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/conversation_helpers.py @@ -0,0 +1,165 @@ +# Copyright (c) Microsoft. All rights reserved. + +# FIXME: Copied code from Semantic Kernel repo, using as-is despite type errors +# type: ignore + +import logging +import time +from dataclasses import dataclass, field +from enum import StrEnum +from typing import Union + +from semantic_kernel.contents import ChatMessageContent + + +class ConversationMessageType(StrEnum): + DEFAULT = "default" + ARTIFACT_UPDATE = "artifact-update" + REASONING = "reasoning" + + +@dataclass +class Conversation: + """An abstraction to represent a list of messages and common operations such as adding messages + and getting a string representation. + + Args: + conversation_messages (list[ChatMessageContent]): A list of ChatMessageContent objects. + """ + + logger = logging.getLogger(__name__) + conversation_messages: list[ChatMessageContent] = field(default_factory=list) + + def add_messages(self, messages: Union[ChatMessageContent, list[ChatMessageContent], "Conversation", None]) -> None: + """Add a message, list of messages to the conversation or merge another conversation into the end of this one. + + Args: + messages (Union[ChatMessageContent, list[ChatMessageContent], "Conversation"]): The message(s) to add. + All messages will be added to the end of the conversation. + + Returns: + None + """ + if isinstance(messages, list): + self.conversation_messages.extend(messages) + elif isinstance(messages, Conversation): + self.conversation_messages.extend(messages.conversation_messages) + elif isinstance(messages, ChatMessageContent): + # if ChatMessageContent.metadata doesn't have type, then add default + if "type" not in messages.metadata: + messages.metadata["type"] = ConversationMessageType.DEFAULT + self.conversation_messages.append(messages) + else: + self.logger.warning(f"Invalid message type: {type(messages)}") + return None + + def get_repr_for_prompt( + self, + exclude_types: list[ConversationMessageType] | None = None, + ) -> str: + """Create a string representation of the conversation history for use in LLM prompts. + + Args: + exclude_types (list[ConversationMessageType] | None): A list of message types to exclude from the conversation + history. If None, all message types will be included. + + Returns: + str: A string representation of the conversation history. + """ + if len(self.conversation_messages) == 0: + return "None" + + # Do not include the excluded messages types in the conversation history repr. + if exclude_types is not None: + conversation_messages = [ + message + for message in self.conversation_messages + if "type" in message.metadata and message.metadata["type"] not in exclude_types + ] + else: + conversation_messages = self.conversation_messages + + to_join = [] + current_turn = None + for message in conversation_messages: + participant_name = message.name + # Modify the default user to be capitalized for consistency with how assistant is written. + if participant_name == "user": + participant_name = "User" + + # If the turn number is None, don't include it in the string + if "turn_number" in message.metadata and current_turn != message.metadata["turn_number"]: + current_turn = message.metadata["turn_number"] + to_join.append(f"[Turn {current_turn}]") + + # Add the message content + if (message.role == "assistant") and ( + "type" in message.metadata and message.metadata["type"] == ConversationMessageType.ARTIFACT_UPDATE + ): + to_join.append(message.content) + elif message.role == "assistant": + to_join.append(f"Assistant: {message.content}") + else: + user_string = message.content.strip() + if user_string == "": + to_join.append(f"{participant_name}: ") + else: + to_join.append(f"{participant_name}: {user_string}") + conversation_string = "\n".join(to_join) + return conversation_string + + def message_to_json(self, message: ChatMessageContent) -> dict: + """ + Convert a ChatMessageContent object to a JSON serializable dictionary. + + Args: + message (ChatMessageContent): The ChatMessageContent object to convert to JSON. + + Returns: + dict: A JSON serializable dictionary representation of the ChatMessageContent object. + """ + return { + "role": message.role, + "content": message.content, + "name": message.name, + "metadata": { + "turn_number": message.metadata["turn_number"] if "turn_number" in message.metadata else None, + "type": message.metadata["type"] if "type" in message.metadata else ConversationMessageType.DEFAULT, + "timestamp": message.metadata["timestamp"] if "timestamp" in message.metadata else None, + }, + } + + def to_json(self) -> dict: + json_data = {} + json_data["conversation"] = {} + json_data["conversation"]["conversation_messages"] = [ + self.message_to_json(message) for message in self.conversation_messages + ] + return json_data + + @classmethod + def from_json( + cls, + json_data: dict, + ) -> "Conversation": + conversation = cls() + for message in json_data["conversation"]["conversation_messages"]: + conversation.add_messages( + ChatMessageContent( + role=message["role"], + content=message["content"], + name=message["name"], + metadata={ + "turn_number": message["metadata"]["turn_number"], + "type": ConversationMessageType(message["metadata"]["type"]), + "timestamp": message["metadata"]["timestamp"], + }, + ) + ) + + return conversation + + +def create_formatted_timestamp() -> str: + """Create a formatted timestamp.""" + return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())) diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/definition.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/definition.py new file mode 100644 index 00000000..a8befa22 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/definition.py @@ -0,0 +1,14 @@ +from dataclasses import dataclass +from typing import Optional + +from form_filler_skill.guided_conversation.resources import ResourceConstraint + + +@dataclass +class GCDefinition: + artifact_schema: str + rules: str + conversation_flow: Optional[str] + conversation_context: str + resource_constraint: Optional[ResourceConstraint] + service_id: str = "gc_main" diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/openai_tool_calling.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/openai_tool_calling.py new file mode 100644 index 00000000..1e567896 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/openai_tool_calling.py @@ -0,0 +1,167 @@ +# Copyright (c) Microsoft. All rights reserved. + +# FIXME: Copied code from Semantic Kernel repo, using as-is despite type errors +# type: ignore + +import json +import logging +from dataclasses import dataclass +from enum import Enum +from typing import Any + +from semantic_kernel.contents.function_call_content import FunctionCallContent +from semantic_kernel.functions import FunctionResult + +logger = logging.getLogger(__name__) + + +@dataclass +class ToolArg: + argument_name: str + required: bool + + +@dataclass +class Tool: + name: str + args: list[ToolArg] + + +class ToolValidationResult(Enum): + NO_TOOL_CALLED = "No tool was called" + INVALID_TOOL_CALLED = "A tool was called with an unexpected name" + MISSING_REQUIRED_ARGUMENT = "The tool called is missing a required argument" + INVALID_ARGUMENT_TYPE = "The value of an argument is of an unexpected type" + INVALID_ARGUMENT = "The tool called has an unexpected argument" + SUCCESS = "success" + + +def parse_function_result(response: FunctionResult) -> dict[str, Any]: + """Parse the response from SK's FunctionResult object into only the relevant data for easier downstream processing. + This should only be used when you expect the response to contain tool calls. + + Args: + response (FunctionResult): The response from the kernel. + + Returns: + dict[str, Any]: The parsed response data with the following format if n was set greater than 1: + { + "choices": [ + { + "tool_names": list[str], + "tool_args_list": list[dict[str, Any]], + "message": str, + "finish_reason": str, + "validation_result": ToolValidationResult + }, ... + ] + } + Otherwise, the response will directly contain the data from the first choice (tool_names, etc keys) + """ + response_data: dict[str, Any] = {"choices": []} + for response_choice in response.value: + response_data_curr = {} + finish_reason = response_choice.finish_reason + + if finish_reason == "tool_calls": + tool_names = [] + tool_args_list = [] + # Only look at the items that are of instance `FunctionCallContent` + tool_calls = [item for item in response_choice.items if isinstance(item, FunctionCallContent)] + for tool_call in tool_calls: + if "-" not in tool_call.name: + logger.info(f"Tool call name {tool_call.name} does not match naming convention - modifying name.") + tool_names.append(tool_call.name + "-" + tool_call.name) + else: + tool_names.append(tool_call.name) + try: + tool_args = json.loads(tool_call.arguments) + except json.JSONDecodeError: + logger.warning(f"Failed to parse tool arguments for tool call {tool_call.name}. Using empty dict.") + tool_args = {} + tool_args_list.append(tool_args) + response_data_curr["tool_names"] = tool_names + response_data_curr["tool_args_list"] = tool_args_list + + response_data_curr["message"] = response_choice.content + response_data_curr["finish_reason"] = finish_reason + response_data["choices"].append(response_data_curr) + + if len(response_data["choices"]) == 1: + response_data.update(response_data["choices"][0]) + del response_data["choices"] + + return response_data + + +def construct_tool_objects(kernel_function_tools: dict) -> list[Tool]: + """Construct a list of Tool objects from the kernel function tools definition. + + Args: + kernel_function_tools (dict): The definition of tools done by the kernel function. + + Returns: + list[Tool]: The list of Tool objects constructed from the kernel function tools definition. + """ + + tool_objects: list[Tool] = [] + for tool_definition in kernel_function_tools: + tool_name = tool_definition["function"]["name"] + tool_args = tool_definition["function"]["parameters"]["properties"] + + tool_arg_objects: list[ToolArg] = [] + for argument_name, _ in tool_args.items(): + tool_arg = ToolArg(argument_name=argument_name, required=False) + tool_arg_objects.append(tool_arg) + + required_args = tool_definition["function"]["parameters"]["required"] + for tool_arg_object in tool_arg_objects: + if tool_arg_object.argument_name in required_args: + tool_arg_object.required = True + + tool_objects.append(Tool(name=tool_name, args=tool_arg_objects)) + return tool_objects + + +def validate_tool_calling(response: dict[str, Any], request_tool_param: dict) -> ToolValidationResult: + """Validate that the response from the LLM called tools corrected. + 1. Check if any tool was called. + 2. Check if the tools called were valid (names match) + 3. Check if all the required arguments were passed. + + Args: + response (dict[str, Any]): The response from the LLM containing the tools called (output of parse_function_result) + tools (list[Tool]): The list of tools that can be called by the model. + + Returns: + ToolValidationResult: The result of the validation. ToolValidationResult.SUCCESS if the validation passed. + """ + + tool_objects = construct_tool_objects(request_tool_param) + tool_names = response.get("tool_names", []) + tool_args_list = response.get("tool_args_list", []) + + # Check if any tool was called. + if not tool_names: + logger.info("No tool was called.") + return ToolValidationResult.NO_TOOL_CALLED + + for tool_name, tool_args in zip(tool_names, tool_args_list, strict=True): + # Check the tool names is valid. + tool: Tool | None = next((t for t in tool_objects if t.name == tool_name), None) + if not tool: + logger.warning(f"Invalid tool called: {tool_name}") + return ToolValidationResult.INVALID_TOOL_CALLED + + for arg in tool.args: + # Check if the required arguments were passed. + if arg.required and arg.argument_name not in tool_args: + logger.warning(f"Missing required argument '{arg.argument_name}' for tool '{tool_name}'.") + return ToolValidationResult.MISSING_REQUIRED_ARGUMENT + + for tool_arg_name in tool_args.keys(): + if tool_arg_name not in [arg.argument_name for arg in tool.args]: + logger.warning(f"Unexpected argument '{tool_arg_name}' for tool '{tool_name}'.") + return ToolValidationResult.INVALID_ARGUMENT + + return ToolValidationResult.SUCCESS diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/plugin_helpers.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/plugin_helpers.py new file mode 100644 index 00000000..ba32e4df --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/plugin_helpers.py @@ -0,0 +1,69 @@ +# # Copyright (c) Microsoft. All rights reserved. + +# FIXME: Copied code from Semantic Kernel repo, using as-is despite type errors +# type: ignore + +from dataclasses import dataclass + +from pydantic import ValidationError +from semantic_kernel import Kernel +from semantic_kernel.connectors.ai.function_calling_utils import kernel_function_metadata_to_function_call_format +from semantic_kernel.contents import ChatMessageContent + + +@dataclass +class PluginOutput: + """A wrapper for all Guided Conversation Plugins. This class is used to return the output of a generic plugin. + + Args: + update_successful (bool): Whether the update was successful. + messages (list[ChatMessageContent]): A list of messages to be used at the user's digression, it + contains information about the process of calling the plugin. + """ + + update_successful: bool + messages: list[ChatMessageContent] + + +def format_kernel_functions_as_tools(kernel: Kernel, functions: list[str]): + """Format kernel functions as JSON schemas for custom validation.""" + formatted_tools = [] + for _, kernel_plugin_def in kernel.plugins.items(): + for function_name, function_def in kernel_plugin_def.functions.items(): + if function_name in functions: + func_metadata = function_def.metadata + formatted_tools.append(kernel_function_metadata_to_function_call_format(func_metadata)) + return formatted_tools + + +def update_attempts( + error: Exception, attempt_id: str, previous_attempts: list[tuple[str, str]] +) -> tuple[list[tuple[str, str]], str]: + """ + Updates the plugin class attribute list of previous attempts with the current attempt and error message + (including duplicates). + + Args: + error (Exception): The error object. + attempt_id (str): The ID of the current attempt. + previous_attempts (list): The list of previous attempts. + + Returns: + str: A formatted (optimized for LLM performance) string of previous attempts, with duplicates removed. + """ + if isinstance(error, ValidationError): + error_str = "; ".join([e.get("msg") for e in error.errors()]) + # replace "; Input should be 'Unanswered'" with " or input should be 'Unanswered'" for clarity + error_str = error_str.replace("; Input should be 'Unanswered'", " or input should be 'Unanswered'") + else: + error_str = str(error) + new_failed_attempt = (attempt_id, error_str) + previous_attempts.append(new_failed_attempt) + + # Format previous attempts to be more friendly for the LLM + attempts_list = [] + for attempt, error in previous_attempts: + attempts_list.append(f"Attempt: {attempt}\nError: {error}") + llm_formatted_attempts = "\n".join(attempts_list) + + return previous_attempts, llm_formatted_attempts diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/resources.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/resources.py new file mode 100644 index 00000000..103966f5 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/resources.py @@ -0,0 +1,254 @@ +# Copyright (c) Microsoft. All rights reserved. + +# FIXME: Copied code from Semantic Kernel repo, using as-is despite type errors +# type: ignore + +import logging +import math +import time +from enum import StrEnum + +from pydantic import BaseModel + + +class ResourceConstraintUnit(StrEnum): + """Choose the unit of the resource constraint. + Seconds and Minutes are real-time and will be impacted by the latency of the model.""" + + SECONDS = "seconds" + MINUTES = "minutes" + TURNS = "turns" + + +class ResourceConstraintMode(StrEnum): + """Choose how the agent should use the resource. + Maximum: is an upper bound, i.e. the agent can end the conversation before the resource is exhausted + Exact: the agent should aim to use exactly the given amount of the resource""" + + MAXIMUM = "maximum" + EXACT = "exact" + + +class ResourceConstraint(BaseModel): + """A structured representation of the resource constraint for the GuidedConversation agent. + + Args: + quantity (float | int): The quantity of the resource constraint. + unit (ResourceConstraintUnit): The unit of the resource constraint. + mode (ResourceConstraintMode): The mode of the resource constraint. + """ + + quantity: float | int + unit: ResourceConstraintUnit + mode: ResourceConstraintMode + + class Config: + arbitrary_types_allowed = True + + +def format_resource(quantity: float, unit: ResourceConstraintUnit) -> str: + """Get formatted string for a given quantity and unit (e.g. 1 second, 20 seconds)""" + if unit != ResourceConstraintUnit.TURNS: + quantity = round(quantity, 1) + unit = unit.value + return f"{quantity} {unit[:-1] if quantity == 1 else unit}" + + +class GCResource: + """Resource constraints for the GuidedConversation agent. This class is used to keep track of the resource + constraints. If resource_constraint is None, then the agent can continue indefinitely. This also means + that no agenda will be created for the conversation. + + Args: + resource_constraint (ResourceConstraint | None): The resource constraint for the conversation. + initial_seconds_per_turn (int): The initial number of seconds per turn. Defaults to 120 seconds. + """ + + def __init__( + self, + resource_constraint: ResourceConstraint | None, + initial_seconds_per_turn: int = 120, + ): + logger = logging.getLogger(__name__) + self.logger = logger + self.resource_constraint: ResourceConstraint | None = resource_constraint + self.initial_seconds_per_turn: int = initial_seconds_per_turn + + self.turn_number: int = 0 + self.remaining_units: float | None = None + self.elapsed_units: float | None = None + + if resource_constraint is not None: + self.elapsed_units = 0 + self.remaining_units = resource_constraint.quantity + + def start_resource(self) -> None: + """To be called at the start of a conversation turn""" + if self.resource_constraint is not None and ( + self.resource_constraint.unit == ResourceConstraintUnit.SECONDS + or self.resource_constraint.unit == ResourceConstraintUnit.MINUTES + ): + self.start_time = time.time() + + def increment_resource(self) -> None: + """Increment the resource counter by one turn.""" + if self.resource_constraint is not None: + if self.resource_constraint.unit == ResourceConstraintUnit.SECONDS: + self.elapsed_units += time.time() - self.start_time + self.remaining_units = self.resource_constraint.quantity - self.elapsed_units + elif self.resource_constraint.unit == ResourceConstraintUnit.MINUTES: + self.elapsed_units += (time.time() - self.start_time) / 60 + self.remaining_units = self.resource_constraint.quantity - self.elapsed_units + elif self.resource_constraint.unit == ResourceConstraintUnit.TURNS: + self.elapsed_units += 1 + self.remaining_units -= 1 + + self.turn_number += 1 + + def get_resource_mode(self) -> ResourceConstraintMode: + """Get the mode of the resource constraint. + + Returns: + ResourceConstraintMode | None: The mode of the resource constraint, or None if there is no + resource constraint. + """ + return self.resource_constraint.mode if self.resource_constraint is not None else None + + def get_elapsed_turns(self, formatted_repr: bool = False) -> str | int: + """Get the number of elapsed turns. + + Args: + formatted_repr (bool): If true, return a formatted string representation of the elapsed turns. + If false, return an integer. Defaults to False. + + Returns: + str | int: The description/number of elapsed turns. + """ + if formatted_repr: + return format_resource(self.turn_number, ResourceConstraintUnit.TURNS) + else: + return self.turn_number + + def get_remaining_turns(self, formatted_repr: bool = False) -> str | int: + """Get the number of remaining turns. + + Args: + formatted_repr (bool): If true, return a formatted string representation of the remaining turns. + + Returns: + str | int: The description/number of remaining turns. + """ + if formatted_repr: + return format_resource(self.estimate_remaining_turns(), ResourceConstraintUnit.TURNS) + else: + return self.estimate_remaining_turns() + + def estimate_remaining_turns(self) -> int: + """Estimate the remaining turns based on the resource constraint, thereby translating certain + resource units (e.g. seconds, minutes) into turns. + + Returns: + int: The estimated number of remaining turns. + """ + if self.resource_constraint is not None: + if ( + self.resource_constraint.unit == ResourceConstraintUnit.SECONDS + or self.resource_constraint.unit == ResourceConstraintUnit.MINUTES + ): + elapsed_turns = self.turn_number + + # TODO: This can likely be simplified + if self.resource_constraint.unit == ResourceConstraintUnit.MINUTES: + time_per_turn = ( + self.initial_seconds_per_turn + if elapsed_turns == 0 + else (self.elapsed_units * 60) / elapsed_turns + ) + time_per_turn /= 60 + else: + time_per_turn = ( + self.initial_seconds_per_turn if elapsed_turns == 0 else self.elapsed_units / elapsed_turns + ) + remaining_turns = self.remaining_units / time_per_turn + + # Round down, unless it's less than 1, in which case round up + remaining_turns = math.ceil(remaining_turns) if remaining_turns < 1 else math.floor(remaining_turns) + return remaining_turns + elif self.resource_constraint.unit == ResourceConstraintUnit.TURNS: + return self.resource_constraint.quantity - self.turn_number + else: + self.logger.error( + "Resource constraint is not set, so turns cannot be estimated using function estimate_remaining_turns" + ) + raise ValueError( + "Resource constraint is not set. Do not try to call this method without a resource constraint." + ) + + def get_resource_instructions(self) -> tuple[str, str]: + """Get the resource instructions for the conversation. + + Assumes we're always using turns as the resource unit. + + Returns: + str: the resource instructions + """ + if self.resource_constraint is None: + return "" + + formatted_elapsed_resource = format_resource(self.elapsed_units, ResourceConstraintUnit.TURNS) + formatted_remaining_resource = format_resource(self.remaining_units, ResourceConstraintUnit.TURNS) + + # if the resource quantity is anything other than 1, the resource unit should be plural (e.g. "minutes" instead of "minute") + is_plural_elapsed = self.elapsed_units != 1 + is_plural_remaining = self.remaining_units != 1 + + if self.elapsed_units > 0: + resource_instructions = f"So far, {formatted_elapsed_resource} {'have' if is_plural_elapsed else 'has'} elapsed since the conversation began. " + else: + resource_instructions = "" + + if self.resource_constraint.mode == ResourceConstraintMode.EXACT: + exact_mode_instructions = f"""There {"are" if is_plural_remaining else "is"} {formatted_remaining_resource} remaining (including this one) - the conversation will automatically terminate when 0 turns are left. \ +You should continue the conversation until it is automatically terminated. This means you should NOT preemptively end the conversation, \ +either explicitly (by selecting the "End conversation" action) or implicitly (e.g. by telling the user that you have all required information and they should wait for the next step). \ +Your goal is not to maximize efficiency (i.e. complete the artifact as quickly as possible then end the conversation), but rather to make the best use of ALL remaining turns available to you""" + + if is_plural_remaining: + resource_instructions += f"""{exact_mode_instructions}. This will require you to plan your actions carefully using the agenda: you want to avoid the situation where you have to pack too many topics into the final turns because you didn't account for them earlier, \ +or where you've rushed through the conversation and all fields are completed but there are still many turns left.""" + + # special instruction for the final turn (i.e. 1 remaining) in exact mode + else: + resource_instructions += f"""{exact_mode_instructions}, including this one. Therefore, you should use this turn to ask for any remaining information needed to complete the artifact, \ + or, if the artifact is already completed, continue to broaden/deepen the discussion in a way that's directly relevant to the artifact. Do NOT indicate to the user that the conversation is ending.""" + + elif self.resource_constraint.mode == ResourceConstraintMode.MAXIMUM: + resource_instructions += f"""You have a maximum of {formatted_remaining_resource} (including this one) left to complete the conversation. \ +You can decide to terminate the conversation at any point (including now), otherwise the conversation will automatically terminate when 0 turns are left. \ +You will need to plan your actions carefully using the agenda: you want to avoid the situation where you have to pack too many topics into the final turns because you didn't account for them earlier.""" + + else: + self.logger.error("Invalid resource mode provided.") + + return resource_instructions + + def to_json(self) -> dict: + return { + "turn_number": self.turn_number, + "remaining_units": self.remaining_units, + "elapsed_units": self.elapsed_units, + } + + @classmethod + def from_json( + cls, + json_data: dict, + ) -> "GCResource": + gc_resource = cls( + resource_constraint=None, + initial_seconds_per_turn=120, + ) + gc_resource.turn_number = json_data["turn_number"] + gc_resource.remaining_units = json_data["remaining_units"] + gc_resource.elapsed_units = json_data["elapsed_units"] + return gc_resource diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py new file mode 100644 index 00000000..1701d37d --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py @@ -0,0 +1,132 @@ +from typing import Any, Optional + +from chat_driver import ChatDriverConfig +from context import Context +from skill_library import FunctionRoutine, RoutineTypes, Skill +from skill_library.skill_registry import SkillRegistry + +from form_filler_skill.guided_conversation.definition import GCDefinition + +from .chat_drivers.gc_final_update import final_update +from .chat_drivers.gc_update_agenda import update_agenda +from .chat_drivers.gc_update_artifact import update_artifact + +NAME = "guided-conversation" +CLASS_NAME = "GuidedConversationSkill" +DESCRIPTION = ( + "Walks the user through a conversation about gathering info for the creation of an artifact." +) +DEFAULT_MAX_RETRIES = 3 +INSTRUCTIONS = "You are an assistant." + + +class GuidedConversationSkill(Skill): + def __init__( + self, + chat_driver_config: ChatDriverConfig, + ) -> None: + # Put all functions in a group. We are going to use all these as (1) + # skill actions, but also as (2) chat functions and (3) chat commands. + # You can also put them in separate lists if you want to differentiate + # between these. + functions = [ + self.update_agenda, + self.update_artifact, + self.final_update, + ] + + # Add some skill routines. + routines: list[RoutineTypes] = [ + self.conversation_routine, + ] + + # Configure the skill's chat driver. + chat_driver_config.instructions = INSTRUCTIONS + chat_driver_config.commands = functions + chat_driver_config.functions = functions + + # Initialize the skill! + super().__init__( + name=NAME, + description=DESCRIPTION, + chat_driver_config=chat_driver_config, + skill_actions=functions, + routines=routines, + ) + + ################################## + # Routines + ################################## + + def conversation_routine(self) -> FunctionRoutine: + return FunctionRoutine( + name="conversation", + description="Run a guided conversation.", + init_function=self.conversation_init_function, + step_function=self.conversation_step_function, + skill=self, + ) + + async def conversation_init_function( + self, skill_registry: SkillRegistry, context: Context, vars: Optional[dict[str, Any]] + ): + if vars is None: + return + state = {"definition": vars["definition"]} + skill_registry.routine_stack.update_current_state(state) + await self.conversation_step_function(skill_registry, context) + + async def conversation_step_function( + self, + skill_registry: SkillRegistry, + context: Context, + message: Optional[str] = None, + ): + frame = skill_registry.routine_stack.peek() + state = frame.state if frame else {} + definition = GCDefinition(**state["definition"]) + while True: + match state["mode"]: + case None: + state["mode"] = "init" + case "init": + state["chat_history"] = [] + message, done = self.update_agenda(context, definition) + if done: + state["mode"] = "finalize" + state["mode"] = "conversation" + runner.send(message) + return + case "conversation": + state["chat_history"] += message + state["artifact"] = self.update_artifact(context) + message, done = self.update_agenda() + if done: + state["mode"] = "finalize" + runner.send(message) + return + case "finalize": + message = self.final_update() + state["state"] = "done" + runner.send(message) + return + case "done": + return state["artifact"] + + ################################## + # Actions + ################################## + + def update_agenda(self, context: Context, definition: GCDefinition): + update_agenda( + context, + self.openai_client, + definition, + self.chat_driver.message_provider.get(), + ) + + def update_artifact(self, context: Context): + update_artifact(context) + + def final_update(self, context: Context): + final_update(context) diff --git a/libraries/python/skills/skills/form-filler-skill/pyproject.toml b/libraries/python/skills/skills/form-filler-skill/pyproject.toml new file mode 100644 index 00000000..83139534 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/pyproject.toml @@ -0,0 +1,26 @@ +[project] +name = "form-filler-skill" +version = "0.1.0" +description = "MADE:Exploration Form-filler skill" +authors = [{name="MADE:Explorers"}] +readme = "README.md" +requires-python = ">=3.11" +dependencies = [ + "skill-library>=0.1.0", + "chat-driver>=0.1.0", + "context>=0.1.0", + "events>=0.1.0", +] + +[tool.uv] +package = true + +[tool.uv.sources] +skill-library = { path = "../../skill-library", editable= true } +chat-driver = { path = "../../../chat-driver", editable = true } +context = { path = "../../../context", editable = true } +events = { path = "../../../events", editable = true } + +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" diff --git a/libraries/python/skills/skills/form-filler-skill/uv.lock b/libraries/python/skills/skills/form-filler-skill/uv.lock new file mode 100644 index 00000000..0bb68af5 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/uv.lock @@ -0,0 +1,804 @@ +version = 1 +requires-python = ">=3.11" +resolution-markers = [ + "python_full_version < '3.13'", + "python_full_version >= '3.13'", +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, +] + +[[package]] +name = "anyio" +version = "4.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "sniffio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/78/49/f3f17ec11c4a91fe79275c426658e509b07547f874b14c1a526d86a83fc8/anyio-4.6.0.tar.gz", hash = "sha256:137b4559cbb034c477165047febb6ff83f390fc3b20bf181c1fc0a728cb8beeb", size = 170983 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/ef/7a4f225581a0d7886ea28359179cb861d7fbcdefad29663fc1167b86f69f/anyio-4.6.0-py3-none-any.whl", hash = "sha256:c7d2e9d63e31599eeb636c8c5c03a7e108d73b345f064f1c19fdc87b79036a9a", size = 89631 }, +] + +[[package]] +name = "assistant-drive" +version = "0.1.0" +source = { editable = "../../../assistant-drive" } +dependencies = [ + { name = "context" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, +] + +[package.metadata] +requires-dist = [ + { name = "context", editable = "../../../context" }, + { name = "pydantic", specifier = ">=2.6.1" }, + { name = "pydantic-settings", specifier = ">=2.5.2" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "ipykernel", specifier = ">=6.29.5" }, + { name = "pytest", specifier = ">=8.3.1" }, + { name = "pytest-asyncio", specifier = ">=0.23.8" }, + { name = "pytest-repeat", specifier = ">=0.9.3" }, +] + +[[package]] +name = "azure-core" +version = "1.31.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, + { name = "six" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/03/7a/f79ad135a276a37e61168495697c14ba1721a52c3eab4dae2941929c79f8/azure_core-1.31.0.tar.gz", hash = "sha256:656a0dd61e1869b1506b7c6a3b31d62f15984b1a573d6326f6aa2f3e4123284b", size = 277147 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/8e/fcb6a77d3029d2a7356f38dbc77cf7daa113b81ddab76b5593d23321e44c/azure_core-1.31.0-py3-none-any.whl", hash = "sha256:22954de3777e0250029360ef31d80448ef1be13b80a459bff80ba7073379e2cd", size = 197399 }, +] + +[[package]] +name = "azure-identity" +version = "1.18.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "azure-core" }, + { name = "cryptography" }, + { name = "msal" }, + { name = "msal-extensions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b3/5d/1c7da35dd640b4a95a38f980bb6b0b56c4e91d5b3d518ac11a2c4ebf5f62/azure_identity-1.18.0.tar.gz", hash = "sha256:f567579a65d8932fa913c76eddf3305101a15e5727a5e4aa5df649a0f553d4c3", size = 263322 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b0/71/1d1bb387b6acaa5daa3e703c70dde3d54823ccd229bd6730de6e724f296e/azure_identity-1.18.0-py3-none-any.whl", hash = "sha256:bccf6106245b49ff41d0c4cd7b72851c5a2ba3a32cef7589da246f5727f26f02", size = 187179 }, +] + +[[package]] +name = "certifi" +version = "2024.8.30" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/ee/9b19140fe824b367c04c5e1b369942dd754c4c5462d5674002f75c4dedc1/certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9", size = 168507 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", size = 167321 }, +] + +[[package]] +name = "cffi" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264 }, + { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651 }, + { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259 }, + { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200 }, + { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235 }, + { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721 }, + { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242 }, + { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999 }, + { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242 }, + { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604 }, + { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727 }, + { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400 }, + { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178 }, + { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840 }, + { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803 }, + { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850 }, + { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729 }, + { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256 }, + { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424 }, + { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568 }, + { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 }, + { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 }, + { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 }, + { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 }, + { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 }, + { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 }, + { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 }, + { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 }, + { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 }, + { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 }, + { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 }, + { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 }, + { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 }, + { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 }, +] + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/63/09/c1bc53dab74b1816a00d8d030de5bf98f724c52c1635e07681d312f20be8/charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", size = 104809 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/77/02839016f6fbbf808e8b38601df6e0e66c17bbab76dff4613f7511413597/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", size = 191647 }, + { url = "https://files.pythonhosted.org/packages/3e/33/21a875a61057165e92227466e54ee076b73af1e21fe1b31f1e292251aa1e/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", size = 121434 }, + { url = "https://files.pythonhosted.org/packages/dd/51/68b61b90b24ca35495956b718f35a9756ef7d3dd4b3c1508056fa98d1a1b/charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", size = 118979 }, + { url = "https://files.pythonhosted.org/packages/e4/a6/7ee57823d46331ddc37dd00749c95b0edec2c79b15fc0d6e6efb532e89ac/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", size = 136582 }, + { url = "https://files.pythonhosted.org/packages/74/f1/0d9fe69ac441467b737ba7f48c68241487df2f4522dd7246d9426e7c690e/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", size = 146645 }, + { url = "https://files.pythonhosted.org/packages/05/31/e1f51c76db7be1d4aef220d29fbfa5dbb4a99165d9833dcbf166753b6dc0/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", size = 139398 }, + { url = "https://files.pythonhosted.org/packages/40/26/f35951c45070edc957ba40a5b1db3cf60a9dbb1b350c2d5bef03e01e61de/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", size = 140273 }, + { url = "https://files.pythonhosted.org/packages/07/07/7e554f2bbce3295e191f7e653ff15d55309a9ca40d0362fcdab36f01063c/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", size = 142577 }, + { url = "https://files.pythonhosted.org/packages/d8/b5/eb705c313100defa57da79277d9207dc8d8e45931035862fa64b625bfead/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", size = 137747 }, + { url = "https://files.pythonhosted.org/packages/19/28/573147271fd041d351b438a5665be8223f1dd92f273713cb882ddafe214c/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", size = 143375 }, + { url = "https://files.pythonhosted.org/packages/cf/7c/f3b682fa053cc21373c9a839e6beba7705857075686a05c72e0f8c4980ca/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", size = 148474 }, + { url = "https://files.pythonhosted.org/packages/1e/49/7ab74d4ac537ece3bc3334ee08645e231f39f7d6df6347b29a74b0537103/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", size = 140232 }, + { url = "https://files.pythonhosted.org/packages/2d/dc/9dacba68c9ac0ae781d40e1a0c0058e26302ea0660e574ddf6797a0347f7/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", size = 140859 }, + { url = "https://files.pythonhosted.org/packages/6c/c2/4a583f800c0708dd22096298e49f887b49d9746d0e78bfc1d7e29816614c/charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", size = 92509 }, + { url = "https://files.pythonhosted.org/packages/57/ec/80c8d48ac8b1741d5b963797b7c0c869335619e13d4744ca2f67fc11c6fc/charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", size = 99870 }, + { url = "https://files.pythonhosted.org/packages/d1/b2/fcedc8255ec42afee97f9e6f0145c734bbe104aac28300214593eb326f1d/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", size = 192892 }, + { url = "https://files.pythonhosted.org/packages/2e/7d/2259318c202f3d17f3fe6438149b3b9e706d1070fe3fcbb28049730bb25c/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", size = 122213 }, + { url = "https://files.pythonhosted.org/packages/3a/52/9f9d17c3b54dc238de384c4cb5a2ef0e27985b42a0e5cc8e8a31d918d48d/charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", size = 119404 }, + { url = "https://files.pythonhosted.org/packages/99/b0/9c365f6d79a9f0f3c379ddb40a256a67aa69c59609608fe7feb6235896e1/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", size = 137275 }, + { url = "https://files.pythonhosted.org/packages/91/33/749df346e93d7a30cdcb90cbfdd41a06026317bfbfb62cd68307c1a3c543/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", size = 147518 }, + { url = "https://files.pythonhosted.org/packages/72/1a/641d5c9f59e6af4c7b53da463d07600a695b9824e20849cb6eea8a627761/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", size = 140182 }, + { url = "https://files.pythonhosted.org/packages/ee/fb/14d30eb4956408ee3ae09ad34299131fb383c47df355ddb428a7331cfa1e/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", size = 141869 }, + { url = "https://files.pythonhosted.org/packages/df/3e/a06b18788ca2eb6695c9b22325b6fde7dde0f1d1838b1792a0076f58fe9d/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", size = 144042 }, + { url = "https://files.pythonhosted.org/packages/45/59/3d27019d3b447a88fe7e7d004a1e04be220227760264cc41b405e863891b/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", size = 138275 }, + { url = "https://files.pythonhosted.org/packages/7b/ef/5eb105530b4da8ae37d506ccfa25057961b7b63d581def6f99165ea89c7e/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", size = 144819 }, + { url = "https://files.pythonhosted.org/packages/a2/51/e5023f937d7f307c948ed3e5c29c4b7a3e42ed2ee0b8cdf8f3a706089bf0/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", size = 149415 }, + { url = "https://files.pythonhosted.org/packages/24/9d/2e3ef673dfd5be0154b20363c5cdcc5606f35666544381bee15af3778239/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", size = 141212 }, + { url = "https://files.pythonhosted.org/packages/5b/ae/ce2c12fcac59cb3860b2e2d76dc405253a4475436b1861d95fe75bdea520/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", size = 142167 }, + { url = "https://files.pythonhosted.org/packages/ed/3a/a448bf035dce5da359daf9ae8a16b8a39623cc395a2ffb1620aa1bce62b0/charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", size = 93041 }, + { url = "https://files.pythonhosted.org/packages/b6/7c/8debebb4f90174074b827c63242c23851bdf00a532489fba57fef3416e40/charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", size = 100397 }, + { url = "https://files.pythonhosted.org/packages/28/76/e6222113b83e3622caa4bb41032d0b1bf785250607392e1b778aca0b8a7d/charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", size = 48543 }, +] + +[[package]] +name = "chat-driver" +version = "0.1.0" +source = { editable = "../../../chat-driver" } +dependencies = [ + { name = "azure-identity" }, + { name = "context" }, + { name = "events" }, + { name = "function-registry" }, + { name = "openai" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "python-dotenv" }, + { name = "python-liquid" }, + { name = "requests" }, + { name = "tiktoken" }, +] + +[package.metadata] +requires-dist = [ + { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "context", editable = "../../../context" }, + { name = "events", editable = "../../../events" }, + { name = "function-registry", editable = "../../../function-registry" }, + { name = "openai", specifier = ">=1.16.1" }, + { name = "pydantic", specifier = ">=2.6.1" }, + { name = "pydantic-settings", specifier = ">=2.3.4" }, + { name = "python-dotenv", specifier = ">=1.0.1" }, + { name = "python-liquid", specifier = ">=1.12.1" }, + { name = "requests", specifier = ">=2.32.0" }, + { name = "tiktoken", specifier = ">=0.7.0" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, +] + +[[package]] +name = "context" +version = "0.1.0" +source = { editable = "../../../context" } +dependencies = [ + { name = "events" }, +] + +[package.metadata] +requires-dist = [{ name = "events", editable = "../../../events" }] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.1" }, + { name = "pytest-asyncio", specifier = ">=0.23.8" }, + { name = "pytest-repeat", specifier = ">=0.9.3" }, +] + +[[package]] +name = "cryptography" +version = "43.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/de/ba/0664727028b37e249e73879348cc46d45c5c1a2a2e81e8166462953c5755/cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d", size = 686927 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/28/b92c98a04ba762f8cdeb54eba5c4c84e63cac037a7c5e70117d337b15ad6/cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d", size = 6223222 }, + { url = "https://files.pythonhosted.org/packages/33/13/1193774705783ba364121aa2a60132fa31a668b8ababd5edfa1662354ccd/cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062", size = 3794751 }, + { url = "https://files.pythonhosted.org/packages/5e/4b/39bb3c4c8cfb3e94e736b8d8859ce5c81536e91a1033b1d26770c4249000/cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962", size = 3981827 }, + { url = "https://files.pythonhosted.org/packages/ce/dc/1471d4d56608e1013237af334b8a4c35d53895694fbb73882d1c4fd3f55e/cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277", size = 3780034 }, + { url = "https://files.pythonhosted.org/packages/ad/43/7a9920135b0d5437cc2f8f529fa757431eb6a7736ddfadfdee1cc5890800/cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a", size = 3993407 }, + { url = "https://files.pythonhosted.org/packages/cc/42/9ab8467af6c0b76f3d9b8f01d1cf25b9c9f3f2151f4acfab888d21c55a72/cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042", size = 3886457 }, + { url = "https://files.pythonhosted.org/packages/a4/65/430509e31700286ec02868a2457d2111d03ccefc20349d24e58d171ae0a7/cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494", size = 4081499 }, + { url = "https://files.pythonhosted.org/packages/bb/18/a04b6467e6e09df8c73b91dcee8878f4a438a43a3603dc3cd6f8003b92d8/cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2", size = 2616504 }, + { url = "https://files.pythonhosted.org/packages/cc/73/0eacbdc437202edcbdc07f3576ed8fb8b0ab79d27bf2c5d822d758a72faa/cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d", size = 3067456 }, + { url = "https://files.pythonhosted.org/packages/8a/b6/bc54b371f02cffd35ff8dc6baba88304d7cf8e83632566b4b42e00383e03/cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d", size = 6225263 }, + { url = "https://files.pythonhosted.org/packages/00/0e/8217e348a1fa417ec4c78cd3cdf24154f5e76fd7597343a35bd403650dfd/cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806", size = 3794368 }, + { url = "https://files.pythonhosted.org/packages/3d/ed/38b6be7254d8f7251fde8054af597ee8afa14f911da67a9410a45f602fc3/cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85", size = 3981750 }, + { url = "https://files.pythonhosted.org/packages/64/f3/b7946c3887cf7436f002f4cbb1e6aec77b8d299b86be48eeadfefb937c4b/cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c", size = 3778925 }, + { url = "https://files.pythonhosted.org/packages/ac/7e/ebda4dd4ae098a0990753efbb4b50954f1d03003846b943ea85070782da7/cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1", size = 3993152 }, + { url = "https://files.pythonhosted.org/packages/43/f6/feebbd78a3e341e3913846a3bb2c29d0b09b1b3af1573c6baabc2533e147/cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa", size = 3886392 }, + { url = "https://files.pythonhosted.org/packages/bd/4c/ab0b9407d5247576290b4fd8abd06b7f51bd414f04eef0f2800675512d61/cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4", size = 4082606 }, + { url = "https://files.pythonhosted.org/packages/05/36/e532a671998d6fcfdb9122da16434347a58a6bae9465e527e450e0bc60a5/cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47", size = 2617948 }, + { url = "https://files.pythonhosted.org/packages/b3/c6/c09cee6968add5ff868525c3815e5dccc0e3c6e89eec58dc9135d3c40e88/cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb", size = 3070445 }, +] + +[[package]] +name = "distro" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277 }, +] + +[[package]] +name = "events" +version = "0.1.0" +source = { editable = "../../../events" } +dependencies = [ + { name = "pydantic" }, +] + +[package.metadata] +requires-dist = [{ name = "pydantic", specifier = ">=2.6.1" }] + +[[package]] +name = "form-filler-skill" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "chat-driver" }, + { name = "context" }, + { name = "events" }, + { name = "skill-library" }, +] + +[package.metadata] +requires-dist = [ + { name = "chat-driver", editable = "../../../chat-driver" }, + { name = "context", editable = "../../../context" }, + { name = "events", editable = "../../../events" }, + { name = "skill-library", editable = "../../skill-library" }, +] + +[[package]] +name = "function-registry" +version = "0.1.0" +source = { editable = "../../../function-registry" } +dependencies = [ + { name = "azure-identity" }, + { name = "context" }, + { name = "openai" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "python-dotenv" }, + { name = "requests" }, + { name = "tiktoken" }, +] + +[package.metadata] +requires-dist = [ + { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "context", editable = "../../../context" }, + { name = "openai", specifier = ">=1.16.1" }, + { name = "pydantic", specifier = ">=2.6.1" }, + { name = "pydantic-settings", specifier = ">=2.3.4" }, + { name = "python-dotenv", specifier = ">=1.0.1" }, + { name = "requests", specifier = ">=2.32.0" }, + { name = "tiktoken", specifier = ">=0.7.0" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.1" }, + { name = "pytest-asyncio", specifier = ">=0.23.8" }, + { name = "pytest-repeat", specifier = ">=0.9.3" }, +] + +[[package]] +name = "h11" +version = "0.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 }, +] + +[[package]] +name = "httpcore" +version = "1.0.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b6/44/ed0fa6a17845fb033bd885c03e842f08c1b9406c86a2e60ac1ae1b9206a6/httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f", size = 85180 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/89/b161908e2f51be56568184aeb4a880fd287178d176fd1c860d2217f41106/httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f", size = 78011 }, +] + +[[package]] +name = "httpx" +version = "0.27.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, + { name = "sniffio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/78/82/08f8c936781f67d9e6b9eeb8a0c8b4e406136ea4c3d1f89a5db71d42e0e6/httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2", size = 144189 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0", size = 76395 }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, +] + +[[package]] +name = "importlib-resources" +version = "6.4.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/98/be/f3e8c6081b684f176b761e6a2fef02a0be939740ed6f54109a2951d806f3/importlib_resources-6.4.5.tar.gz", hash = "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065", size = 43372 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl", hash = "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717", size = 36115 }, +] + +[[package]] +name = "jiter" +version = "0.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/1a/aa64be757afc614484b370a4d9fc1747dc9237b37ce464f7f9d9ca2a3d38/jiter-0.5.0.tar.gz", hash = "sha256:1d916ba875bcab5c5f7d927df998c4cb694d27dceddf3392e58beaf10563368a", size = 158300 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/5f/3ac960ed598726aae46edea916e6df4df7ff6fe084bc60774b95cf3154e6/jiter-0.5.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d4c8e1ed0ef31ad29cae5ea16b9e41529eb50a7fba70600008e9f8de6376d553", size = 284131 }, + { url = "https://files.pythonhosted.org/packages/03/eb/2308fa5f5c14c97c4c7720fef9465f1fa0771826cddb4eec9866bdd88846/jiter-0.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6f16e21276074a12d8421692515b3fd6d2ea9c94fd0734c39a12960a20e85f3", size = 299310 }, + { url = "https://files.pythonhosted.org/packages/3c/f6/dba34ca10b44715fa5302b8e8d2113f72eb00a9297ddf3fa0ae4fd22d1d1/jiter-0.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5280e68e7740c8c128d3ae5ab63335ce6d1fb6603d3b809637b11713487af9e6", size = 332282 }, + { url = "https://files.pythonhosted.org/packages/69/f7/64e0a7439790ec47f7681adb3871c9d9c45fff771102490bbee5e92c00b7/jiter-0.5.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:583c57fc30cc1fec360e66323aadd7fc3edeec01289bfafc35d3b9dcb29495e4", size = 342370 }, + { url = "https://files.pythonhosted.org/packages/55/31/1efbfff2ae8e4d919144c53db19b828049ad0622a670be3bbea94a86282c/jiter-0.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26351cc14507bdf466b5f99aba3df3143a59da75799bf64a53a3ad3155ecded9", size = 363591 }, + { url = "https://files.pythonhosted.org/packages/30/c3/7ab2ca2276426a7398c6dfb651e38dbc81954c79a3bfbc36c514d8599499/jiter-0.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4829df14d656b3fb87e50ae8b48253a8851c707da9f30d45aacab2aa2ba2d614", size = 378551 }, + { url = "https://files.pythonhosted.org/packages/47/e7/5d88031cd743c62199b125181a591b1671df3ff2f6e102df85c58d8f7d31/jiter-0.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a42a4bdcf7307b86cb863b2fb9bb55029b422d8f86276a50487982d99eed7c6e", size = 319152 }, + { url = "https://files.pythonhosted.org/packages/4c/2d/09ea58e1adca9f0359f3d41ef44a1a18e59518d7c43a21f4ece9e72e28c0/jiter-0.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04d461ad0aebf696f8da13c99bc1b3e06f66ecf6cfd56254cc402f6385231c06", size = 357377 }, + { url = "https://files.pythonhosted.org/packages/7d/2f/83ff1058cb56fc3ff73e0d3c6440703ddc9cdb7f759b00cfbde8228fc435/jiter-0.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e6375923c5f19888c9226582a124b77b622f8fd0018b843c45eeb19d9701c403", size = 511091 }, + { url = "https://files.pythonhosted.org/packages/ae/c9/4f85f97c9894382ab457382337aea0012711baaa17f2ed55c0ff25f3668a/jiter-0.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2cec323a853c24fd0472517113768c92ae0be8f8c384ef4441d3632da8baa646", size = 492948 }, + { url = "https://files.pythonhosted.org/packages/4d/f2/2e987e0eb465e064c5f52c2f29c8d955452e3b316746e326269263bfb1b7/jiter-0.5.0-cp311-none-win32.whl", hash = "sha256:aa1db0967130b5cab63dfe4d6ff547c88b2a394c3410db64744d491df7f069bb", size = 195183 }, + { url = "https://files.pythonhosted.org/packages/ab/59/05d1c3203c349b37c4dd28b02b9b4e5915a7bcbd9319173b4548a67d2e93/jiter-0.5.0-cp311-none-win_amd64.whl", hash = "sha256:aa9d2b85b2ed7dc7697597dcfaac66e63c1b3028652f751c81c65a9f220899ae", size = 191032 }, + { url = "https://files.pythonhosted.org/packages/aa/bd/c3950e2c478161e131bed8cb67c36aed418190e2a961a1c981e69954e54b/jiter-0.5.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9f664e7351604f91dcdd557603c57fc0d551bc65cc0a732fdacbf73ad335049a", size = 283511 }, + { url = "https://files.pythonhosted.org/packages/80/1c/8ce58d8c37a589eeaaa5d07d131fd31043886f5e77ab50c00a66d869a361/jiter-0.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:044f2f1148b5248ad2c8c3afb43430dccf676c5a5834d2f5089a4e6c5bbd64df", size = 296974 }, + { url = "https://files.pythonhosted.org/packages/4d/b8/6faeff9eed8952bed93a77ea1cffae7b946795b88eafd1a60e87a67b09e0/jiter-0.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:702e3520384c88b6e270c55c772d4bd6d7b150608dcc94dea87ceba1b6391248", size = 331897 }, + { url = "https://files.pythonhosted.org/packages/4f/54/1d9a2209b46d39ce6f0cef3ad87c462f9c50312ab84585e6bd5541292b35/jiter-0.5.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:528d742dcde73fad9d63e8242c036ab4a84389a56e04efd854062b660f559544", size = 342962 }, + { url = "https://files.pythonhosted.org/packages/2a/de/90360be7fc54b2b4c2dfe79eb4ed1f659fce9c96682e6a0be4bbe71371f7/jiter-0.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8cf80e5fe6ab582c82f0c3331df27a7e1565e2dcf06265afd5173d809cdbf9ba", size = 363844 }, + { url = "https://files.pythonhosted.org/packages/ba/ad/ef32b173191b7a53ea8a6757b80723cba321f8469834825e8c71c96bde17/jiter-0.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:44dfc9ddfb9b51a5626568ef4e55ada462b7328996294fe4d36de02fce42721f", size = 378709 }, + { url = "https://files.pythonhosted.org/packages/07/de/353ce53743c0defbbbd652e89c106a97dbbac4eb42c95920b74b5056b93a/jiter-0.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c451f7922992751a936b96c5f5b9bb9312243d9b754c34b33d0cb72c84669f4e", size = 319038 }, + { url = "https://files.pythonhosted.org/packages/3f/92/42d47310bf9530b9dece9e2d7c6d51cf419af5586ededaf5e66622d160e2/jiter-0.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:308fce789a2f093dca1ff91ac391f11a9f99c35369117ad5a5c6c4903e1b3e3a", size = 357763 }, + { url = "https://files.pythonhosted.org/packages/bd/8c/2bb76a9a84474d48fdd133d3445db8a4413da4e87c23879d917e000a9d87/jiter-0.5.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7f5ad4a7c6b0d90776fdefa294f662e8a86871e601309643de30bf94bb93a64e", size = 511031 }, + { url = "https://files.pythonhosted.org/packages/33/4f/9f23d79c0795e0a8e56e7988e8785c2dcda27e0ed37977256d50c77c6a19/jiter-0.5.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ea189db75f8eca08807d02ae27929e890c7d47599ce3d0a6a5d41f2419ecf338", size = 493042 }, + { url = "https://files.pythonhosted.org/packages/df/67/8a4f975aa834b8aecdb6b131422390173928fd47f42f269dcc32034ab432/jiter-0.5.0-cp312-none-win32.whl", hash = "sha256:e3bbe3910c724b877846186c25fe3c802e105a2c1fc2b57d6688b9f8772026e4", size = 195405 }, + { url = "https://files.pythonhosted.org/packages/15/81/296b1e25c43db67848728cdab34ac3eb5c5cbb4955ceb3f51ae60d4a5e3d/jiter-0.5.0-cp312-none-win_amd64.whl", hash = "sha256:a586832f70c3f1481732919215f36d41c59ca080fa27a65cf23d9490e75b2ef5", size = 189720 }, +] + +[[package]] +name = "msal" +version = "1.31.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, + { name = "pyjwt", extra = ["crypto"] }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/59/04/8d7aa5c671a26ca5612257fd419f97380ba89cdd231b2eb67df58483796d/msal-1.31.0.tar.gz", hash = "sha256:2c4f189cf9cc8f00c80045f66d39b7c0f3ed45873fd3d1f2af9f22db2e12ff4b", size = 144950 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/40/0a5d743484e1ad00493bdffa8d10d7dbc6a51fec95290ad396e47e79fa43/msal-1.31.0-py3-none-any.whl", hash = "sha256:96bc37cff82ebe4b160d5fc0f1196f6ca8b50e274ecd0ec5bf69c438514086e7", size = 113109 }, +] + +[[package]] +name = "msal-extensions" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "msal" }, + { name = "portalocker" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2d/38/ad49272d0a5af95f7a0cb64a79bbd75c9c187f3b789385a143d8d537a5eb/msal_extensions-1.2.0.tar.gz", hash = "sha256:6f41b320bfd2933d631a215c91ca0dd3e67d84bd1a2f50ce917d5874ec646bef", size = 22391 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/69/314d887a01599669fb330da14e5c6ff5f138609e322812a942a74ef9b765/msal_extensions-1.2.0-py3-none-any.whl", hash = "sha256:cf5ba83a2113fa6dc011a254a72f1c223c88d7dfad74cc30617c4679a417704d", size = 19254 }, +] + +[[package]] +name = "openai" +version = "1.51.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "httpx" }, + { name = "jiter" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/af/cc59b1447f5a02bb1f25b9b0cd94b607aa2c969a81d9a244d4067f91f6fe/openai-1.51.0.tar.gz", hash = "sha256:8dc4f9d75ccdd5466fc8c99a952186eddceb9fd6ba694044773f3736a847149d", size = 306880 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/08/9f22356d4fbd273f734db1e6663b7ca6987943080567f5580471022e57ca/openai-1.51.0-py3-none-any.whl", hash = "sha256:d9affafb7e51e5a27dce78589d4964ce4d6f6d560307265933a94b2e3f3c5d2c", size = 383533 }, +] + +[[package]] +name = "portalocker" +version = "2.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pywin32", marker = "platform_system == 'Windows'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ed/d3/c6c64067759e87af98cc668c1cc75171347d0f1577fab7ca3749134e3cd4/portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f", size = 40891 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9b/fb/a70a4214956182e0d7a9099ab17d50bfcba1056188e9b14f35b9e2b62a0d/portalocker-2.10.1-py3-none-any.whl", hash = "sha256:53a5984ebc86a025552264b459b46a2086e269b21823cb572f8f28ee759e45bf", size = 18423 }, +] + +[[package]] +name = "pycparser" +version = "2.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, +] + +[[package]] +name = "pydantic" +version = "2.9.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a9/b7/d9e3f12af310e1120c21603644a1cd86f59060e040ec5c3a80b8f05fae30/pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f", size = 769917 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/e4/ba44652d562cbf0bf320e0f3810206149c8a4e99cdbf66da82e97ab53a15/pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12", size = 434928 }, +] + +[[package]] +name = "pydantic-core" +version = "2.23.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e2/aa/6b6a9b9f8537b872f552ddd46dd3da230367754b6f707b8e1e963f515ea3/pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863", size = 402156 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/30/890a583cd3f2be27ecf32b479d5d615710bb926d92da03e3f7838ff3e58b/pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8", size = 1865160 }, + { url = "https://files.pythonhosted.org/packages/1d/9a/b634442e1253bc6889c87afe8bb59447f106ee042140bd57680b3b113ec7/pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d", size = 1776777 }, + { url = "https://files.pythonhosted.org/packages/75/9a/7816295124a6b08c24c96f9ce73085032d8bcbaf7e5a781cd41aa910c891/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e", size = 1799244 }, + { url = "https://files.pythonhosted.org/packages/a9/8f/89c1405176903e567c5f99ec53387449e62f1121894aa9fc2c4fdc51a59b/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607", size = 1805307 }, + { url = "https://files.pythonhosted.org/packages/d5/a5/1a194447d0da1ef492e3470680c66048fef56fc1f1a25cafbea4bc1d1c48/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd", size = 2000663 }, + { url = "https://files.pythonhosted.org/packages/13/a5/1df8541651de4455e7d587cf556201b4f7997191e110bca3b589218745a5/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea", size = 2655941 }, + { url = "https://files.pythonhosted.org/packages/44/31/a3899b5ce02c4316865e390107f145089876dff7e1dfc770a231d836aed8/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e", size = 2052105 }, + { url = "https://files.pythonhosted.org/packages/1b/aa/98e190f8745d5ec831f6d5449344c48c0627ac5fed4e5340a44b74878f8e/pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b", size = 1919967 }, + { url = "https://files.pythonhosted.org/packages/ae/35/b6e00b6abb2acfee3e8f85558c02a0822e9a8b2f2d812ea8b9079b118ba0/pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0", size = 1964291 }, + { url = "https://files.pythonhosted.org/packages/13/46/7bee6d32b69191cd649bbbd2361af79c472d72cb29bb2024f0b6e350ba06/pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64", size = 2109666 }, + { url = "https://files.pythonhosted.org/packages/39/ef/7b34f1b122a81b68ed0a7d0e564da9ccdc9a2924c8d6c6b5b11fa3a56970/pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f", size = 1732940 }, + { url = "https://files.pythonhosted.org/packages/2f/76/37b7e76c645843ff46c1d73e046207311ef298d3f7b2f7d8f6ac60113071/pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3", size = 1916804 }, + { url = "https://files.pythonhosted.org/packages/74/7b/8e315f80666194b354966ec84b7d567da77ad927ed6323db4006cf915f3f/pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231", size = 1856459 }, + { url = "https://files.pythonhosted.org/packages/14/de/866bdce10ed808323d437612aca1ec9971b981e1c52e5e42ad9b8e17a6f6/pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee", size = 1770007 }, + { url = "https://files.pythonhosted.org/packages/dc/69/8edd5c3cd48bb833a3f7ef9b81d7666ccddd3c9a635225214e044b6e8281/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87", size = 1790245 }, + { url = "https://files.pythonhosted.org/packages/80/33/9c24334e3af796ce80d2274940aae38dd4e5676298b4398eff103a79e02d/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8", size = 1801260 }, + { url = "https://files.pythonhosted.org/packages/a5/6f/e9567fd90104b79b101ca9d120219644d3314962caa7948dd8b965e9f83e/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327", size = 1996872 }, + { url = "https://files.pythonhosted.org/packages/2d/ad/b5f0fe9e6cfee915dd144edbd10b6e9c9c9c9d7a56b69256d124b8ac682e/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2", size = 2661617 }, + { url = "https://files.pythonhosted.org/packages/06/c8/7d4b708f8d05a5cbfda3243aad468052c6e99de7d0937c9146c24d9f12e9/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36", size = 2071831 }, + { url = "https://files.pythonhosted.org/packages/89/4d/3079d00c47f22c9a9a8220db088b309ad6e600a73d7a69473e3a8e5e3ea3/pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126", size = 1917453 }, + { url = "https://files.pythonhosted.org/packages/e9/88/9df5b7ce880a4703fcc2d76c8c2d8eb9f861f79d0c56f4b8f5f2607ccec8/pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e", size = 1968793 }, + { url = "https://files.pythonhosted.org/packages/e3/b9/41f7efe80f6ce2ed3ee3c2dcfe10ab7adc1172f778cc9659509a79518c43/pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24", size = 2116872 }, + { url = "https://files.pythonhosted.org/packages/63/08/b59b7a92e03dd25554b0436554bf23e7c29abae7cce4b1c459cd92746811/pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84", size = 1738535 }, + { url = "https://files.pythonhosted.org/packages/88/8d/479293e4d39ab409747926eec4329de5b7129beaedc3786eca070605d07f/pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9", size = 1917992 }, + { url = "https://files.pythonhosted.org/packages/ad/ef/16ee2df472bf0e419b6bc68c05bf0145c49247a1095e85cee1463c6a44a1/pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc", size = 1856143 }, + { url = "https://files.pythonhosted.org/packages/da/fa/bc3dbb83605669a34a93308e297ab22be82dfb9dcf88c6cf4b4f264e0a42/pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd", size = 1770063 }, + { url = "https://files.pythonhosted.org/packages/4e/48/e813f3bbd257a712303ebdf55c8dc46f9589ec74b384c9f652597df3288d/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05", size = 1790013 }, + { url = "https://files.pythonhosted.org/packages/b4/e0/56eda3a37929a1d297fcab1966db8c339023bcca0b64c5a84896db3fcc5c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d", size = 1801077 }, + { url = "https://files.pythonhosted.org/packages/04/be/5e49376769bfbf82486da6c5c1683b891809365c20d7c7e52792ce4c71f3/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510", size = 1996782 }, + { url = "https://files.pythonhosted.org/packages/bc/24/e3ee6c04f1d58cc15f37bcc62f32c7478ff55142b7b3e6d42ea374ea427c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6", size = 2661375 }, + { url = "https://files.pythonhosted.org/packages/c1/f8/11a9006de4e89d016b8de74ebb1db727dc100608bb1e6bbe9d56a3cbbcce/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b", size = 2071635 }, + { url = "https://files.pythonhosted.org/packages/7c/45/bdce5779b59f468bdf262a5bc9eecbae87f271c51aef628d8c073b4b4b4c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327", size = 1916994 }, + { url = "https://files.pythonhosted.org/packages/d8/fa/c648308fe711ee1f88192cad6026ab4f925396d1293e8356de7e55be89b5/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6", size = 1968877 }, + { url = "https://files.pythonhosted.org/packages/16/16/b805c74b35607d24d37103007f899abc4880923b04929547ae68d478b7f4/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f", size = 2116814 }, + { url = "https://files.pythonhosted.org/packages/d1/58/5305e723d9fcdf1c5a655e6a4cc2a07128bf644ff4b1d98daf7a9dbf57da/pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769", size = 1738360 }, + { url = "https://files.pythonhosted.org/packages/a5/ae/e14b0ff8b3f48e02394d8acd911376b7b66e164535687ef7dc24ea03072f/pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5", size = 1919411 }, +] + +[[package]] +name = "pydantic-settings" +version = "2.5.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dotenv" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/68/27/0bed9dd26b93328b60a1402febc780e7be72b42847fa8b5c94b7d0aeb6d1/pydantic_settings-2.5.2.tar.gz", hash = "sha256:f90b139682bee4d2065273d5185d71d37ea46cfe57e1b5ae184fc6a0b2484ca0", size = 70938 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/8d/29e82e333f32d9e2051c10764b906c2a6cd140992910b5f49762790911ba/pydantic_settings-2.5.2-py3-none-any.whl", hash = "sha256:2c912e55fd5794a59bf8c832b9de832dcfdf4778d79ff79b708744eed499a907", size = 26864 }, +] + +[[package]] +name = "pyjwt" +version = "2.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fb/68/ce067f09fca4abeca8771fe667d89cc347d1e99da3e093112ac329c6020e/pyjwt-2.9.0.tar.gz", hash = "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c", size = 78825 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/84/0fdf9b18ba31d69877bd39c9cd6052b47f3761e9910c15de788e519f079f/PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850", size = 22344 }, +] + +[package.optional-dependencies] +crypto = [ + { name = "cryptography" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, +] + +[[package]] +name = "python-dotenv" +version = "1.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 }, +] + +[[package]] +name = "python-liquid" +version = "1.12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-resources" }, + { name = "python-dateutil" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/59/b4/c4e39470edf507056333cd688a36bb7fbdb17090105d9f454ecf6ff09845/python_liquid-1.12.1.tar.gz", hash = "sha256:7367e979125859fb4116f360f224a89a52ecb455fb26843c43e4d800b389d325", size = 124636 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/6e/bfd01926e28f6cf355a7a8460271ba135013870f5857b06f35dbf65ab237/python_liquid-1.12.1-py3-none-any.whl", hash = "sha256:2224312944be16c1a44406398eb8a07c7e57398d5c0ef15ff950946dbefe7c33", size = 206592 }, +] + +[[package]] +name = "pywin32" +version = "306" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/1e/fc18ad83ca553e01b97aa8393ff10e33c1fb57801db05488b83282ee9913/pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407", size = 8507689 }, + { url = "https://files.pythonhosted.org/packages/7e/9e/ad6b1ae2a5ad1066dc509350e0fbf74d8d50251a51e420a2a8feaa0cecbd/pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e", size = 9227547 }, + { url = "https://files.pythonhosted.org/packages/91/20/f744bff1da8f43388498503634378dbbefbe493e65675f2cc52f7185c2c2/pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a", size = 10388324 }, + { url = "https://files.pythonhosted.org/packages/14/91/17e016d5923e178346aabda3dfec6629d1a26efe587d19667542105cf0a6/pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b", size = 8507705 }, + { url = "https://files.pythonhosted.org/packages/83/1c/25b79fc3ec99b19b0a0730cc47356f7e2959863bf9f3cd314332bddb4f68/pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e", size = 9227429 }, + { url = "https://files.pythonhosted.org/packages/1c/43/e3444dc9a12f8365d9603c2145d16bf0a2f8180f343cf87be47f5579e547/pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040", size = 10388145 }, +] + +[[package]] +name = "regex" +version = "2024.9.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/38/148df33b4dbca3bd069b963acab5e0fa1a9dbd6820f8c322d0dd6faeff96/regex-2024.9.11.tar.gz", hash = "sha256:6c188c307e8433bcb63dc1915022deb553b4203a70722fc542c363bf120a01fd", size = 399403 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/a1/d526b7b6095a0019aa360948c143aacfeb029919c898701ce7763bbe4c15/regex-2024.9.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2cce2449e5927a0bf084d346da6cd5eb016b2beca10d0013ab50e3c226ffc0df", size = 482483 }, + { url = "https://files.pythonhosted.org/packages/32/d9/bfdd153179867c275719e381e1e8e84a97bd186740456a0dcb3e7125c205/regex-2024.9.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b37fa423beefa44919e009745ccbf353d8c981516e807995b2bd11c2c77d268", size = 287442 }, + { url = "https://files.pythonhosted.org/packages/33/c4/60f3370735135e3a8d673ddcdb2507a8560d0e759e1398d366e43d000253/regex-2024.9.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:64ce2799bd75039b480cc0360907c4fb2f50022f030bf9e7a8705b636e408fad", size = 284561 }, + { url = "https://files.pythonhosted.org/packages/b1/51/91a5ebdff17f9ec4973cb0aa9d37635efec1c6868654bbc25d1543aca4ec/regex-2024.9.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4cc92bb6db56ab0c1cbd17294e14f5e9224f0cc6521167ef388332604e92679", size = 791779 }, + { url = "https://files.pythonhosted.org/packages/07/4a/022c5e6f0891a90cd7eb3d664d6c58ce2aba48bff107b00013f3d6167069/regex-2024.9.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d05ac6fa06959c4172eccd99a222e1fbf17b5670c4d596cb1e5cde99600674c4", size = 832605 }, + { url = "https://files.pythonhosted.org/packages/ac/1c/3793990c8c83ca04e018151ddda83b83ecc41d89964f0f17749f027fc44d/regex-2024.9.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040562757795eeea356394a7fb13076ad4f99d3c62ab0f8bdfb21f99a1f85664", size = 818556 }, + { url = "https://files.pythonhosted.org/packages/e9/5c/8b385afbfacb853730682c57be56225f9fe275c5bf02ac1fc88edbff316d/regex-2024.9.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6113c008a7780792efc80f9dfe10ba0cd043cbf8dc9a76ef757850f51b4edc50", size = 792808 }, + { url = "https://files.pythonhosted.org/packages/9b/8b/a4723a838b53c771e9240951adde6af58c829fb6a6a28f554e8131f53839/regex-2024.9.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e5fb5f77c8745a60105403a774fe2c1759b71d3e7b4ca237a5e67ad066c7199", size = 781115 }, + { url = "https://files.pythonhosted.org/packages/83/5f/031a04b6017033d65b261259c09043c06f4ef2d4eac841d0649d76d69541/regex-2024.9.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:54d9ff35d4515debf14bc27f1e3b38bfc453eff3220f5bce159642fa762fe5d4", size = 778155 }, + { url = "https://files.pythonhosted.org/packages/fd/cd/4660756070b03ce4a66663a43f6c6e7ebc2266cc6b4c586c167917185eb4/regex-2024.9.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:df5cbb1fbc74a8305b6065d4ade43b993be03dbe0f8b30032cced0d7740994bd", size = 784614 }, + { url = "https://files.pythonhosted.org/packages/93/8d/65b9bea7df120a7be8337c415b6d256ba786cbc9107cebba3bf8ff09da99/regex-2024.9.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7fb89ee5d106e4a7a51bce305ac4efb981536301895f7bdcf93ec92ae0d91c7f", size = 853744 }, + { url = "https://files.pythonhosted.org/packages/96/a7/fba1eae75eb53a704475baf11bd44b3e6ccb95b316955027eb7748f24ef8/regex-2024.9.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a738b937d512b30bf75995c0159c0ddf9eec0775c9d72ac0202076c72f24aa96", size = 855890 }, + { url = "https://files.pythonhosted.org/packages/45/14/d864b2db80a1a3358534392373e8a281d95b28c29c87d8548aed58813910/regex-2024.9.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e28f9faeb14b6f23ac55bfbbfd3643f5c7c18ede093977f1df249f73fd22c7b1", size = 781887 }, + { url = "https://files.pythonhosted.org/packages/4d/a9/bfb29b3de3eb11dc9b412603437023b8e6c02fb4e11311863d9bf62c403a/regex-2024.9.11-cp311-cp311-win32.whl", hash = "sha256:18e707ce6c92d7282dfce370cd205098384b8ee21544e7cb29b8aab955b66fa9", size = 261644 }, + { url = "https://files.pythonhosted.org/packages/c7/ab/1ad2511cf6a208fde57fafe49829cab8ca018128ab0d0b48973d8218634a/regex-2024.9.11-cp311-cp311-win_amd64.whl", hash = "sha256:313ea15e5ff2a8cbbad96ccef6be638393041b0a7863183c2d31e0c6116688cf", size = 274033 }, + { url = "https://files.pythonhosted.org/packages/6e/92/407531450762bed778eedbde04407f68cbd75d13cee96c6f8d6903d9c6c1/regex-2024.9.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b0d0a6c64fcc4ef9c69bd5b3b3626cc3776520a1637d8abaa62b9edc147a58f7", size = 483590 }, + { url = "https://files.pythonhosted.org/packages/8e/a2/048acbc5ae1f615adc6cba36cc45734e679b5f1e4e58c3c77f0ed611d4e2/regex-2024.9.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:49b0e06786ea663f933f3710a51e9385ce0cba0ea56b67107fd841a55d56a231", size = 288175 }, + { url = "https://files.pythonhosted.org/packages/8a/ea/909d8620329ab710dfaf7b4adee41242ab7c9b95ea8d838e9bfe76244259/regex-2024.9.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5b513b6997a0b2f10e4fd3a1313568e373926e8c252bd76c960f96fd039cd28d", size = 284749 }, + { url = "https://files.pythonhosted.org/packages/ca/fa/521eb683b916389b4975337873e66954e0f6d8f91bd5774164a57b503185/regex-2024.9.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee439691d8c23e76f9802c42a95cfeebf9d47cf4ffd06f18489122dbb0a7ad64", size = 795181 }, + { url = "https://files.pythonhosted.org/packages/28/db/63047feddc3280cc242f9c74f7aeddc6ee662b1835f00046f57d5630c827/regex-2024.9.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8f877c89719d759e52783f7fe6e1c67121076b87b40542966c02de5503ace42", size = 835842 }, + { url = "https://files.pythonhosted.org/packages/e3/94/86adc259ff8ec26edf35fcca7e334566c1805c7493b192cb09679f9c3dee/regex-2024.9.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23b30c62d0f16827f2ae9f2bb87619bc4fba2044911e2e6c2eb1af0161cdb766", size = 823533 }, + { url = "https://files.pythonhosted.org/packages/29/52/84662b6636061277cb857f658518aa7db6672bc6d1a3f503ccd5aefc581e/regex-2024.9.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ab7824093d8f10d44330fe1e6493f756f252d145323dd17ab6b48733ff6c0a", size = 797037 }, + { url = "https://files.pythonhosted.org/packages/c3/2a/cd4675dd987e4a7505f0364a958bc41f3b84942de9efaad0ef9a2646681c/regex-2024.9.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8dee5b4810a89447151999428fe096977346cf2f29f4d5e29609d2e19e0199c9", size = 784106 }, + { url = "https://files.pythonhosted.org/packages/6f/75/3ea7ec29de0bbf42f21f812f48781d41e627d57a634f3f23947c9a46e303/regex-2024.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98eeee2f2e63edae2181c886d7911ce502e1292794f4c5ee71e60e23e8d26b5d", size = 782468 }, + { url = "https://files.pythonhosted.org/packages/d3/67/15519d69b52c252b270e679cb578e22e0c02b8dd4e361f2b04efcc7f2335/regex-2024.9.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:57fdd2e0b2694ce6fc2e5ccf189789c3e2962916fb38779d3e3521ff8fe7a822", size = 790324 }, + { url = "https://files.pythonhosted.org/packages/9c/71/eff77d3fe7ba08ab0672920059ec30d63fa7e41aa0fb61c562726e9bd721/regex-2024.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d552c78411f60b1fdaafd117a1fca2f02e562e309223b9d44b7de8be451ec5e0", size = 860214 }, + { url = "https://files.pythonhosted.org/packages/81/11/e1bdf84a72372e56f1ea4b833dd583b822a23138a616ace7ab57a0e11556/regex-2024.9.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a0b2b80321c2ed3fcf0385ec9e51a12253c50f146fddb2abbb10f033fe3d049a", size = 859420 }, + { url = "https://files.pythonhosted.org/packages/ea/75/9753e9dcebfa7c3645563ef5c8a58f3a47e799c872165f37c55737dadd3e/regex-2024.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a", size = 787333 }, + { url = "https://files.pythonhosted.org/packages/bc/4e/ba1cbca93141f7416624b3ae63573e785d4bc1834c8be44a8f0747919eca/regex-2024.9.11-cp312-cp312-win32.whl", hash = "sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776", size = 262058 }, + { url = "https://files.pythonhosted.org/packages/6e/16/efc5f194778bf43e5888209e5cec4b258005d37c613b67ae137df3b89c53/regex-2024.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009", size = 273526 }, + { url = "https://files.pythonhosted.org/packages/93/0a/d1c6b9af1ff1e36832fe38d74d5c5bab913f2bdcbbd6bc0e7f3ce8b2f577/regex-2024.9.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784", size = 483376 }, + { url = "https://files.pythonhosted.org/packages/a4/42/5910a050c105d7f750a72dcb49c30220c3ae4e2654e54aaaa0e9bc0584cb/regex-2024.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36", size = 288112 }, + { url = "https://files.pythonhosted.org/packages/8d/56/0c262aff0e9224fa7ffce47b5458d373f4d3e3ff84e99b5ff0cb15e0b5b2/regex-2024.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92", size = 284608 }, + { url = "https://files.pythonhosted.org/packages/b9/54/9fe8f9aec5007bbbbce28ba3d2e3eaca425f95387b7d1e84f0d137d25237/regex-2024.9.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86", size = 795337 }, + { url = "https://files.pythonhosted.org/packages/b2/e7/6b2f642c3cded271c4f16cc4daa7231be544d30fe2b168e0223724b49a61/regex-2024.9.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85", size = 835848 }, + { url = "https://files.pythonhosted.org/packages/cd/9e/187363bdf5d8c0e4662117b92aa32bf52f8f09620ae93abc7537d96d3311/regex-2024.9.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963", size = 823503 }, + { url = "https://files.pythonhosted.org/packages/f8/10/601303b8ee93589f879664b0cfd3127949ff32b17f9b6c490fb201106c4d/regex-2024.9.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6", size = 797049 }, + { url = "https://files.pythonhosted.org/packages/ef/1c/ea200f61ce9f341763f2717ab4daebe4422d83e9fd4ac5e33435fd3a148d/regex-2024.9.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802", size = 784144 }, + { url = "https://files.pythonhosted.org/packages/d8/5c/d2429be49ef3292def7688401d3deb11702c13dcaecdc71d2b407421275b/regex-2024.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29", size = 782483 }, + { url = "https://files.pythonhosted.org/packages/12/d9/cbc30f2ff7164f3b26a7760f87c54bf8b2faed286f60efd80350a51c5b99/regex-2024.9.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8", size = 790320 }, + { url = "https://files.pythonhosted.org/packages/19/1d/43ed03a236313639da5a45e61bc553c8d41e925bcf29b0f8ecff0c2c3f25/regex-2024.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84", size = 860435 }, + { url = "https://files.pythonhosted.org/packages/34/4f/5d04da61c7c56e785058a46349f7285ae3ebc0726c6ea7c5c70600a52233/regex-2024.9.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554", size = 859571 }, + { url = "https://files.pythonhosted.org/packages/12/7f/8398c8155a3c70703a8e91c29532558186558e1aea44144b382faa2a6f7a/regex-2024.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8", size = 787398 }, + { url = "https://files.pythonhosted.org/packages/58/3a/f5903977647a9a7e46d5535e9e96c194304aeeca7501240509bde2f9e17f/regex-2024.9.11-cp313-cp313-win32.whl", hash = "sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8", size = 262035 }, + { url = "https://files.pythonhosted.org/packages/ff/80/51ba3a4b7482f6011095b3a036e07374f64de180b7d870b704ed22509002/regex-2024.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f", size = 273510 }, +] + +[[package]] +name = "requests" +version = "2.32.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, +] + +[[package]] +name = "six" +version = "1.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/71/39/171f1c67cd00715f190ba0b100d606d440a28c93c7714febeca8b79af85e/six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", size = 34041 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", size = 11053 }, +] + +[[package]] +name = "skill-library" +version = "0.1.0" +source = { editable = "../../skill-library" } +dependencies = [ + { name = "assistant-drive" }, + { name = "chat-driver" }, + { name = "context" }, + { name = "events" }, + { name = "function-registry" }, + { name = "openai" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "python-dotenv" }, + { name = "requests" }, + { name = "tiktoken" }, +] + +[package.metadata] +requires-dist = [ + { name = "assistant-drive", editable = "../../../assistant-drive" }, + { name = "chat-driver", editable = "../../../chat-driver" }, + { name = "context", editable = "../../../context" }, + { name = "events", editable = "../../../events" }, + { name = "function-registry", editable = "../../../function-registry" }, + { name = "openai", specifier = ">=1.16.1" }, + { name = "pydantic", specifier = ">=2.6.1" }, + { name = "pydantic-settings", specifier = ">=2.3.4" }, + { name = "python-dotenv", specifier = ">=1.0.1" }, + { name = "requests", specifier = ">=2.32.0" }, + { name = "tiktoken", specifier = ">=0.7.0" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, +] + +[[package]] +name = "tiktoken" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "regex" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c4/4a/abaec53e93e3ef37224a4dd9e2fc6bb871e7a538c2b6b9d2a6397271daf4/tiktoken-0.7.0.tar.gz", hash = "sha256:1077266e949c24e0291f6c350433c6f0971365ece2b173a23bc3b9f9defef6b6", size = 33437 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/eb/57492b2568eea1d546da5cc1ae7559d924275280db80ba07e6f9b89a914b/tiktoken-0.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:10c7674f81e6e350fcbed7c09a65bca9356eaab27fb2dac65a1e440f2bcfe30f", size = 961468 }, + { url = "https://files.pythonhosted.org/packages/30/ef/e07dbfcb2f85c84abaa1b035a9279575a8da0236305491dc22ae099327f7/tiktoken-0.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:084cec29713bc9d4189a937f8a35dbdfa785bd1235a34c1124fe2323821ee93f", size = 907005 }, + { url = "https://files.pythonhosted.org/packages/ea/9b/f36db825b1e9904c3a2646439cb9923fc1e09208e2e071c6d9dd64ead131/tiktoken-0.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:811229fde1652fedcca7c6dfe76724d0908775b353556d8a71ed74d866f73f7b", size = 1049183 }, + { url = "https://files.pythonhosted.org/packages/61/b4/b80d1fe33015e782074e96bbbf4108ccd283b8deea86fb43c15d18b7c351/tiktoken-0.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86b6e7dc2e7ad1b3757e8a24597415bafcfb454cebf9a33a01f2e6ba2e663992", size = 1080830 }, + { url = "https://files.pythonhosted.org/packages/2a/40/c66ff3a21af6d62a7e0ff428d12002c4e0389f776d3ff96dcaa0bb354eee/tiktoken-0.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1063c5748be36344c7e18c7913c53e2cca116764c2080177e57d62c7ad4576d1", size = 1092967 }, + { url = "https://files.pythonhosted.org/packages/2e/80/f4c9e255ff236e6a69ce44b927629cefc1b63d3a00e2d1c9ed540c9492d2/tiktoken-0.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:20295d21419bfcca092644f7e2f2138ff947a6eb8cfc732c09cc7d76988d4a89", size = 1142682 }, + { url = "https://files.pythonhosted.org/packages/b1/10/c04b4ff592a5f46b28ebf4c2353f735c02ae7f0ce1b165d00748ced6467e/tiktoken-0.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:959d993749b083acc57a317cbc643fb85c014d055b2119b739487288f4e5d1cb", size = 799009 }, + { url = "https://files.pythonhosted.org/packages/1d/46/4cdda4186ce900608f522da34acf442363346688c71b938a90a52d7b84cc/tiktoken-0.7.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:71c55d066388c55a9c00f61d2c456a6086673ab7dec22dd739c23f77195b1908", size = 960446 }, + { url = "https://files.pythonhosted.org/packages/b6/30/09ced367d280072d7a3e21f34263dfbbf6378661e7a0f6414e7c18971083/tiktoken-0.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:09ed925bccaa8043e34c519fbb2f99110bd07c6fd67714793c21ac298e449410", size = 906652 }, + { url = "https://files.pythonhosted.org/packages/e6/7b/c949e4954441a879a67626963dff69096e3c774758b9f2bb0853f7b4e1e7/tiktoken-0.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03c6c40ff1db0f48a7b4d2dafeae73a5607aacb472fa11f125e7baf9dce73704", size = 1047904 }, + { url = "https://files.pythonhosted.org/packages/50/81/1842a22f15586072280364c2ab1e40835adaf64e42fe80e52aff921ee021/tiktoken-0.7.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d20b5c6af30e621b4aca094ee61777a44118f52d886dbe4f02b70dfe05c15350", size = 1079836 }, + { url = "https://files.pythonhosted.org/packages/6d/87/51a133a3d5307cf7ae3754249b0faaa91d3414b85c3d36f80b54d6817aa6/tiktoken-0.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d427614c3e074004efa2f2411e16c826f9df427d3c70a54725cae860f09e4bf4", size = 1092472 }, + { url = "https://files.pythonhosted.org/packages/a5/1f/c93517dc6d3b2c9e988b8e24f87a8b2d4a4ab28920a3a3f3ea338397ae0c/tiktoken-0.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8c46d7af7b8c6987fac9b9f61041b452afe92eb087d29c9ce54951280f899a97", size = 1141881 }, + { url = "https://files.pythonhosted.org/packages/bf/4b/48ca098cb580c099b5058bf62c4cb5e90ca6130fa43ef4df27088536245b/tiktoken-0.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:0bc603c30b9e371e7c4c7935aba02af5994a909fc3c0fe66e7004070858d3f8f", size = 799281 }, +] + +[[package]] +name = "tqdm" +version = "4.66.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "platform_system == 'Windows'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/83/6ba9844a41128c62e810fddddd72473201f3eacde02046066142a2d96cc5/tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad", size = 169504 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/5d/acf5905c36149bbaec41ccf7f2b68814647347b72075ac0b1fe3022fdc73/tqdm-4.66.5-py3-none-any.whl", hash = "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd", size = 78351 }, +] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, +] + +[[package]] +name = "urllib3" +version = "2.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", size = 300677 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338 }, +] From 72b3702903d82515030d83b775f6690cf070f35e Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Tue, 5 Nov 2024 23:31:30 +0000 Subject: [PATCH 05/14] Splits OpenAI client helper methods out of ChatDriver. Adds strict parsing to Function registry for structured completion call helpers. --- .../chat-driver/chat_driver/__init__.py | 6 +- .../tests/formatted_instructions_test.py | 18 +- libraries/python/chat-driver/uv.lock | 256 ++- libraries/python/events/events/events.py | 2 +- .../notebooks/notebooks/chat_driver.ipynb | 1940 ++++++++++------- 5 files changed, 1469 insertions(+), 753 deletions(-) diff --git a/libraries/python/chat-driver/chat_driver/__init__.py b/libraries/python/chat-driver/chat_driver/__init__.py index 76bbf0de..4950ad56 100644 --- a/libraries/python/chat-driver/chat_driver/__init__.py +++ b/libraries/python/chat-driver/chat_driver/__init__.py @@ -3,7 +3,7 @@ import logging from context import Context, ContextProtocol -from openai_client.completion import JSON_OBJECT_RESPONSE_FORMAT, TEXT_RESPONSE_FORMAT, ResponseFormat +from openai_client.completion import JSON_OBJECT_RESPONSE_FORMAT, TEXT_RESPONSE_FORMAT from .chat_driver import ( ChatDriver, @@ -14,15 +14,17 @@ logger = logging.getLogger(__name__) +logger = logging.getLogger(__name__) + __all__ = [ "ChatDriver", "ChatDriverConfig", "Context", "ContextProtocol", "JSON_OBJECT_RESPONSE_FORMAT", + "JSON_OBJECT_RESPONSE_FORMAT", "LocalMessageHistoryProvider", "LocalMessageHistoryProviderConfig", "MessageHistoryProviderProtocol", - "ResponseFormat", "TEXT_RESPONSE_FORMAT", ] diff --git a/libraries/python/chat-driver/chat_driver/tests/formatted_instructions_test.py b/libraries/python/chat-driver/chat_driver/tests/formatted_instructions_test.py index 0f9aad88..c79ef24c 100644 --- a/libraries/python/chat-driver/chat_driver/tests/formatted_instructions_test.py +++ b/libraries/python/chat-driver/chat_driver/tests/formatted_instructions_test.py @@ -1,19 +1,5 @@ -from typing import Any - from chat_driver.chat_driver import ChatDriver -from liquid import Template - - -def format_message(message: str, vars: dict[str, Any]) -> str: - """ - Format a message with the given variables. - """ - out = message - if not message: - return message - template = Template(message) - out = template.render(**vars) - return out +from openai_client.messages import format_with_dict def test_formatted_instructions() -> None: @@ -48,7 +34,7 @@ def test_formatted_instructions() -> None: "user_feedback": user_feedback, "chat_history": chat_history, }, - formatter=format_message, + formatter=format_with_dict, ) expected = [ diff --git a/libraries/python/chat-driver/uv.lock b/libraries/python/chat-driver/uv.lock index f471be1f..6ce43bb0 100644 --- a/libraries/python/chat-driver/uv.lock +++ b/libraries/python/chat-driver/uv.lock @@ -144,6 +144,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/36/39/cbb3ff28ad09434a1be7803b2846077bc3b23a8232beb489962fc818fe21/azure_ai_contentsafety-1.0.0-py3-none-any.whl", hash = "sha256:e1c5574a541f9290fdd071d23535e14b1f463af231a6f0ac0f917e125f0463cf", size = 61328 }, ] +[[package]] +name = "asgi-correlation-id" +version = "4.3.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "starlette" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f4/ff/a6538245ac1eaa7733ec6740774e9d5add019e2c63caa29e758c16c0afdd/asgi_correlation_id-4.3.4.tar.gz", hash = "sha256:ea6bc310380373cb9f731dc2e8b2b6fb978a76afe33f7a2384f697b8d6cd811d", size = 20075 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/ab/6936e2663c47a926e0659437b9333ad87d1ff49b1375d239026e0a268eba/asgi_correlation_id-4.3.4-py3-none-any.whl", hash = "sha256:36ce69b06c7d96b4acb89c7556a4c4f01a972463d3d49c675026cbbd08e9a0a2", size = 15262 }, +] + +[[package]] +name = "attrs" +version = "24.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/0f/aafca9af9315aee06a89ffde799a10a582fe8de76c563ee80bbcdc08b3fb/attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", size = 792678 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2", size = 63001 }, +] + +[[package]] +name = "azure-ai-contentsafety" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "azure-core" }, + { name = "isodate" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/08/e9/c069efade0e4976d96208306f1cf0803838cdb0b60e00a2a96bd20806bff/azure-ai-contentsafety-1.0.0.tar.gz", hash = "sha256:052731bd1419a720fa00910f46bf3428c4e5bd05280da7393d0c8106d46cc6d7", size = 63806 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/39/cbb3ff28ad09434a1be7803b2846077bc3b23a8232beb489962fc818fe21/azure_ai_contentsafety-1.0.0-py3-none-any.whl", hash = "sha256:e1c5574a541f9290fdd071d23535e14b1f463af231a6f0ac0f917e125f0463cf", size = 61328 }, +] + [[package]] name = "azure-core" version = "1.31.0" @@ -188,6 +223,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8", size = 15148 }, ] +[[package]] +name = "backoff" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/47/d7/5bbeb12c44d7c4f2fb5b56abce497eb5ed9f34d85701de869acedd602619/backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba", size = 17001 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8", size = 15148 }, +] + [[package]] name = "certifi" version = "2024.8.30" @@ -408,6 +452,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2d/82/e5d2c1c67d19841e9edc74954c827444ae826978499bde3dfc1d007c8c11/deepmerge-2.0-py3-none-any.whl", hash = "sha256:6de9ce507115cff0bed95ff0ce9ecc31088ef50cbdf09bc90a09349a318b3d00", size = 13475 }, ] +[[package]] +name = "deepmerge" +version = "2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a8/3a/b0ba594708f1ad0bc735884b3ad854d3ca3bdc1d741e56e40bbda6263499/deepmerge-2.0.tar.gz", hash = "sha256:5c3d86081fbebd04dd5de03626a0607b809a98fb6ccba5770b62466fe940ff20", size = 19890 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/82/e5d2c1c67d19841e9edc74954c827444ae826978499bde3dfc1d007c8c11/deepmerge-2.0-py3-none-any.whl", hash = "sha256:6de9ce507115cff0bed95ff0ce9ecc31088ef50cbdf09bc90a09349a318b3d00", size = 13475 }, +] + [[package]] name = "distro" version = "1.9.0" @@ -787,6 +840,75 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, ] +[[package]] +name = "markdown-it-py" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353 }, + { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392 }, + { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984 }, + { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120 }, + { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032 }, + { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057 }, + { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359 }, + { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306 }, + { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094 }, + { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521 }, + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, +] + [[package]] name = "msal" version = "1.31.0" @@ -884,7 +1006,95 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/80/ac/54c76352d493866637756b7c0ecec44f0b5bafb8fe753d98472cf6cfe4ce/openai-1.52.1.tar.gz", hash = "sha256:383b96c7e937cbec23cad5bf5718085381e4313ca33c5c5896b54f8e1b19d144", size = 310069 } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/08/9f22356d4fbd273f734db1e6663b7ca6987943080567f5580471022e57ca/openai-1.51.0-py3-none-any.whl", hash = "sha256:d9affafb7e51e5a27dce78589d4964ce4d6f6d560307265933a94b2e3f3c5d2c", size = 383533 }, + { url = "https://files.pythonhosted.org/packages/ad/31/28a83e124e9f9dd04c83b5aeb6f8b1770f45addde4dd3d34d9a9091590ad/openai-1.52.1-py3-none-any.whl", hash = "sha256:f23e83df5ba04ee0e82c8562571e8cb596cd88f9a84ab783e6c6259e5ffbfb4a", size = 386945 }, +] + +[[package]] +name = "openai-client" +version = "0.1.0" +source = { editable = "../openai-client" } +dependencies = [ + { name = "azure-ai-contentsafety" }, + { name = "azure-core", extra = ["aio"] }, + { name = "azure-identity" }, + { name = "function-registry" }, + { name = "openai" }, + { name = "pillow" }, + { name = "semantic-workbench-assistant" }, + { name = "tiktoken" }, +] + +[package.metadata] +requires-dist = [ + { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, + { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, + { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "function-registry", editable = "../function-registry" }, + { name = "openai", specifier = ">=1.3.9" }, + { name = "pillow", specifier = ">=11.0.0" }, + { name = "semantic-workbench-assistant", editable = "../semantic-workbench-assistant" }, + { name = "tiktoken", specifier = ">=0.7.0" }, +] + +[package.metadata.requires-dev] +dev = [{ name = "pytest", specifier = ">=8.3.3" }] + +[[package]] +name = "packaging" +version = "24.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/51/65/50db4dda066951078f0a96cf12f4b9ada6e4b811516bf0262c0f4f7064d4/packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", size = 148788 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124", size = 53985 }, +] + +[[package]] +name = "pillow" +version = "11.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/26/0d95c04c868f6bdb0c447e3ee2de5564411845e36a858cfd63766bc7b563/pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739", size = 46737780 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f0/eb/f7e21b113dd48a9c97d364e0915b3988c6a0b6207652f5a92372871b7aa4/pillow-11.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1c1d72714f429a521d8d2d018badc42414c3077eb187a59579f28e4270b4b0fc", size = 3154705 }, + { url = "https://files.pythonhosted.org/packages/25/b3/2b54a1d541accebe6bd8b1358b34ceb2c509f51cb7dcda8687362490da5b/pillow-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:499c3a1b0d6fc8213519e193796eb1a86a1be4b1877d678b30f83fd979811d1a", size = 2979222 }, + { url = "https://files.pythonhosted.org/packages/20/12/1a41eddad8265c5c19dda8fb6c269ce15ee25e0b9f8f26286e6202df6693/pillow-11.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8b2351c85d855293a299038e1f89db92a2f35e8d2f783489c6f0b2b5f3fe8a3", size = 4190220 }, + { url = "https://files.pythonhosted.org/packages/a9/9b/8a8c4d07d77447b7457164b861d18f5a31ae6418ef5c07f6f878fa09039a/pillow-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4dba50cfa56f910241eb7f883c20f1e7b1d8f7d91c750cd0b318bad443f4d5", size = 4291399 }, + { url = "https://files.pythonhosted.org/packages/fc/e4/130c5fab4a54d3991129800dd2801feeb4b118d7630148cd67f0e6269d4c/pillow-11.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5ddbfd761ee00c12ee1be86c9c0683ecf5bb14c9772ddbd782085779a63dd55b", size = 4202709 }, + { url = "https://files.pythonhosted.org/packages/39/63/b3fc299528d7df1f678b0666002b37affe6b8751225c3d9c12cf530e73ed/pillow-11.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa", size = 4372556 }, + { url = "https://files.pythonhosted.org/packages/c6/a6/694122c55b855b586c26c694937d36bb8d3b09c735ff41b2f315c6e66a10/pillow-11.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b4fd7bd29610a83a8c9b564d457cf5bd92b4e11e79a4ee4716a63c959699b306", size = 4287187 }, + { url = "https://files.pythonhosted.org/packages/ba/a9/f9d763e2671a8acd53d29b1e284ca298bc10a595527f6be30233cdb9659d/pillow-11.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cb929ca942d0ec4fac404cbf520ee6cac37bf35be479b970c4ffadf2b6a1cad9", size = 4418468 }, + { url = "https://files.pythonhosted.org/packages/6e/0e/b5cbad2621377f11313a94aeb44ca55a9639adabcaaa073597a1925f8c26/pillow-11.0.0-cp311-cp311-win32.whl", hash = "sha256:006bcdd307cc47ba43e924099a038cbf9591062e6c50e570819743f5607404f5", size = 2249249 }, + { url = "https://files.pythonhosted.org/packages/dc/83/1470c220a4ff06cd75fc609068f6605e567ea51df70557555c2ab6516b2c/pillow-11.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:52a2d8323a465f84faaba5236567d212c3668f2ab53e1c74c15583cf507a0291", size = 2566769 }, + { url = "https://files.pythonhosted.org/packages/52/98/def78c3a23acee2bcdb2e52005fb2810ed54305602ec1bfcfab2bda6f49f/pillow-11.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:16095692a253047fe3ec028e951fa4221a1f3ed3d80c397e83541a3037ff67c9", size = 2254611 }, + { url = "https://files.pythonhosted.org/packages/1c/a3/26e606ff0b2daaf120543e537311fa3ae2eb6bf061490e4fea51771540be/pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923", size = 3147642 }, + { url = "https://files.pythonhosted.org/packages/4f/d5/1caabedd8863526a6cfa44ee7a833bd97f945dc1d56824d6d76e11731939/pillow-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903", size = 2978999 }, + { url = "https://files.pythonhosted.org/packages/d9/ff/5a45000826a1aa1ac6874b3ec5a856474821a1b59d838c4f6ce2ee518fe9/pillow-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4", size = 4196794 }, + { url = "https://files.pythonhosted.org/packages/9d/21/84c9f287d17180f26263b5f5c8fb201de0f88b1afddf8a2597a5c9fe787f/pillow-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f", size = 4300762 }, + { url = "https://files.pythonhosted.org/packages/84/39/63fb87cd07cc541438b448b1fed467c4d687ad18aa786a7f8e67b255d1aa/pillow-11.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9", size = 4210468 }, + { url = "https://files.pythonhosted.org/packages/7f/42/6e0f2c2d5c60f499aa29be14f860dd4539de322cd8fb84ee01553493fb4d/pillow-11.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7", size = 4381824 }, + { url = "https://files.pythonhosted.org/packages/31/69/1ef0fb9d2f8d2d114db982b78ca4eeb9db9a29f7477821e160b8c1253f67/pillow-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6", size = 4296436 }, + { url = "https://files.pythonhosted.org/packages/44/ea/dad2818c675c44f6012289a7c4f46068c548768bc6c7f4e8c4ae5bbbc811/pillow-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc", size = 4429714 }, + { url = "https://files.pythonhosted.org/packages/af/3a/da80224a6eb15bba7a0dcb2346e2b686bb9bf98378c0b4353cd88e62b171/pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6", size = 2249631 }, + { url = "https://files.pythonhosted.org/packages/57/97/73f756c338c1d86bb802ee88c3cab015ad7ce4b838f8a24f16b676b1ac7c/pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47", size = 2567533 }, + { url = "https://files.pythonhosted.org/packages/0b/30/2b61876e2722374558b871dfbfcbe4e406626d63f4f6ed92e9c8e24cac37/pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25", size = 2254890 }, + { url = "https://files.pythonhosted.org/packages/63/24/e2e15e392d00fcf4215907465d8ec2a2f23bcec1481a8ebe4ae760459995/pillow-11.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699", size = 3147300 }, + { url = "https://files.pythonhosted.org/packages/43/72/92ad4afaa2afc233dc44184adff289c2e77e8cd916b3ddb72ac69495bda3/pillow-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38", size = 2978742 }, + { url = "https://files.pythonhosted.org/packages/9e/da/c8d69c5bc85d72a8523fe862f05ababdc52c0a755cfe3d362656bb86552b/pillow-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2", size = 4194349 }, + { url = "https://files.pythonhosted.org/packages/cd/e8/686d0caeed6b998351d57796496a70185376ed9c8ec7d99e1d19ad591fc6/pillow-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2", size = 4298714 }, + { url = "https://files.pythonhosted.org/packages/ec/da/430015cec620d622f06854be67fd2f6721f52fc17fca8ac34b32e2d60739/pillow-11.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527", size = 4208514 }, + { url = "https://files.pythonhosted.org/packages/44/ae/7e4f6662a9b1cb5f92b9cc9cab8321c381ffbee309210940e57432a4063a/pillow-11.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa", size = 4380055 }, + { url = "https://files.pythonhosted.org/packages/74/d5/1a807779ac8a0eeed57f2b92a3c32ea1b696e6140c15bd42eaf908a261cd/pillow-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f", size = 4296751 }, + { url = "https://files.pythonhosted.org/packages/38/8c/5fa3385163ee7080bc13026d59656267daaaaf3c728c233d530e2c2757c8/pillow-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb", size = 4430378 }, + { url = "https://files.pythonhosted.org/packages/ca/1d/ad9c14811133977ff87035bf426875b93097fb50af747793f013979facdb/pillow-11.0.0-cp313-cp313-win32.whl", hash = "sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798", size = 2249588 }, + { url = "https://files.pythonhosted.org/packages/fb/01/3755ba287dac715e6afdb333cb1f6d69740a7475220b4637b5ce3d78cec2/pillow-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de", size = 2567509 }, + { url = "https://files.pythonhosted.org/packages/c0/98/2c7d727079b6be1aba82d195767d35fcc2d32204c7a5820f822df5330152/pillow-11.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84", size = 2254791 }, + { url = "https://files.pythonhosted.org/packages/eb/38/998b04cc6f474e78b563716b20eecf42a2fa16a84589d23c8898e64b0ffd/pillow-11.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b", size = 3150854 }, + { url = "https://files.pythonhosted.org/packages/13/8e/be23a96292113c6cb26b2aa3c8b3681ec62b44ed5c2bd0b258bd59503d3c/pillow-11.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003", size = 2982369 }, + { url = "https://files.pythonhosted.org/packages/97/8a/3db4eaabb7a2ae8203cd3a332a005e4aba00067fc514aaaf3e9721be31f1/pillow-11.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2", size = 4333703 }, + { url = "https://files.pythonhosted.org/packages/28/ac/629ffc84ff67b9228fe87a97272ab125bbd4dc462745f35f192d37b822f1/pillow-11.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a", size = 4412550 }, + { url = "https://files.pythonhosted.org/packages/d6/07/a505921d36bb2df6868806eaf56ef58699c16c388e378b0dcdb6e5b2fb36/pillow-11.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8", size = 4461038 }, + { url = "https://files.pythonhosted.org/packages/d6/b9/fb620dd47fc7cc9678af8f8bd8c772034ca4977237049287e99dda360b66/pillow-11.0.0-cp313-cp313t-win32.whl", hash = "sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8", size = 2253197 }, + { url = "https://files.pythonhosted.org/packages/df/86/25dde85c06c89d7fc5db17940f07aae0a56ac69aa9ccb5eb0f09798862a8/pillow-11.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904", size = 2572169 }, + { url = "https://files.pythonhosted.org/packages/51/85/9c33f2517add612e17f3381aee7c4072779130c634921a756c97bc29fb49/pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3", size = 2256828 }, ] [[package]] @@ -1138,6 +1348,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", size = 1205513 }, ] +[[package]] +name = "pygments" +version = "2.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", size = 4891905 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", size = 1205513 }, +] + [[package]] name = "pyjwt" version = "2.9.0" @@ -1253,6 +1472,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, ] +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612 }, + { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040 }, + { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829 }, + { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167 }, + { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952 }, + { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301 }, + { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638 }, + { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850 }, + { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980 }, + { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 }, + { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 }, + { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 }, + { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 }, + { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 }, + { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, + { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 }, + { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 }, + { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 }, + { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 }, + { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 }, + { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 }, + { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, +] + [[package]] name = "regex" version = "2024.9.11" diff --git a/libraries/python/events/events/events.py b/libraries/python/events/events/events.py index dbe84b46..80ba9075 100644 --- a/libraries/python/events/events/events.py +++ b/libraries/python/events/events/events.py @@ -38,7 +38,7 @@ class BaseEvent(BaseModel): session_id: str | None = Field(default=None) timestamp: datetime = Field(default_factory=datetime.now) message: str | None = Field(default=None) - metadata: dict[str, Any] = {} + metadata: dict[str, Any] = Field(default_factory=dict) def __str__(self) -> str: return f"{self.__class__.__name__}: {self.message}" diff --git a/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb b/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb index cbc18ebf..5c65e71e 100644 --- a/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb +++ b/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb @@ -1,742 +1,1216 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Chat Driver\n", - "\n", - "An OpenAI Chat Completions API wrapper." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Notebook setup\n", - "\n", - "Run this cell to set the notebook up. Other sections can be run independently." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "%reload_ext autoreload\n", - "%autoreload 2\n", - "\n", - "import os\n", - "from dotenv import load_dotenv\n", - "from azure.identity import aio, DefaultAzureCredential, get_bearer_token_provider, AzureCliCredential\n", - "\n", - "from openai import AsyncAzureOpenAI, AzureOpenAI\n", - "\n", - "import logging \n", - "import json\n", - "from pathlib import Path\n", - "\n", - "# Set up structured logging to a file.\n", - "class JsonFormatter(logging.Formatter):\n", - " def format(self, record) -> str:\n", - " record_dict = record.__dict__\n", - " log_record = {\n", - " 'timestamp': self.formatTime(record, self.datefmt),\n", - " 'level': record.levelname,\n", - " 'session_id': record_dict.get('session_id', None),\n", - " 'run_id': record_dict.get('run_id', None),\n", - " 'message': record.getMessage(),\n", - " 'data': record_dict.get('data', None),\n", - " 'module': record.module,\n", - " 'funcName': record.funcName,\n", - " 'lineNumber': record.lineno,\n", - " 'logger': record.name,\n", - " }\n", - " extra_fields = {\n", - " key: value for key, value in record.__dict__.items() \n", - " if key not in ['levelname', 'msg', 'args', 'exc_info', 'funcName', 'module', 'lineno', 'name', 'message', 'asctime', 'session_id', 'run_id', 'data']\n", - " }\n", - " log_record.update(extra_fields)\n", - " return json.dumps(log_record)\n", - "\n", - "logger = logging.getLogger()\n", - "logger.setLevel(logging.DEBUG)\n", - "modules = ['httpcore.connection', 'httpcore.http11', 'httpcore.sync.connection', 'httpx', 'openai', 'urllib3.connectionpool', 'urllib3.util.retry']\n", - "for module in modules:\n", - " logging.getLogger(module).setLevel(logging.ERROR)\n", - "if logger.hasHandlers():\n", - " logger.handlers.clear()\n", - "data_dir = Path('.data')\n", - "if not data_dir.exists():\n", - " data_dir.mkdir()\n", - "handler = logging.FileHandler(data_dir / 'logs.jsonl')\n", - "handler.setFormatter(JsonFormatter())\n", - "logger.addHandler(handler)\n", - "\n", - "\n", - "load_dotenv()\n", - "credential = DefaultAzureCredential()\n", - "\n", - "azure_openai_config = {\n", - " \"azure_endpoint\": os.environ.get(\"AZURE_OPENAI_ENDPOINT\", \"\"),\n", - " \"azure_deployment\": os.environ.get(\"AZURE_OPENAI_DEPLOYMENT\", \"\"),\n", - " \"api_version\": os.environ.get(\"AZURE_OPENAI_API_VERSION\", \"\"),\n", - " \"max_retries\": 2,\n", - "}\n", - "\n", - "model = azure_openai_config.get(\"azure_deployment\", \"gpt-4o\")\n", - "\n", - "async_client = AsyncAzureOpenAI(\n", - " **azure_openai_config,\n", - " azure_ad_token_provider=aio.get_bearer_token_provider(\n", - " aio.AzureCliCredential(),\n", - " \"https://cognitiveservices.azure.com/.default\",\n", - " ),\n", - ")\n", - "\n", - "client = AzureOpenAI(\n", - " **azure_openai_config,\n", - " azure_ad_token_provider=get_bearer_token_provider(\n", - " AzureCliCredential(),\n", - " \"https://cognitiveservices.azure.com/.default\",\n", - " ),\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## ChatCompletionsAPI usage\n", - "\n", - "Azure/OpenAI's Chat Completions API is the fundamental building block of an AI assistant that uses the GPT model. \n", - "\n", - "- https://platform.openai.com/docs/api-reference/chat\n", - "- https://github.com/openai/openai-python/blob/main/api.md\n", - "- https://platform.openai.com/docs/api-reference/chat drivers" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Sync" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ + "cells": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'id': 'chatcmpl-AQga9wXFldlhHVce3CfXMQ7jXo9L9', 'choices': [{'finish_reason': 'stop', 'index': 0, 'logprobs': None, 'message': {'content': 'This is a test.', 'refusal': None, 'role': 'assistant', 'function_call': None, 'tool_calls': None}}], 'created': 1730923577, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': {'completion_tokens': 5, 'prompt_tokens': 12, 'total_tokens': 17, 'completion_tokens_details': None, 'prompt_tokens_details': None}}\n" - ] - } - ], - "source": [ - "completion = client.chat.completions.create(\n", - " messages=[\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"Say this is a test\",\n", - " }\n", - " ],\n", - " model=model,\n", - ")\n", - "print(completion.model_dump())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Async" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Chat Driver\n", + "\n", + "An OpenAI Chat Completions API wrapper." + ] + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "ChatCompletion(id='chatcmpl-AQgaCid05i8dGgUHijQsvPAsMYbv4', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='This is a test.', refusal=None, role='assistant', function_call=None, tool_calls=None))], created=1730923580, model='gpt-4o-2024-08-06', object='chat.completion', service_tier=None, system_fingerprint='fp_d54531d9eb', usage=CompletionUsage(completion_tokens=5, prompt_tokens=12, total_tokens=17, completion_tokens_details=None, prompt_tokens_details=None))\n" - ] - } - ], - "source": [ - "response = await async_client.chat.completions.create(\n", - " messages=[\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"Say this is a test\",\n", - " }\n", - " ],\n", - " model=model,\n", - ")\n", - "print(response)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Streaming" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Notebook setup\n", + "\n", + "Run this cell to set the notebook up. Other sections can be run independently." + ] + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': '', 'function_call': None, 'refusal': None, 'role': 'assistant', 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", - "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': 'This', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", - "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': ' is', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", - "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': ' a', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", - "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': ' test', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", - "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': '.', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", - "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': None, 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': 'stop', 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n" - ] - } - ], - "source": [ - "stream = await async_client.chat.completions.create(\n", - " messages=[\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"Say this is a test\",\n", - " }\n", - " ],\n", - " model=model,\n", - " stream=True,\n", - ")\n", - "async for chunk in stream:\n", - " print(chunk.model_dump())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## OpenAI Chat Completion Driver (a.k.a \"chat driver\")\n", - "\n", - "### OpenAI Assistants\n", - "\n", - "The Azure/OpenAI Assistants API is newer, stateful API that splits an `assistant` from the data about a conversation `thread` that can be `run` against an `assistant`. Additionally, you can add `tools` to an assistant that enable the assistant to have more interactive capabilities. The tools currently available are:\n", - "\n", - "- *Functions*: Registering local functions with the assistant so it knows it can call them before generating a response. This is a \"hold on let me look that up for you\" kind of interaction.\n", - "- *File Search* (formerly the retrieval plugin): Attach one or more files and they will be RAG-vectorized and available as content to the assistant.\n", - "- *Code Interpreter*: Run python code in a secure sandbox.\n", - "\n", - "The Assistant API productized as OpenAI's `GPTs` product. The `GPT Builder` lets developers create and deploy GPTs assistants using a web interface.\n", - "\n", - "### Chat Driver\n", - "\n", - "But an \"assistant\" requires pretty strong \"abstraction lock-in\". This thing isn't really an assistant in the fullest sense... it's more like a \"pseudo-assistant\", but this confuses things. Let's just let the Chat Completion API be what it is and drive it as necessary as we create our assistants. Let's just wrap up the function calling bits (which, ultimately, can give you the other tools like Functions and File Search) in a simple-to-use GPT-like interface we'll call a *chat driver*.\n", - "\n", - "The chat driver is meant to be used the exact way the Chat Completions API is... just easier.\n", - "\n", - "Our chat driver provides:\n", - "\n", - "- The ability to almost magically register functions to the function tool using a `FunctionRegistry`.\n", - "- Tracking of message history.\n", - "- Management of a `Context` object that can be used for session management and supply additional context to functions.\n", - "- Some prompt creation helpers.\n", - "- Other utilities... this is just meant to be an interface you can use to forget about all the api complexities." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "%reload_ext autoreload\n", + "%autoreload 2\n", + "\n", + "import os\n", + "from dotenv import load_dotenv\n", + "from azure.identity import aio, DefaultAzureCredential, get_bearer_token_provider, AzureCliCredential\n", + "\n", + "from openai import AsyncAzureOpenAI, AzureOpenAI\n", + "\n", + "import logging \n", + "import json\n", + "from pathlib import Path\n", + "\n", + "LOGGING = {\n", + " \"version\": 1,\n", + " \"disable_existing_loggers\": False,\n", + " \"formatters\": {\n", + " \"json\": {\n", + " \"()\": \"pythonjsonlogger.jsonlogger.JsonFormatter\",\n", + " \"fmt\": \"%(asctime)s %(levelname)s %(name)s %(message)s\",\n", + "\n", + " }\n", + " },\n", + "}\n", + "\n", + "\n", + "# Set up structured logging to a file. All of the cells in this notebook use\n", + "# this logger. Find them at .data/logs.jsonl.\n", + "class JsonFormatter(logging.Formatter):\n", + " def format(self, record) -> str:\n", + " record_dict = record.__dict__\n", + " log_record = {\n", + " 'timestamp': self.formatTime(record, self.datefmt),\n", + " 'level': record.levelname,\n", + " 'session_id': record_dict.get('session_id', None),\n", + " 'run_id': record_dict.get('run_id', None),\n", + " 'message': record.getMessage(),\n", + " 'data': record_dict.get('data', None),\n", + " 'module': record.module,\n", + " 'funcName': record.funcName,\n", + " 'lineNumber': record.lineno,\n", + " 'logger': record.name,\n", + " }\n", + " extra_fields = {\n", + " key: value for key, value in record.__dict__.items() \n", + " if key not in ['levelname', 'msg', 'args', 'exc_info', 'funcName', 'module', 'lineno', 'name', 'message', 'asctime', 'session_id', 'run_id', 'data']\n", + " }\n", + " log_record.update(extra_fields)\n", + " return json.dumps(log_record)\n", + "\n", + "logger = logging.getLogger()\n", + "logger.setLevel(logging.DEBUG)\n", + "modules = ['httpcore.connection', 'httpcore.http11', 'httpcore.sync.connection', 'httpx', 'openai', 'urllib3.connectionpool', 'urllib3.util.retry']\n", + "for module in modules:\n", + " logging.getLogger(module).setLevel(logging.ERROR)\n", + "if logger.hasHandlers():\n", + " logger.handlers.clear()\n", + "data_dir = Path('.data')\n", + "if not data_dir.exists():\n", + " data_dir.mkdir()\n", + "handler = logging.FileHandler(data_dir / 'logs.jsonl')\n", + "handler.setFormatter(JsonFormatter())\n", + "logger.addHandler(handler)\n", + "\n", + "\n", + "load_dotenv()\n", + "credential = DefaultAzureCredential()\n", + "\n", + "azure_openai_config = {\n", + " \"azure_endpoint\": os.environ.get(\"AZURE_OPENAI_ENDPOINT\", \"\"),\n", + " \"azure_deployment\": os.environ.get(\"AZURE_OPENAI_DEPLOYMENT\", \"\"),\n", + " \"api_version\": os.environ.get(\"AZURE_OPENAI_API_VERSION\", \"\"),\n", + " \"max_retries\": 2,\n", + "}\n", + "logger.info(\"Azure OpenAI configuration\", extra=azure_openai_config)\n", + "\n", + "async_client = AsyncAzureOpenAI(\n", + " **azure_openai_config,\n", + " azure_ad_token_provider=aio.get_bearer_token_provider(\n", + " aio.AzureCliCredential(),\n", + " \"https://cognitiveservices.azure.com/.default\",\n", + " ),\n", + ")\n", + "\n", + "client = AzureOpenAI(\n", + " **azure_openai_config,\n", + " azure_ad_token_provider=get_bearer_token_provider(\n", + " AzureCliCredential(),\n", + " \"https://cognitiveservices.azure.com/.default\",\n", + " ),\n", + ")\n", + "\n", + "model: str = azure_openai_config.get(\"azure_deployment\", \"gpt-4o\")\n" + ] + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "conversation-id-1000\n", - "\n", - "Hello Paul! How can I assist you today?\n", - "\n", - "Commands:\n", - "help(): Return this help message.\n", - "erase(name: str): Erases a stored value.\n", - "echo(text: str): Return the text.\n", - "get_file_contents(file_path: str): Return the contents of a file.\n", - "\n", - "conversation-id-1000: Hi, my name is Paul.\n", - "\n", - "The content of \"123.txt\" is: \"The purpose of life is to be happy.\"\n", - "\n", - "{\n", - " \"id\": \"9444f8f2-aa5a-4c19-9bf4-d36b6bfa9ba4\",\n", - " \"session_id\": null,\n", - " \"timestamp\": \"2024-11-06T20:06:27.777169\",\n", - " \"message\": \"The content of \\\"123.txt\\\" is: \\\"The purpose of life is to be happy.\\\"\",\n", - " \"metadata\": {\n", - " \"completion_args\": {\n", - " \"model\": \"gpt-4o\",\n", - " \"messages\": [\n", - " {\n", - " \"role\": \"system\",\n", - " \"content\": \"You are a helpful assistant.\"\n", - " },\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"Hi, my name is Paul.\"\n", - " },\n", - " {\n", - " \"role\": \"assistant\",\n", - " \"content\": \"Hello Paul! How can I assist you today?\"\n", - " },\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"Please tell me what's in file 123.txt.\"\n", - " }\n", - " ],\n", - " \"tools\": [\n", - " {\n", - " \"type\": \"function\",\n", - " \"function\": {\n", - " \"name\": \"help\",\n", - " \"description\": \"Return this help message.\",\n", - " \"strict\": true,\n", - " \"parameters\": {\n", - " \"type\": \"object\",\n", - " \"properties\": {},\n", - " \"additionalProperties\": false\n", - " }\n", - " }\n", - " },\n", - " {\n", - " \"type\": \"function\",\n", - " \"function\": {\n", - " \"name\": \"erase\",\n", - " \"description\": \"Erases a stored value.\",\n", - " \"strict\": true,\n", - " \"parameters\": {\n", - " \"type\": \"object\",\n", - " \"properties\": {\n", - " \"name\": {\n", - " \"type\": \"string\"\n", - " }\n", - " },\n", - " \"additionalProperties\": false,\n", - " \"required\": [\n", - " \"name\"\n", - " ]\n", - " }\n", - " }\n", - " },\n", - " {\n", - " \"type\": \"function\",\n", - " \"function\": {\n", - " \"name\": \"echo\",\n", - " \"description\": \"Return the text.\",\n", - " \"strict\": true,\n", - " \"parameters\": {\n", - " \"type\": \"object\",\n", - " \"properties\": {\n", - " \"text\": {\n", - " \"type\": \"string\"\n", - " }\n", - " },\n", - " \"additionalProperties\": false,\n", - " \"required\": [\n", - " \"text\"\n", - " ]\n", - " }\n", - " }\n", - " },\n", - " {\n", - " \"type\": \"function\",\n", - " \"function\": {\n", - " \"name\": \"get_file_contents\",\n", - " \"description\": \"Return the contents of a file.\",\n", - " \"strict\": true,\n", - " \"parameters\": {\n", - " \"type\": \"object\",\n", - " \"properties\": {\n", - " \"file_path\": {\n", - " \"type\": \"string\"\n", - " }\n", - " },\n", - " \"additionalProperties\": false,\n", - " \"required\": [\n", - " \"file_path\"\n", - " ]\n", - " }\n", - " }\n", - " }\n", - " ],\n", - " \"tool_choice\": null,\n", - " \"response_format\": {\n", - " \"type\": \"text\"\n", - " }\n", - " },\n", - " \"completion\": {\n", - " \"id\": \"chatcmpl-AQgaIFjYmKV3PUaYNUoYOKQ9LraYg\",\n", - " \"choices\": [\n", - " {\n", - " \"finish_reason\": \"tool_calls\",\n", - " \"index\": 0,\n", - " \"logprobs\": null,\n", - " \"message\": {\n", - " \"content\": null,\n", - " \"refusal\": null,\n", - " \"role\": \"assistant\",\n", - " \"function_call\": null,\n", - " \"tool_calls\": [\n", - " {\n", - " \"id\": \"call_hCAzGLjdWGTBMVbJDi3ZYs2Z\",\n", - " \"function\": {\n", - " \"arguments\": \"{\\\"file_path\\\":\\\"123.txt\\\"}\",\n", - " \"name\": \"get_file_contents\",\n", - " \"parsed_arguments\": {\n", - " \"file_path\": \"123.txt\"\n", - " }\n", - " },\n", - " \"type\": \"function\"\n", - " }\n", - " ],\n", - " \"parsed\": null\n", - " }\n", - " }\n", - " ],\n", - " \"created\": 1730923586,\n", - " \"model\": \"gpt-4o-2024-08-06\",\n", - " \"object\": \"chat.completion\",\n", - " \"service_tier\": null,\n", - " \"system_fingerprint\": \"fp_d54531d9eb\",\n", - " \"usage\": {\n", - " \"completion_tokens\": 17,\n", - " \"prompt_tokens\": 135,\n", - " \"total_tokens\": 152,\n", - " \"completion_tokens_details\": null,\n", - " \"prompt_tokens_details\": null\n", - " }\n", - " },\n", - " \"tool_completion_args\": {\n", - " \"model\": \"gpt-4o\",\n", - " \"messages\": [\n", - " {\n", - " \"role\": \"system\",\n", - " \"content\": \"You are a helpful assistant.\"\n", - " },\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"Hi, my name is Paul.\"\n", - " },\n", - " {\n", - " \"role\": \"assistant\",\n", - " \"content\": \"Hello Paul! How can I assist you today?\"\n", - " },\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"Please tell me what's in file 123.txt.\"\n", - " },\n", - " {\n", - " \"role\": \"assistant\",\n", - " \"tool_calls\": [\n", - " {\n", - " \"id\": \"call_hCAzGLjdWGTBMVbJDi3ZYs2Z\",\n", - " \"function\": {\n", - " \"arguments\": \"{\\\"file_path\\\":\\\"123.txt\\\"}\",\n", - " \"name\": \"get_file_contents\",\n", - " \"parsed_arguments\": {\n", - " \"file_path\": \"123.txt\"\n", - " }\n", - " },\n", - " \"type\": \"function\"\n", - " }\n", - " ]\n", - " },\n", - " {\n", - " \"role\": \"tool\",\n", - " \"content\": \"The purpose of life is to be happy.\",\n", - " \"tool_call_id\": \"call_hCAzGLjdWGTBMVbJDi3ZYs2Z\"\n", - " }\n", - " ],\n", - " \"response_format\": {\n", - " \"type\": \"text\"\n", - " }\n", - " }\n", - " }\n", - "}\n" - ] - } - ], - "source": [ - "from typing import cast\n", - "from chat_driver import ChatDriver, ChatDriverConfig, Context\n", - "from chat_driver import LocalMessageHistoryProvider #, LocalMessageHistoryProviderConfig\n", - "# from typing import List\n", - "# from openai.types.chat import ChatCompletionMessageParam\n", - "\n", - "\n", - "# When an chat driver is created, it will automatically create a context with a\n", - "# session_id. Or, if you want to use a specific session_id, you can pass it as\n", - "# an argument. This is useful for scoping this chat driver instance to an\n", - "# external identifier.\n", - "context = Context(\"conversation-id-1000\")\n", - "\n", - "\n", - "# Define tool functions for the chat driver. All functions used by the chat driver\n", - "# require a session_id as the first argument.\n", - "def get_file_contents(context: Context, file_path: str) -> str:\n", - " \"\"\"Return the contents of a file.\"\"\"\n", - " return \"The purpose of life is to be happy.\"\n", - "\n", - "\n", - "def erase(context: Context, name: str) -> str:\n", - " \"\"\"Erases a stored value.\"\"\"\n", - " return f\"{context.session_id}: {name} erased\"\n", - "\n", - "\n", - "# Define the chat driver.\n", - "instructions = \"You are a helpful assistant.\"\n", - "\n", - "# Define the conversation so far (optional).\n", - "# messages: List[ChatCompletionMessageParam] = []\n", - "# localMessageHistoryConfig = LocalMessageHistoryProviderConfig(f\"./data/{context.session_id}\", messages)\n", - "# message_provider = LocalMessageHistoryProvider(localMessageHistoryConfig)\n", - "\n", - "chat_driver = ChatDriver(\n", - " ChatDriverConfig(\n", - " openai_client=async_client,\n", - " model=model,\n", - " instructions=instructions,\n", - " context=context,\n", - " # message_provider=message_provider,\n", - " commands=[erase], # Commands can be registered when instantiating the chat driver.\n", - " functions=[erase], # Functions can be registered when instantiating the chat driver.\n", - " ),\n", - ")\n", - "\n", - "# Let's clear the data from previous runs.\n", - "message_provider = cast(LocalMessageHistoryProvider, chat_driver.message_provider)\n", - "message_provider.delete_all()\n", - "\n", - "\n", - "# You can also use the `register_function` decorator to register a function.\n", - "# Remember, all functions used by the chat driver require a session_id as the\n", - "# first argument.\n", - "@chat_driver.register_function_and_command\n", - "def echo(context: Context, text: str) -> str:\n", - " \"\"\"Return the text.\"\"\"\n", - " return f\"{context.session_id}: {text}\"\n", - "\n", - "\n", - "# You can also register functions manually.\n", - "chat_driver.register_function_and_command(get_file_contents)\n", - "\n", - "# Ok. Let's see if we got one.\n", - "print(chat_driver.context.session_id)\n", - "\n", - "# Let's see if the agent can respond.\n", - "response = await chat_driver.respond(\"Hi, my name is Paul.\")\n", - "print()\n", - "print(response.message)\n", - "\n", - "# Help command (shows command available).\n", - "response = await chat_driver.respond(\"/help\")\n", - "print()\n", - "print(response.message)\n", - "\n", - "# We can run any function or command directly.\n", - "response = await chat_driver.functions.echo(\"Hi, my name is Paul.\")\n", - "print()\n", - "print(response)\n", - "\n", - "# Let's see if the chat driver has the ability to run it's own registered function.\n", - "response = await chat_driver.respond(\"Please tell me what's in file 123.txt.\")\n", - "print()\n", - "print(response.message)\n", - "\n", - "# Let's see the full response event.\n", - "print()\n", - "print(response.to_json())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Chat with a chat driver" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ChatCompletionsAPI usage\n", + "\n", + "Azure/OpenAI's Chat Completions API is the fundamental building block of an AI assistant that uses the GPT model. \n", + "\n", + "- https://platform.openai.com/docs/api-reference/chat\n", + "- https://github.com/openai/openai-python/blob/main/api.md\n", + "- https://platform.openai.com/docs/api-reference/chat drivers" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Sync" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'id': 'chatcmpl-AQga9wXFldlhHVce3CfXMQ7jXo9L9', 'choices': [{'finish_reason': 'stop', 'index': 0, 'logprobs': None, 'message': {'content': 'This is a test.', 'refusal': None, 'role': 'assistant', 'function_call': None, 'tool_calls': None}}], 'created': 1730923577, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': {'completion_tokens': 5, 'prompt_tokens': 12, 'total_tokens': 17, 'completion_tokens_details': None, 'prompt_tokens_details': None}}\n" + ] + } + ], + "source": [ + "completion = client.chat.completions.create(\n", + " messages=[\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"Say this is a test\",\n", + " }\n", + " ],\n", + " model=model,\n", + ")\n", + "print(completion.model_dump_json(indent=2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Async" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ChatCompletion(id='chatcmpl-AQgaCid05i8dGgUHijQsvPAsMYbv4', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='This is a test.', refusal=None, role='assistant', function_call=None, tool_calls=None))], created=1730923580, model='gpt-4o-2024-08-06', object='chat.completion', service_tier=None, system_fingerprint='fp_d54531d9eb', usage=CompletionUsage(completion_tokens=5, prompt_tokens=12, total_tokens=17, completion_tokens_details=None, prompt_tokens_details=None))\n" + ] + } + ], + "source": [ + "message_event = await async_client.chat.completions.create(\n", + " messages=[\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"Say this is a test\",\n", + " }\n", + " ],\n", + " model=model,\n", + ")\n", + "print(message_event)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Streaming" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': '', 'function_call': None, 'refusal': None, 'role': 'assistant', 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': 'This', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': ' is', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': ' a', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': ' test', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': '.', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': None, 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': 'stop', 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n" + ] + } + ], + "source": [ + "stream = await async_client.chat.completions.create(\n", + " messages=[\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"Say this is a test\",\n", + " }\n", + " ],\n", + " model=model,\n", + " stream=True,\n", + ")\n", + "async for chunk in stream:\n", + " print(chunk.model_dump())" + ] + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "User: /echo(\"hello world\")\n", - "Assistant: hello world\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## OpenAI Helpers" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Standardized response handling" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The future of AI is both exciting and complex, with its trajectory shaped by advances in technology, ethical considerations, and societal needs. As we look ahead, several key themes emerge:\n", + "\n", + "1. **Integration and Personalization**: AI will become increasingly integrated into our daily lives, driving personalized experiences. From healthcare to education, AI systems will tailor recommendations and interventions to individual needs, optimizing outcomes across various sectors.\n", + "\n", + "2. **AI in Healthcare**: We can expect AI to revolutionize the healthcare industry by enhancing diagnostic accuracy, streamlining administrative processes, and developing personalized medicine. AI-driven tools could predict diseases, recommend treatments, and even aid in surgical procedures, ultimately improving patient care and reducing costs.\n", + "\n", + "3. **Autonomous Systems**: Autonomous vehicles, drones, and robotic systems will become more prevalent, transforming industries like transportation, logistics, and manufacturing. These systems will improve efficiency and safety while also creating new business models and opportunities.\n", + "\n", + "4. **Ethical and Responsible AI**: As AI systems become more autonomous, the demand for ethical AI frameworks will increase. Ensuring transparency, fairness, accountability, and privacy will be crucial to maintaining public trust. Developing AI systems that align with human values and societal norms will be an ongoing challenge.\n", + "\n", + "5. **AI and the Workforce**: While AI will automate certain tasks, it will also create new job opportunities and demand an upskilled workforce. It is important to focus on reskilling and education initiatives to prepare the workforce for an AI-augmented future.\n", + "\n", + "6. **AI in Climate and Sustainability**: AI will play a significant role in addressing climate change and promoting sustainability. From optimizing energy usage and improving agricultural practices to predicting environmental changes, AI could be a critical tool in creating a more sustainable future.\n", + "\n", + "7. **AI in Creativity and Arts**: AI is increasingly being used in creative fields, such as music, art, and literature. While it can augment human creativity by offering new tools and perspectives, there will be ongoing discussions about the nature of creativity and authorship.\n", + "\n", + "8. **AI Governance and Policy**: With AI's growing influence, policy and regulation will need to keep pace to address issues such as data ownership, algorithmic bias, and national security. International collaboration may be necessary to create coherent frameworks addressing these challenges.\n", + "\n", + "In summary, AI has the potential to greatly benefit society, but its development requires thoughtful consideration of ethical, social, and economic impacts. As we move forward, collaboration among technologists, policymakers, and the public will be essential to harness AI for the greater good.\n" + ] + } + ], + "source": [ + "from context import Context\n", + "from openai_client.errors import CompletionError, validate_completion\n", + "from openai_client.logging import extra_data, serializable_completion_args\n", + "from openai_client.completion import completion_message_string\n", + "\n", + "context = Context(\"conversation-id-1005\")\n", + "\n", + "# We use a metadata dictionary in our helpers to store information about the\n", + "# completion request.\n", + "metadata = {}\n", + "\n", + "# This is just standard OpenAI completion request arguments.\n", + "completion_args = {\n", + " \"model\": model,\n", + " \"messages\": [\n", + " {\n", + " \"role\": \"system\",\n", + " \"content\": \"You are a famous computer scientist. You are giving a talk at a conference. You are talking about the future of AI and how it will change the world. You are asked a questions by audience members and answer thoughtfully.\",\n", + " },\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"What is the future of AI?\",\n", + " }\n", + " ],\n", + "}\n", + "\n", + "# If we these completion args to logs and metadata, though, they need to be\n", + "# serializable. We have a helper for that.\n", + "metadata[\"completion_args\"] = serializable_completion_args(completion_args)\n", + "\n", + "# We have helpers for validating the response and handling exceptions in a\n", + "# standardized way. These ensure that logging happens and metadata is loaded up\n", + "# properly.\n", + "try:\n", + " completion = await async_client.beta.chat.completions.parse(**completion_args)\n", + "\n", + " # This helper looks for any error-like situations (the model refuses to\n", + " # answer, content filters, incomplete responses) and throws exceptions that\n", + " # are handled by the next helper. The first argument is an identifier that\n", + " # will be used for logs and metadata namespacing.\n", + " validate_completion(completion)\n", + " logger.debug(\"completion response.\", extra=extra_data(completion))\n", + " metadata[\"completion\"] = completion.model_dump()\n", + "\n", + "except Exception as e:\n", + " # This helper processes all the types of error conditions you might get from\n", + " # the OpenAI API in a standardized way.\n", + " completion_error = CompletionError(e)\n", + " print(completion_error)\n", + " print(completion_error.body)\n", + "\n", + "else:\n", + " # The message_string helper is used to extract the response from the completion\n", + " # (which can get tedious).\n", + " print(completion_message_string(completion))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### JSON" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"thoughts\": \"AI is rapidly evolving and has the potential to transform virtually every industry. With advancements in machine learning, natural language processing, and robotics, AI will continue to play a crucial role in automating routine tasks and providing intelligent insights.\",\n", + " \"answer\": \"The future of AI involves deeper integration into everyday life and industry. We will likely see AI systems becoming more autonomous, sophisticated, and seamlessly integrated into systems like healthcare, transportation, and personalized services. AI's future encompasses not only technological advancements but also ethical considerations and ensuring beneficial societal impacts.\"\n", + "}\n" + ] + } + ], + "source": [ + "from context import Context\n", + "from openai_client.errors import CompletionError, validate_completion\n", + "from openai_client.logging import extra_data, serializable_completion_args\n", + "from openai_client.completion import completion_message_dict, JSON_OBJECT_RESPONSE_FORMAT\n", + "\n", + "context = Context(\"conversation-id-1002\")\n", + "metadata = {}\n", + "completion_args = {\n", + " \"model\": model,\n", + " \"messages\": [\n", + " {\n", + " \"role\": \"system\",\n", + " \"content\": \"You are a famous computer scientist. You are giving a talk at a conference. You are talking about the future of AI and how it will change the world. You are asked a questions by audience members and return your answer as valid JSON like { \\\"thoughts\\\": , \\\"answer\\\": }.\",\n", + " },\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"What is the future of AI?\",\n", + " }\n", + " ],\n", + " \"response_format\": JSON_OBJECT_RESPONSE_FORMAT,\n", + "}\n", + "metadata[\"completion_args\"] = serializable_completion_args(completion_args)\n", + "try:\n", + " completion = await async_client.beta.chat.completions.parse(**completion_args)\n", + " validate_completion(completion)\n", + " metadata[\"completion\"] = completion.model_dump()\n", + "except Exception as e:\n", + " completion_error = CompletionError(e)\n", + " metadata[\"completion_error\"] = completion_error.body\n", + " logger.error(completion_error.message, extra=extra_data({\"error\": completion_error.body, \"metadata\": metadata}))\n", + "else:\n", + " message = completion_message_dict(completion)\n", + " print(json.dumps(message, indent=2))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Structured Output\n", + "\n", + "Any Pydantic BaseModel can be used as the \"response_format\" and OpenAI will try to load it up for you." + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"thoughts\": \"AI has shown immense potential in various fields, including healthcare, transportation, and climate science. The trajectory of its development suggests even greater integration into daily life and business operations.\",\n", + " \"answer\": \"The future of AI lies in its ability to become more autonomous, adaptive, and integrated into various facets of life and industry. We will likely see AI taking on increasingly complex tasks with minimal human intervention, improving efficiency and productivity. It will transform sectors like healthcare through predictive diagnostics, personalize education, and enhance decision-making in businesses with deeper insights from data analytics. However, it will also be crucial to address ethical concerns, such as privacy, bias, and the impact on jobs, to ensure AI serves the broader good.\"\n", + "}\n" + ] + } + ], + "source": [ + "from context import Context\n", + "from pydantic import BaseModel\n", + "from typing import cast\n", + "from openai_client.errors import CompletionError, validate_completion\n", + "from openai_client.logging import extra_data, serializable_completion_args\n", + "from openai_client.completion import completion_message_dict, JSON_OBJECT_RESPONSE_FORMAT\n", + "\n", + "class Output(BaseModel):\n", + " thoughts: str\n", + " answer: str\n", + "\n", + "context = Context(\"conversation-id-1002\")\n", + "metadata = {}\n", + "completion_args = {\n", + " \"model\": model,\n", + " \"messages\": [\n", + " {\n", + " \"role\": \"system\",\n", + " \"content\": \"You are a famous computer scientist. You are giving a talk at a conference. You are talking about the future of AI and how it will change the world. You are asked a questions by audience members and return your answer as valid JSON like { \\\"thoughts\\\": , \\\"answer\\\": }.\",\n", + " },\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"What is the future of AI?\",\n", + " }\n", + " ],\n", + " \"response_format\": Output,\n", + "}\n", + "\n", + "metadata[\"completion_args\"] = serializable_completion_args(completion_args)\n", + "try:\n", + " completion = await async_client.beta.chat.completions.parse(**completion_args)\n", + " validate_completion(completion)\n", + " metadata[\"completion\"] = completion.model_dump()\n", + "except Exception as e:\n", + " completion_error = CompletionError(e)\n", + " metadata[\"completion_error\"] = completion_error.body\n", + " logger.error(completion_error.message, extra=extra_data({\"error\": completion_error.body, \"metadata\": metadata}))\n", + "else:\n", + " # The parsed message is in the `parsed` attribute.\n", + " output = cast(Output, completion.choices[0].message.parsed)\n", + " print(output.model_dump_json(indent=2))\n", + "\n", + " # Or you can just get the text of the message like usual.\n", + " # print(completion.choices[0].message.content)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## OpenAI Chat Completion Driver (a.k.a \"chat driver\")\n", + "\n", + "### OpenAI Assistants\n", + "\n", + "The Azure/OpenAI Assistants API is newer, stateful API that splits an `assistant` from the data about a conversation `thread` that can be `run` against an `assistant`. Additionally, you can add `tools` to an assistant that enable the assistant to have more interactive capabilities. The tools currently available are:\n", + "\n", + "- *Functions*: Registering local functions with the assistant so it knows it can call them before generating a response. This is a \"hold on let me look that up for you\" kind of interaction.\n", + "- *File Search* (formerly the retrieval plugin): Attach one or more files and they will be RAG-vectorized and available as content to the assistant.\n", + "- *Code Interpreter*: Run python code in a secure sandbox.\n", + "\n", + "The Assistant API productized as OpenAI's `GPTs` product. The `GPT Builder` lets developers create and deploy GPTs assistants using a web interface.\n", + "\n", + "### Chat Driver\n", + "\n", + "But an \"assistant\" requires pretty strong \"abstraction lock-in\". This thing isn't really an assistant in the fullest sense... it's more like a \"pseudo-assistant\", but this confuses things. Let's just let the Chat Completion API be what it is and drive it as necessary as we create our assistants. Let's just wrap up the function calling bits (which, ultimately, can give you the other tools like Functions and File Search) in a simple-to-use GPT-like interface we'll call a *chat driver*.\n", + "\n", + "The chat driver is meant to be used the exact way the Chat Completions API is... just easier.\n", + "\n", + "Our chat driver provides:\n", + "\n", + "- The ability to almost magically register functions to the function tool using a `FunctionRegistry`.\n", + "- Tracking of message history.\n", + "- Management of a `Context` object that can be used for session management and supply additional context to functions.\n", + "- Some prompt creation helpers.\n", + "- Other utilities... this is just meant to be an interface you can use to forget about all the api complexities." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Here is the simplest usage of a chat driver\n", + "\n", + "Notice that a .data directory is created by default. This is where the conversation history is stored." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "conversation-id-1000\n", + "\n", + "Hello Paul! How can I assist you today?\n", + "\n", + "Commands:\n", + "help(): Return this help message.\n", + "erase(name: str): Erases a stored value.\n", + "echo(text: str): Return the text.\n", + "get_file_contents(file_path: str): Return the contents of a file.\n", + "\n", + "conversation-id-1000: Hi, my name is Paul.\n", + "\n", + "The content of \"123.txt\" is: \"The purpose of life is to be happy.\"\n", + "\n", + "{\n", + " \"id\": \"9444f8f2-aa5a-4c19-9bf4-d36b6bfa9ba4\",\n", + " \"session_id\": null,\n", + " \"timestamp\": \"2024-11-06T20:06:27.777169\",\n", + " \"message\": \"The content of \\\"123.txt\\\" is: \\\"The purpose of life is to be happy.\\\"\",\n", + " \"metadata\": {\n", + " \"completion_args\": {\n", + " \"model\": \"gpt-4o\",\n", + " \"messages\": [\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"What is the future of AI?\"\n", + " },\n", + " {\n", + " \"role\": \"assistant\",\n", + " \"content\": \"The future of AI is incredibly promising and will likely be revolutionary in many aspects of our lives. In the coming years and decades, we can expect several major trends and developments to shape the landscape of artificial intelligence:\\n\\n1. **Ubiquitous Integration**: AI will continue to permeate all aspects of our daily lives, from personal assistants and smart home devices to complex systems in healthcare, finance, and transportation. This integration will enable more efficient, personalized, and automated experiences.\\n\\n2. **Advanced Machine Learning**: We will see significant advancements in machine learning techniques, particularly in areas such as reinforcement learning, unsupervised learning, and transfer learning. These advancements will improve AI's ability to learn from fewer examples and adapt more flexibly to new and changing environments.\\n\\n3. **Ethical and Explainable AI**: As AI becomes more entrenched in critical decision-making processes, there will be a stronger emphasis on developing ethical guidelines and explainable AI systems. This will involve creating transparent models that can be understood and trusted by humans, ensuring fairness and reducing bias.\\n\\n4. **AI and Human Collaboration**: The future will see AI as a collaborator rather than a mere tool. AI systems will augment human abilities, providing insights and recommendations so that people can make better decisions and enhance creativity and productivity across various fields.\\n\\n5. **AI in Healthcare**: AI will play a transformative role in healthcare, enabling early diagnosis, personalized treatment plans, drug discovery, and efficient management of healthcare systems. This can lead to significant improvements in patient outcomes and accessibility to medical services.\\n\\n6. **Autonomous Systems**: The development of autonomous vehicles, drones, and robots will advance, impacting industries such as logistics, agriculture, and urban planning. These systems will greatly improve efficiency and safety in operations.\\n\\n7. **AI Governance and Regulation**: As AI systems grow more powerful, there will be an increasing need for regulation to ensure they are used responsibly and do not harm society. This includes addressing issues such as privacy, security, and the impact on labor markets.\\n\\n8. **AI for Sustainability**: AI will be crucial in addressing global challenges like climate change, resource management, and conservation efforts, optimizing energy use, predicting environmental changes, and developing sustainable practices.\\n\\n9. **Quantum Computing and AI**: The integration of AI with quantum computing holds the potential to solve problems previously considered intractable, speeding up computation and enhancing AI's capabilities.\\n\\n10. **AI and Creativity**: AI will increasingly be involved in creative domains, assisting with tasks such as art, music, and writing, leading to new forms of expression and collaboration between humans and machines.\\n\\nIn summary, while AI presents numerous opportunities, it also comes with challenges that society must address. Ensuring that its development is aligned with societal values will be crucial for leveraging AI's potential in a way that benefits everyone.\"\n", + " },\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"What is the future of AI?\"\n", + " },\n", + " {\n", + " \"role\": \"assistant\",\n", + " \"content\": \"Hello Paul! How can I assist you today?\"\n", + " },\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"Please tell me what's in file 123.txt.\"\n", + " }\n", + " ],\n", + " \"tools\": [\n", + " {\n", + " \"type\": \"function\",\n", + " \"function\": {\n", + " \"name\": \"help\",\n", + " \"description\": \"Return this help message.\",\n", + " \"strict\": true,\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {},\n", + " \"additionalProperties\": false\n", + " }\n", + " }\n", + " },\n", + " {\n", + " \"type\": \"function\",\n", + " \"function\": {\n", + " \"name\": \"erase\",\n", + " \"description\": \"Erases a stored value.\",\n", + " \"strict\": true,\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"name\": {\n", + " \"type\": \"string\"\n", + " }\n", + " },\n", + " \"additionalProperties\": false,\n", + " \"required\": [\n", + " \"name\"\n", + " ]\n", + " }\n", + " }\n", + " },\n", + " {\n", + " \"type\": \"function\",\n", + " \"function\": {\n", + " \"name\": \"echo\",\n", + " \"description\": \"Return the text.\",\n", + " \"strict\": true,\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"text\": {\n", + " \"type\": \"string\"\n", + " }\n", + " },\n", + " \"additionalProperties\": false,\n", + " \"required\": [\n", + " \"text\"\n", + " ]\n", + " }\n", + " }\n", + " },\n", + " {\n", + " \"type\": \"function\",\n", + " \"function\": {\n", + " \"name\": \"get_file_contents\",\n", + " \"description\": \"Return the contents of a file.\",\n", + " \"strict\": true,\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"file_path\": {\n", + " \"type\": \"string\"\n", + " }\n", + " },\n", + " \"additionalProperties\": false,\n", + " \"required\": [\n", + " \"file_path\"\n", + " ]\n", + " }\n", + " }\n", + " }\n", + " ],\n", + " \"tool_choice\": null,\n", + " \"response_format\": {\n", + " \"type\": \"text\"\n", + " }\n", + " },\n", + " \"completion\": {\n", + " \"id\": \"chatcmpl-AQgaIFjYmKV3PUaYNUoYOKQ9LraYg\",\n", + " \"choices\": [\n", + " {\n", + " \"finish_reason\": \"stop\",\n", + " \"index\": 0,\n", + " \"logprobs\": null,\n", + " \"message\": {\n", + " \"content\": \"The future of AI is set to be transformative, with significant advancements and implications across many areas of life and industry. Here are some key trends and developments expected in the future of AI:\\n\\n1. **Widespread Integration**: AI will become deeply embedded into everyday life, enhancing technologies in sectors such as healthcare, finance, education, and entertainment. This integration will facilitate more efficient, personalized, and automated experiences.\\n\\n2. **Advanced Machine Learning**: Continuous improvements in machine learning algorithms, including deep learning, will enable AI systems to process and interpret complex data more effectively. This advancement will help AI systems become more autonomous and capable.\\n\\n3. **Ethical and Fair AI**: As AI's role grows, developing ethical guidelines and ensuring fairness will become increasingly important. Efforts will focus on minimizing bias and increasing transparency, fostering trust and acceptability.\\n\\n4. **Human-AI Collaboration**: AI will increasingly act as a collaborative partner, augmenting human abilities and enhancing creativity, decision-making, and productivity across various fields. This symbiosis will redefine how we work and interact with technology.\\n\\n5. **Healthcare Innovations**: AI is expected to revolutionize healthcare through improved diagnostics, personalized treatments, predictive analytics, and efficient management of healthcare operations. This could lead to better patient outcomes and more accessible healthcare services.\\n\\n6. **Growth of Autonomous Systems**: The development of autonomous vehicles, drones, and robotics will continue to advance, transforming industries like transportation, logistics, and agriculture by improving safety, efficiency, and sustainability.\\n\\n7. **AI for Sustainability**: AI will play a crucial role in tackling environmental challenges, optimizing resource usage, improving climate models, and promoting sustainable practices, thereby contributing to environmental conservation efforts.\\n\\n8. **Quantum Computing and AI**: The synergy between AI and quantum computing could result in unprecedented computational capabilities, leading to significant breakthroughs in fields such as cryptography, complex simulations, and material science.\\n\\n9. **Creative Applications**: AI will increasingly contribute to creative industries, aiding in the production of art, music, and literature, and providing innovative tools and mediums for artistic exploration.\\n\\n10. **Focus on Explainability**: As AI systems become more integral to decision-making, the demand for explainable AI will grow. Developing AI that can clearly articulate its decision-making processes will be crucial for building trust and ensuring accountability.\\n\\nWhile the future of AI offers immense potential, it also poses challenges—including ethical considerations, privacy issues, and potential job displacement. Navigating these challenges will require careful thought, regulation, and collaboration across various stakeholders to ensure that AI benefits society as a whole.\",\n", + " \"refusal\": null,\n", + " \"role\": \"assistant\",\n", + " \"function_call\": null,\n", + " \"tool_calls\": [\n", + " {\n", + " \"id\": \"call_hCAzGLjdWGTBMVbJDi3ZYs2Z\",\n", + " \"function\": {\n", + " \"arguments\": \"{\\\"file_path\\\":\\\"123.txt\\\"}\",\n", + " \"name\": \"get_file_contents\",\n", + " \"parsed_arguments\": {\n", + " \"file_path\": \"123.txt\"\n", + " }\n", + " },\n", + " \"type\": \"function\"\n", + " }\n", + " ],\n", + " \"parsed\": null\n", + " }\n", + " }\n", + " ],\n", + " \"created\": 1730923586,\n", + " \"model\": \"gpt-4o-2024-08-06\",\n", + " \"object\": \"chat.completion\",\n", + " \"service_tier\": null,\n", + " \"system_fingerprint\": \"fp_d54531d9eb\",\n", + " \"usage\": {\n", + " \"completion_tokens\": 17,\n", + " \"prompt_tokens\": 135,\n", + " \"total_tokens\": 152,\n", + " \"completion_tokens_details\": null,\n", + " \"prompt_tokens_details\": null\n", + " }\n", + " },\n", + " \"tool_completion_args\": {\n", + " \"model\": \"gpt-4o\",\n", + " \"messages\": [\n", + " {\n", + " \"role\": \"system\",\n", + " \"content\": \"You are a helpful assistant.\"\n", + " },\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"Hi, my name is Paul.\"\n", + " },\n", + " {\n", + " \"role\": \"assistant\",\n", + " \"content\": \"Hello Paul! How can I assist you today?\"\n", + " },\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"Please tell me what's in file 123.txt.\"\n", + " },\n", + " {\n", + " \"role\": \"assistant\",\n", + " \"tool_calls\": [\n", + " {\n", + " \"id\": \"call_hCAzGLjdWGTBMVbJDi3ZYs2Z\",\n", + " \"function\": {\n", + " \"arguments\": \"{\\\"file_path\\\":\\\"123.txt\\\"}\",\n", + " \"name\": \"get_file_contents\",\n", + " \"parsed_arguments\": {\n", + " \"file_path\": \"123.txt\"\n", + " }\n", + " },\n", + " \"type\": \"function\"\n", + " }\n", + " ]\n", + " },\n", + " {\n", + " \"role\": \"tool\",\n", + " \"content\": \"The purpose of life is to be happy.\",\n", + " \"tool_call_id\": \"call_hCAzGLjdWGTBMVbJDi3ZYs2Z\"\n", + " }\n", + " ],\n", + " \"response_format\": {\n", + " \"type\": \"text\"\n", + " }\n", + " }\n", + " }\n", + "}\n" + ] + } + ], + "source": [ + "from chat_driver import ChatDriver, ChatDriverConfig\n", + "from context import Context\n", + "\n", + "# When an chat driver is created, it will automatically create a context with a\n", + "# session_id. Or, if you want to use a specific session_id, you can pass it as\n", + "# an argument. This is useful for scoping this chat driver instance to an\n", + "# external identifier.\n", + "context = Context(\"simple-id-1000\")\n", + "\n", + "instructions = \"You are a famous computer scientist. You are giving a talk at a conference. You are talking about the future of AI and how it will change the world. You are asked a questions by audience members.\"\n", + "\n", + "chat_driver = ChatDriver(\n", + " ChatDriverConfig(\n", + " openai_client=async_client,\n", + " model=model,\n", + " instructions=instructions,\n", + " context=context,\n", + " ),\n", + ")\n", + "\n", + "message_event = await chat_driver.respond(\"What is the future of AI?\")\n", + "print(message_event.model_dump_json(indent=2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### You can tell the chat driver to always return JSON\n", + "\n", + "Note: You MUST include the word \"JSON\" somewhere in your instructions. This is an OpenAI requirement for JSON return. However, note that a ChatDriver response method only returns string responses in its returned `MessageEvent` since these events are intended to be used in chat scenarios. If you want to transform it into an actual JSON object, you'll need to `json.loads(response.message)` it yourself." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{ \"thoughts\": \"The future of AI is a topic filled with both excitement and caution, as it holds the potential for transformative impacts across various facets of society.\", \"answer\": \"The future of AI is likely to involve increased integration into everyday life, with advancements in areas such as natural language processing, computer vision, and data analysis. AI is set to enhance fields like healthcare through predictive diagnostics, personalized medicine, and robotic surgery. In transportation, autonomous vehicles will likely become more common. AI will also improve efficiencies in industries like manufacturing and logistics. However, this future will also require addressing ethical considerations, data privacy concerns, and ensuring that AI technologies are accessible and beneficial for all members of society. A key focus will be on developing fair and unbiased AI systems, and creating governance frameworks that promote responsible AI development and usage.\" }\n", + "{\n", + " \"thoughts\": \"The future of AI is a topic filled with both excitement and caution, as it holds the potential for transformative impacts across various facets of society.\",\n", + " \"answer\": \"The future of AI is likely to involve increased integration into everyday life, with advancements in areas such as natural language processing, computer vision, and data analysis. AI is set to enhance fields like healthcare through predictive diagnostics, personalized medicine, and robotic surgery. In transportation, autonomous vehicles will likely become more common. AI will also improve efficiencies in industries like manufacturing and logistics. However, this future will also require addressing ethical considerations, data privacy concerns, and ensuring that AI technologies are accessible and beneficial for all members of society. A key focus will be on developing fair and unbiased AI systems, and creating governance frameworks that promote responsible AI development and usage.\"\n", + "}\n" + ] + } + ], + "source": [ + "\n", + "from chat_driver import ChatDriver, JSON_OBJECT_RESPONSE_FORMAT, ChatDriverConfig\n", + "from context import Context\n", + "\n", + "context = Context(\"conversation-id-1002\")\n", + "instructions = 'You are a famous computer scientist. You are giving a talk at a conference. You are talking about the future of AI and how it will change the world. You are asked a questions by audience members and return your answer as valid json, like this: { \"thoughts\": , \"answer\": }.'\n", + "\n", + "chat_driver = ChatDriver(\n", + " ChatDriverConfig(\n", + " openai_client=async_client,\n", + " model=model,\n", + " instructions=instructions,\n", + " context=context,\n", + " ),\n", + ")\n", + "\n", + "message_event = await chat_driver.respond(\"What is the future of AI?\", response_format=JSON_OBJECT_RESPONSE_FORMAT)\n", + "print(message_event.message)\n", + "\n", + "print(json.dumps(json.loads(message_event.message or \"\"), indent=2))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Chat drivers can return structured responses\n", + "\n", + "Just give it a class that inherits from Pydantic BaseModel and it will return your response in that structure. Most the time, if you want this kind of thing, you probably don't want a Chat Driver. Just use the OpenAI client with the helpers above. However, in the rare case that you want to actually use the structured output to guarantee the response from the model, this is here for you. You'll need to marshal the object yourself." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\"thoughts\":\"AI is rapidly advancing and its future holds great potential and considerable responsibility. As AI technologies become more integrated into society, we will see transformations across various sectors, including healthcare, transportation, education, and manufacturing. However, these advancements also come with ethical considerations and the need for responsible development.\",\"answer\":\"The future of AI is both exciting and complex. We will likely see AI becoming more autonomous, improving its ability to understand and interpret nuanced human interactions, and solving complex problems in ways that were previously unimaginable. In healthcare, AI could lead to personalized medicine and better diagnostic tools. In transportation, we'll see more autonomous vehicles that could reshape our cities and daily commutes. However, with these advancements comes the responsibility to address ethical concerns such as privacy, security, and fairness. It's crucial that as AI capabilities grow, we also develop frameworks to guide its ethical use and ensure that its benefits are distributed equitably across society.\"}\n", + "{\n", + " \"thoughts\": \"AI is rapidly advancing and its future holds great potential and considerable responsibility. As AI technologies become more integrated into society, we will see transformations across various sectors, including healthcare, transportation, education, and manufacturing. However, these advancements also come with ethical considerations and the need for responsible development.\",\n", + " \"answer\": \"The future of AI is both exciting and complex. We will likely see AI becoming more autonomous, improving its ability to understand and interpret nuanced human interactions, and solving complex problems in ways that were previously unimaginable. In healthcare, AI could lead to personalized medicine and better diagnostic tools. In transportation, we'll see more autonomous vehicles that could reshape our cities and daily commutes. However, with these advancements comes the responsibility to address ethical concerns such as privacy, security, and fairness. It's crucial that as AI capabilities grow, we also develop frameworks to guide its ethical use and ensure that its benefits are distributed equitably across society.\"\n", + "}\n" + ] + } + ], + "source": [ + "# Simple chat driver w/ structured response\n", + "\n", + "from typing import cast\n", + "from chat_driver import ChatDriver, ChatDriverConfig, LocalMessageHistoryProvider\n", + "from context import Context\n", + "from pydantic import BaseModel\n", + "\n", + "context = Context(\"structured-1000\")\n", + "\n", + "instructions = 'You are a famous computer scientist. You are giving a talk at a conference. You are talking about the future of AI and how it will change the world. You are asked a questions by audience members and return a thoughtful response.'\n", + "\n", + "class ThoughtfulResponse(BaseModel):\n", + " \"\"\"A thoughtful response to a question.\"\"\"\n", + " thoughts: str\n", + " answer: str\n", + "\n", + "chat_driver = ChatDriver(\n", + " ChatDriverConfig(\n", + " openai_client=async_client,\n", + " model=model,\n", + " instructions=instructions,\n", + " context=context,\n", + " ),\n", + ")\n", + "\n", + "# Let's clear the data from previous runs.\n", + "message_provider = cast(LocalMessageHistoryProvider, chat_driver.message_provider)\n", + "message_provider.delete_all()\n", + "\n", + "message_event = await chat_driver.respond(\"What is the future of AI?\", response_format=ThoughtfulResponse)\n", + "\n", + "# As always, the event will come back with a string message.\n", + "print(message_event.message)\n", + "\n", + "# If you really want to, you can turn the JSON string back into a Pydantic model.\n", + "thoughtful_response = ThoughtfulResponse(**json.loads(message_event.message or \"\"))\n", + "print(thoughtful_response.model_dump_json(indent=2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### You can register functions to chat drivers\n", + "\n", + "Chat drivers will use any functions you give it as both OpenAI tool calls, and as commands.\n", + "\n", + "With each response call, you can specify what type of response you want to have... string, dictionary, or Pydantic model." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "conversation-id-1002\n", + "\n", + "Hello Paul! How can I assist you today?\n", + "\n", + "Commands:\n", + "help(): Return this help message.\n", + "erase(name: str): Erases a stored value.\n", + "json_thing(): Return json.\n", + "get_weather(input: Input): Return the weather.\n", + "echo(text: str): Return the text.\n", + "get_file_contents(file_path: str): Return the contents of a file.\n", + "\n", + "Args:\n", + "- file_path: The path to the file.\n", + "\n", + "conversation-id-1002: Echo this.\n", + "\n", + "The content of \"123.txt\" is: \"The purpose of life is to be happy.\"\n", + "\n", + "{\"description\":\"Sunny\",\"cloud_cover\":0.2,\"temp_c\":25.0,\"temp_f\":77.0}\n" + ] + } + ], + "source": [ + "from typing import Any, cast\n", + "from chat_driver import ChatDriver, ChatDriverConfig\n", + "from context import Context, ContextProtocol\n", + "from chat_driver import LocalMessageHistoryProvider\n", + "from pydantic import BaseModel, Field\n", + "\n", + "\n", + "# When an chat driver is created, it will automatically create a context with a\n", + "# session_id. Or, if you want to use a specific session_id, you can pass it as\n", + "# an argument. This is useful for scoping this chat driver instance to an\n", + "# external identifier.\n", + "context = Context(\"conversation-id-1002\")\n", + "\n", + "\n", + "# Define tool functions for the chat driver. All functions used by the chat driver\n", + "# require a session_id as the first argument.\n", + "def get_file_contents(context: Context, file_path: str) -> str:\n", + " \"\"\"\n", + " Return the contents of a file.\n", + "\n", + " Args:\n", + " - file_path: The path to the file.\n", + " \"\"\"\n", + " return \"The purpose of life is to be happy.\"\n", + "\n", + "\n", + "def erase(context: Context, name: str) -> str:\n", + " \"\"\"Erases a stored value.\"\"\"\n", + " return f\"{context.session_id}: {name} erased\"\n", + "\n", + "def json_thing(context: Context) -> dict[str, Any]:\n", + " \"\"\"Return json.\"\"\"\n", + " return {\"key\": \"value\"}\n", + "\n", + "class Input(BaseModel):\n", + " zipcode: str\n", + "\n", + "class Weather(BaseModel):\n", + " description: str = Field(description=\"The weather description.\")\n", + " cloud_cover: float\n", + " temp_c: float\n", + " temp_f: float\n", + "\n", + "def get_weather(context: Context, input: Input) -> Weather:\n", + " \"\"\"Return the weather.\"\"\"\n", + " return Weather(description=\"Sunny\", cloud_cover=0.2, temp_c=25.0, temp_f=77.0)\n", + "\n", + "# Define the chat driver.\n", + "instructions = \"You are a helpful assistant.\"\n", + "\n", + "# Define the conversation so far (optional).\n", + "# messages: List[ChatCompletionMessageParam] = []\n", + "# localMessageHistoryConfig = LocalMessageHistoryProviderConfig(f\"./data/{context.session_id}\", messages)\n", + "# message_provider = LocalMessageHistoryProvider(localMessageHistoryConfig)\n", + "\n", + "chat_driver = ChatDriver(\n", + " ChatDriverConfig(\n", + " openai_client=async_client,\n", + " model=model,\n", + " instructions=instructions,\n", + " context=context,\n", + " # message_provider=message_provider,\n", + " commands=[erase, json_thing, get_weather], # Commands can be registered when instantiating the chat driver.\n", + " functions=[erase, json_thing, get_weather], # Functions can be registered when instantiating the chat driver.\n", + " ),\n", + ")\n", + "\n", + "# Let's clear the data from previous runs.\n", + "message_provider = cast(LocalMessageHistoryProvider, chat_driver.message_provider)\n", + "message_provider.delete_all()\n", + "\n", + "\n", + "# You can also use the `register_function` decorator to register a function.\n", + "# Remember, all functions used by the chat driver require a session_id as the\n", + "# first argument.\n", + "@chat_driver.register_function_and_command\n", + "def echo(context: ContextProtocol, text: str) -> str:\n", + " \"\"\"Return the text.\"\"\"\n", + " return f\"{context.session_id}: {text}\"\n", + "\n", + "\n", + "# You can also register functions manually.\n", + "chat_driver.register_function_and_command(get_file_contents)\n", + "\n", + "# Ok. Let's see if we got one.\n", + "print(chat_driver.context.session_id)\n", + "\n", + "# Let's see if the agent can respond.\n", + "message_event = await chat_driver.respond(\"Hi, my name is Paul.\")\n", + "print()\n", + "print(message_event.message)\n", + "\n", + "# Help command (shows command available).\n", + "message_event = await chat_driver.respond(\"/help\")\n", + "print()\n", + "print(message_event.message)\n", + "\n", + "# We can run any function or command directly.\n", + "message_event = await chat_driver.functions.echo(\"Echo this.\")\n", + "print()\n", + "print(message_event)\n", + "\n", + "# Let's see if the chat driver has the ability to run it's own registered function.\n", + "message_event = await chat_driver.respond(\"Please tell me what's in file 123.txt.\")\n", + "print()\n", + "print(message_event.message)\n", + "\n", + "# Stuctured output.\n", + "message_event = await chat_driver.respond(\"What is the weather in 90210?\", response_format=Weather)\n", + "print()\n", + "print(message_event.message)\n", + "\n", + "# Let's see the full response event.\n", + "# print()\n", + "# print(response.to_json())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Chat with a chat driver" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "User: /echo(\"hello world\")\n", + "Assistant: hello world\n" + ] + } + ], + "source": [ + "from chat_driver import ChatDriverConfig, ChatDriver\n", + "from context import Context\n", + "\n", + "context = Context(\"conversation-id-1006\")\n", + "\n", + "\n", + "def get_file_contents(context: Context, file_path: str) -> str:\n", + " \"\"\"Returns the contents of a file.\"\"\"\n", + " return \"The purpose of life is to be happy.\"\n", + "\n", + "\n", + "def erase(context: Context, name: str) -> str:\n", + " \"\"\"Erases a stored value.\"\"\"\n", + " return f\"{context.session_id}: {name} erased\"\n", + "\n", + "\n", + "def echo(context: Context, value: Any) -> str: # noqa: F811\n", + " \"\"\"Echos a value as a string.\"\"\"\n", + " match value:\n", + " case str():\n", + " return value\n", + " case list():\n", + " return \", \".join(map(str, value))\n", + " case dict():\n", + " return json.dumps(value)\n", + " case int() | bool() | float():\n", + " return str(value)\n", + " case _:\n", + " return str(value)\n", + "\n", + "\n", + "functions = [get_file_contents, erase, echo]\n", + "\n", + "# Define the chat driver.\n", + "chat_driver_config = ChatDriverConfig(\n", + " openai_client=async_client,\n", + " model=model,\n", + " instructions=\"You are an assistant that has access to a sand-boxed Posix shell.\",\n", + " context=context,\n", + " commands=functions,\n", + " functions=functions,\n", + ")\n", + "\n", + "chat_driver = ChatDriver(chat_driver_config)\n", + "\n", + "# Note: Look in the .data directory for the logs, message history, and other data.\n", + "\n", + "# Chat with the skill.\n", + "while True:\n", + " message = input(\"User: \")\n", + " if message == \"\":\n", + " break\n", + " print(f\"User: {message}\", flush=True)\n", + " message_event = await chat_driver.respond(message)\n", + " if message_event.metadata.get(\"error\"):\n", + " print(f\"Error: {message_event.metadata.get('error')}\")\n", + " print(message_event.to_json())\n", + " continue\n", + " # You can print the entire message event! \n", + " # print(response.to_json())\n", + " print(f\"Assistant: {message_event.message}\", flush=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Chat Driver with an Assistant Drive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from io import BytesIO\n", + "from typing import Any, BinaryIO\n", + "from chat_driver import ChatDriverConfig, ChatDriver, ChatDriverConfig\n", + "from context import Context\n", + "from assistant_drive import Drive, DriveConfig, IfDriveFileExistsBehavior \n", + "\n", + "session_id = \"conversation-id-1001\"\n", + "\n", + "context = Context(session_id)\n", + "\n", + "def get_drive_from_context(context):\n", + " return Drive(DriveConfig(root=f\".data/drive/{context.session_id}\"))\n", + "\n", + "def write_file_contents(context: Context, file_path: str, contents: str) -> str:\n", + " \"\"\"Writes the contents to a file.\"\"\"\n", + " drive = get_drive_from_context(context)\n", + " content_bytes: BinaryIO = BytesIO(contents.encode(\"utf-8\"))\n", + " drive.write(content_bytes, file_path, if_exists=IfDriveFileExistsBehavior.OVERWRITE)\n", + " return f\"{file_path} updated.\"\n", + "\n", + "def read_file_contents(context: Context, file_path: str) -> str:\n", + " \"\"\"Returns the contents of a file.\"\"\"\n", + " drive = get_drive_from_context(context)\n", + " with drive.open_file(file_path) as file:\n", + " return file.read().decode(\"utf-8\")\n", + "\n", + "functions = [write_file_contents, read_file_contents]\n", + "\n", + "# Define the chat driver.\n", + "chat_driver_config = ChatDriverConfig(\n", + " openai_client=async_client,\n", + " model=model,\n", + " instructions=\"You are an assistant that has access to a sand-boxed Posix shell.\",\n", + " context=context,\n", + " commands=functions,\n", + " functions=functions,\n", + ")\n", + "\n", + "chat_driver = ChatDriver(chat_driver_config)\n", + "\n", + "# Note: Look in the .data directory for the logs, message history, and other data.\n", + "\n", + "# Chat with the skill.\n", + "while True:\n", + " message = input(\"User: \")\n", + " if message == \"\":\n", + " break\n", + " print(f\"User: {message}\", flush=True)\n", + " message_event = await chat_driver.respond(message)\n", + " # You can print the entire response event! \n", + " # print(response.to_json())\n", + " print(f\"Assistant: {message_event.message}\", flush=True)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.10" } - ], - "source": [ - "from typing import Any\n", - "from chat_driver import ChatDriverConfig, ChatDriver\n", - "from context import Context\n", - "\n", - "context = Context(\"conversation-id-1001\")\n", - "\n", - "\n", - "def get_file_contents(context: Context, file_path: str) -> str:\n", - " \"\"\"Returns the contents of a file.\"\"\"\n", - " return \"The purpose of life is to be happy.\"\n", - "\n", - "\n", - "def erase(context: Context, name: str) -> str:\n", - " \"\"\"Erases a stored value.\"\"\"\n", - " return f\"{context.session_id}: {name} erased\"\n", - "\n", - "\n", - "def echo(context: Context, value: Any) -> str: # noqa: F811\n", - " \"\"\"Echos a value as a string.\"\"\"\n", - " match value:\n", - " case str():\n", - " return value\n", - " case list():\n", - " return \", \".join(map(str, value))\n", - " case dict():\n", - " return json.dumps(value)\n", - " case int() | bool() | float():\n", - " return str(value)\n", - " case _:\n", - " return str(value)\n", - "\n", - "\n", - "functions = [get_file_contents, erase, echo]\n", - "\n", - "# Define the chat driver.\n", - "chat_driver_config = ChatDriverConfig(\n", - " openai_client=async_client,\n", - " model=model,\n", - " instructions=\"You are an assistant that has access to a sand-boxed Posix shell.\",\n", - " context=context,\n", - " commands=functions,\n", - " functions=functions,\n", - ")\n", - "\n", - "chat_driver = ChatDriver(chat_driver_config)\n", - "\n", - "# Note: Look in the .data directory for the logs, message history, and other data.\n", - "\n", - "# Chat with the skill.\n", - "while True:\n", - " message = input(\"User: \")\n", - " if message == \"\":\n", - " break\n", - " print(f\"User: {message}\", flush=True)\n", - " response = await chat_driver.respond(message)\n", - " # You can print the entire response event! \n", - " # print(response.to_json())\n", - " print(f\"Assistant: {response.message}\", flush=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Chat Driver with an Assistant Drive" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from io import BytesIO\n", - "from typing import Any, BinaryIO\n", - "from chat_driver import ChatDriverConfig, ChatDriver, ChatDriverConfig\n", - "from context import Context\n", - "from assistant_drive import Drive, DriveConfig, IfDriveFileExistsBehavior \n", - "\n", - "session_id = \"conversation-id-1001\"\n", - "\n", - "context = Context(session_id)\n", - "\n", - "def get_drive_from_context(context):\n", - " return Drive(DriveConfig(root=f\".data/drive/{context.session_id}\"))\n", - "\n", - "def write_file_contents(context: Context, file_path: str, contents: str) -> str:\n", - " \"\"\"Writes the contents to a file.\"\"\"\n", - " drive = get_drive_from_context(context)\n", - " content_bytes: BinaryIO = BytesIO(contents.encode(\"utf-8\"))\n", - " drive.write(content_bytes, file_path, if_exists=IfDriveFileExistsBehavior.OVERWRITE)\n", - " return f\"{file_path} updated.\"\n", - "\n", - "def read_file_contents(context: Context, file_path: str) -> str:\n", - " \"\"\"Returns the contents of a file.\"\"\"\n", - " drive = get_drive_from_context(context)\n", - " with drive.open_file(file_path) as file:\n", - " return file.read().decode(\"utf-8\")\n", - "\n", - "functions = [write_file_contents, read_file_contents]\n", - "\n", - "# Define the chat driver.\n", - "chat_driver_config = ChatDriverConfig(\n", - " openai_client=async_client,\n", - " model=model,\n", - " instructions=\"You are an assistant that has access to a sand-boxed Posix shell.\",\n", - " context=context,\n", - " commands=functions,\n", - " functions=functions,\n", - ")\n", - "\n", - "chat_driver = ChatDriver(chat_driver_config)\n", - "\n", - "# Note: Look in the .data directory for the logs, message history, and other data.\n", - "\n", - "# Chat with the skill.\n", - "while True:\n", - " message = input(\"User: \")\n", - " if message == \"\":\n", - " break\n", - " print(f\"User: {message}\", flush=True)\n", - " response = await chat_driver.respond(message)\n", - " # You can print the entire response event! \n", - " # print(response.to_json())\n", - " print(f\"Assistant: {response.message}\", flush=True)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": ".venv", - "language": "python", - "name": "python3" }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.10" - } - }, - "nbformat": 4, - "nbformat_minor": 2 + "nbformat": 4, + "nbformat_minor": 2 } From ed22a399c529c27a1ded53a91ab8b74407ae492f Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Tue, 5 Nov 2024 23:34:16 +0000 Subject: [PATCH 06/14] WIP: Skills (not working) --- assistants/prospector-assistant/uv.lock | 2 + .../assistant/assistant_registry.py | 94 ++ .../assistant/skill_assistant.py | 82 +- .../assistant/skill_controller.py | 170 --- .../assistant/skill_event_mapper.py | 70 ++ assistants/skill-assistant/pyproject.toml | 21 +- assistants/skill-assistant/uv.lock | 27 +- .../document_skill/chat_drivers/__init__.py | 11 + .../chat_drivers/draft_content.py | 78 ++ .../chat_drivers/draft_outline.py | 56 + .../get_user_feedback_for_outline_decision.py | 75 ++ .../get_user_feedback_for_page_decision.py | 75 ++ .../document_skill/document_skill.py | 414 ++------ .../skills/skills/document-skill/uv.lock | 2 + .../form_filler_skill/agenda.py | 24 + .../form_filler_skill/artifact.py | 463 +++++++++ .../form_filler_skill/base_model_llm.py | 53 + .../chat_drivers/extract_form_fields.py | 74 ++ .../chat_drivers/final_update.py | 91 ++ .../chat_drivers/fix_agenda_error.py | 57 + .../chat_drivers/fix_artifact_error.py | 67 ++ .../chat_drivers/gc_update_agenda.py | 247 ----- .../chat_drivers/unneeded/choose_action.py | 248 +++++ .../unneeded/choose_action_template.py | 52 + .../unneeded/execute_reasoning.py | 61 ++ .../chat_drivers/update_agenda.py | 140 +++ .../chat_drivers/update_agenda_template.py | 31 + .../chat_drivers/update_artifact.py | 219 ++++ .../chat_drivers/update_artifact_template.py | 32 + .../form_filler_skill/definition.py | 14 + .../guided_conversation/agenda.py | 200 +--- .../guided_conversation/base_model_llm.py | 34 +- .../chat_drivers/gc_final_update.py | 0 .../chat_drivers/gc_fix_agenda_error.py | 9 +- .../chat_drivers/gc_update_agenda.py | 250 +++++ .../chat_drivers/gc_update_artifact.py | 0 .../conversation_helpers.py | 1 + .../guided_conversation/resources.py | 207 ++-- .../guided_conversation_skill.py | 76 +- .../form_filler_skill/message.py | 61 ++ .../form_filler_skill/resources.py | 275 +++++ .../skills/form-filler-skill/pyproject.toml | 4 + .../skills/skills/form-filler-skill/uv.lock | 970 ++++++++++++++++++ .../posix-skill/posix_skill/posix_skill.py | 6 +- .../python/skills/skills/posix-skill/uv.lock | 2 + .../skills/skills/prospector-skill/uv.lock | 2 + .../skills/skills/skill-template/uv.lock | 2 + semantic-workbench.code-workspace | 8 + 48 files changed, 4064 insertions(+), 1093 deletions(-) create mode 100644 assistants/skill-assistant/assistant/assistant_registry.py delete mode 100644 assistants/skill-assistant/assistant/skill_controller.py create mode 100644 assistants/skill-assistant/assistant/skill_event_mapper.py create mode 100644 libraries/python/skills/skills/document-skill/document_skill/chat_drivers/__init__.py create mode 100644 libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_content.py create mode 100644 libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_outline.py create mode 100644 libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_outline_decision.py create mode 100644 libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_page_decision.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/agenda.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/artifact.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/base_model_llm.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/extract_form_fields.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/final_update.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_agenda_error.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_artifact_error.py delete mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_update_agenda.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action_template.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/execute_reasoning.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_agenda_template.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact_template.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/definition.py rename libraries/python/skills/skills/form-filler-skill/form_filler_skill/{ => guided_conversation}/chat_drivers/gc_final_update.py (100%) rename libraries/python/skills/skills/form-filler-skill/form_filler_skill/{ => guided_conversation}/chat_drivers/gc_fix_agenda_error.py (95%) create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_agenda.py rename libraries/python/skills/skills/form-filler-skill/form_filler_skill/{ => guided_conversation}/chat_drivers/gc_update_artifact.py (100%) create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/message.py create mode 100644 libraries/python/skills/skills/form-filler-skill/form_filler_skill/resources.py diff --git a/assistants/prospector-assistant/uv.lock b/assistants/prospector-assistant/uv.lock index 7bf660ca..f964fc01 100644 --- a/assistants/prospector-assistant/uv.lock +++ b/assistants/prospector-assistant/uv.lock @@ -397,6 +397,7 @@ dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, + { name = "python-liquid" }, { name = "requests" }, { name = "tiktoken" }, ] @@ -412,6 +413,7 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, + { name = "python-liquid", specifier = ">=1.12.1" }, { name = "requests", specifier = ">=2.32.0" }, { name = "tiktoken", specifier = ">=0.7.0" }, ] diff --git a/assistants/skill-assistant/assistant/assistant_registry.py b/assistants/skill-assistant/assistant/assistant_registry.py new file mode 100644 index 00000000..5285da1f --- /dev/null +++ b/assistants/skill-assistant/assistant/assistant_registry.py @@ -0,0 +1,94 @@ +import asyncio +import logging +from pathlib import Path +from typing import List + +from chat_driver import ChatDriverConfig +from skill_library import Assistant, Skill + +from assistant.skill_event_mapper import SkillEventMapperProtocol + +logger = logging.getLogger(__name__) + + +# TODO: Put this registry in the skill library. +class AssistantRegistry: + """ + This class handles the creation and management of skill assistant instances + for this service. Each conversation has its own assistant and we start each + assistant in it's own thread so that all events are able to be + asynchronously passed on to the Semantic Workbench. + """ + + def __init__(self) -> None: + self.assistants: dict[str, Assistant] = {} + self.tasks: set[asyncio.Task] = set() + + async def get_or_create_assistant( + self, + session_id: str, + event_mapper: SkillEventMapperProtocol, + chat_driver_config: ChatDriverConfig, + skills: List[Skill] = [], + ) -> Assistant: + """ + Get or create an assistant for the given conversation context. + """ + assistant = self.get_assistant(session_id) + if not assistant: + assistant = await self.register_assistant( + session_id, event_mapper, chat_driver_config, skills + ) + return assistant + + def get_assistant( + self, + session_id: str, + ) -> Assistant | None: + if session_id in self.assistants: + return self.assistants[session_id] + return None + + async def register_assistant( + self, + session_id: str, + event_mapper: SkillEventMapperProtocol, + chat_driver_config: ChatDriverConfig, + skills: List[Skill] = [], + ) -> Assistant: + """ + Define the skill assistant that you want to have backing this assistant + service. You can configure the assistant instructions and which skills + to include here. + """ + + # Create the assistant. + assistant = Assistant( + name="Assistant", + chat_driver_config=chat_driver_config, + session_id=session_id, + metadrive_root=Path(".data") / session_id / ".assistant", + ) + assistant.register_skills(skills) + + # Assistant event consumer. + async def subscribe() -> None: + """Event consumer for the assistant.""" + async for skill_event in assistant.events: + try: + await event_mapper.map(skill_event) + except Exception: + logging.exception("Exception in skill assistant event handling") + await assistant.wait() + + # Register the assistant + self.assistants[session_id] = assistant + + # Start an event consumer task and save a reference. + task = asyncio.create_task(subscribe()) + self.tasks.add(task) + + # Remove the task from the set when it completes. + task.add_done_callback(self.tasks.remove) + + return assistant diff --git a/assistants/skill-assistant/assistant/skill_assistant.py b/assistants/skill-assistant/assistant/skill_assistant.py index aa08e2a0..777a6998 100644 --- a/assistants/skill-assistant/assistant/skill_assistant.py +++ b/assistants/skill-assistant/assistant/skill_assistant.py @@ -8,8 +8,13 @@ # the skills library to create a skill-based assistant. import logging +from pathlib import Path +import openai_client +from chat_driver import ChatDriverConfig from content_safety.evaluators import CombinedContentSafetyEvaluator +from form_filler_skill import FormFillerSkill +from posix_skill import PosixSkill from semantic_workbench_api_model.workbench_model import ( ConversationEvent, ConversationMessage, @@ -25,8 +30,10 @@ ConversationContext, ) +from assistant.skill_event_mapper import SkillEventMapper + +from .assistant_registry import AssistantRegistry from .config import AssistantConfigModel -from .skill_controller import AssistantRegistry logger = logging.getLogger(__name__) @@ -139,36 +146,69 @@ async def on_conversation_created(context: ConversationContext) -> None: # Core response logic for handling messages (chat or command) in the conversation. async def respond_to_conversation( - context: ConversationContext, event: ConversationEvent, message: ConversationMessage + conversation_context: ConversationContext, + event: ConversationEvent, + message: ConversationMessage, ) -> None: """ Respond to a conversation message. """ - # TODO: pass metadata to the assistant for at least adding the content safety metadata to debug + # Get the assistant configuration. + config = await assistant_config.get(conversation_context.assistant) - # get the assistant configuration - config = await assistant_config.get(context.assistant) - - # TODO: pass metadata to the assistant for at least adding the content safety metadata to debug + # TODO: pass metadata to the assistant for at least adding the content safety metadata to debug. # metadata = {"debug": {"content_safety": event.data.get(content_safety.metadata_key, {})}} - # update the participant status to indicate the assistant is thinking - await context.update_participant_me(UpdateParticipant(status="thinking...")) + # Update the participant status to indicate the assistant is thinking. + await conversation_context.update_participant_me(UpdateParticipant(status="thinking...")) + + # Get an assistant from the skill library. + assistant = assistant_registry.get_assistant(conversation_context.id) + + # Create and register an assistant if necessary. + if not assistant: + try: + async_client = openai_client.create_client(config.service_config) + chat_driver_config = ChatDriverConfig( + openai_client=async_client, + model=config.chat_driver_config.openai_model, + instructions=config.chat_driver_config.instructions, + # context will be overwritten by the assistant when initialized. + ) + assistant = await assistant_registry.register_assistant( + conversation_context.id, + SkillEventMapper(conversation_context), + chat_driver_config, + [ + PosixSkill( + sandbox_dir=Path(".data") / conversation_context.id, + mount_dir="/mnt/data", + chat_driver_config=chat_driver_config, + ), + FormFillerSkill( + chat_driver_config=chat_driver_config, + ), + ], + ) + + except Exception as e: + logging.exception("exception in on_message_created") + await conversation_context.send_messages( + NewConversationMessage( + message_type=MessageType.note, + content=f"Unhandled error: {e}", + ) + ) + return + finally: + await conversation_context.update_participant_me(UpdateParticipant(status=None)) + try: - # replace the following with your own logic for processing a message created event - assistant = await assistant_registry.get_assistant( - context, - config.chat_driver_config, - config.service_config, - ) - if assistant: - await assistant.put_message(message.content) - else: - logging.error("Assistant not created") + await assistant.put_message(message.content) except Exception as e: logging.exception("exception in on_message_created") - await context.send_messages( + await conversation_context.send_messages( NewConversationMessage( message_type=MessageType.note, content=f"Unhandled error: {e}", @@ -176,4 +216,4 @@ async def respond_to_conversation( ) finally: # update the participant status to indicate the assistant is done thinking - await context.update_participant_me(UpdateParticipant(status=None)) + await conversation_context.update_participant_me(UpdateParticipant(status=None)) diff --git a/assistants/skill-assistant/assistant/skill_controller.py b/assistants/skill-assistant/assistant/skill_controller.py deleted file mode 100644 index 3189cb7e..00000000 --- a/assistants/skill-assistant/assistant/skill_controller.py +++ /dev/null @@ -1,170 +0,0 @@ -import asyncio -import logging -from pathlib import Path - -import openai_client -from chat_driver import ChatDriverConfig -from document_skill import DocumentSkill -from events import events as skill_events -from posix_skill import PosixSkill -from semantic_workbench_api_model.workbench_model import ( - MessageType, - NewConversationMessage, - UpdateParticipant, -) -from semantic_workbench_assistant.assistant_app import ( - ConversationContext, -) -from skill_library import Assistant - -from . import config - -logger = logging.getLogger(__name__) - - -async def _event_mapper( - conversation_context: ConversationContext, - skill_event: skill_events.EventProtocol, -) -> None: - """ - Maps events emitted by the skill assistant (from running actions or - routines) to message types understood by the Semantic Workbench. - """ - metadata = {"debug": skill_event.metadata} if skill_event.metadata else None - - match skill_event: - case skill_events.MessageEvent(): - await conversation_context.send_messages( - NewConversationMessage( - content=skill_event.message or "", - metadata=metadata, - ) - ) - - case skill_events.InformationEvent(): - if skill_event.message: - await conversation_context.send_messages( - NewConversationMessage( - content=f"Information event: {skill_event.message}", - message_type=MessageType.note, - metadata=metadata, - ), - ) - - case skill_events.ErrorEvent(): - await conversation_context.send_messages( - NewConversationMessage( - content=skill_event.message or "", - metadata=metadata, - ) - ) - - case skill_events.StatusUpdatedEvent(): - await conversation_context.update_participant_me(UpdateParticipant(status=skill_event.message)) - - case _: - logger.warning("Unhandled event: %s", skill_event) - - -class AssistantRegistry: - """ - This class handles the creation and management of skill assistant instances - for this service. Each conversation has its own assistant and we start each - assistant in it's own thread so that all events are able to be - asynchronously passed on to the Semantic Workbench. - - """ - - def __init__(self) -> None: - self.assistants: dict[str, Assistant] = {} - self.tasks: set[asyncio.Task] = set() - - async def get_assistant( - self, - conversation_context: ConversationContext, - chat_driver_config: config.ChatDriverConfig, - service_config: openai_client.ServiceConfig, - ) -> Assistant | None: - # If the assistant already exists, return it. - if conversation_context.id in self.assistants: - return self.assistants[conversation_context.id] - - # Create a new assistant. - assistant = await self.create_assistant(conversation_context, chat_driver_config, service_config) - if not assistant: - return - - async def subscribe() -> None: - """Event consumer for the assistant.""" - async for skill_event in assistant.events: - try: - await _event_mapper(conversation_context, skill_event) - except Exception: - logging.exception("Exception in skill assistant event handling") - await assistant.wait() - - # Register the assistant - self.assistants[conversation_context.id] = assistant - # Start an event consumer task and save a reference - task = asyncio.create_task(subscribe()) - self.tasks.add(task) - # Remove the task from the set when it completes - task.add_done_callback(self.tasks.remove) - - return assistant - - async def create_assistant( - self, - conversation_context: ConversationContext, - chat_driver_config: config.ChatDriverConfig, - service_config: openai_client.ServiceConfig, - ) -> Assistant | None: - """ - Define the skill assistant that you want to have backing this assistant - service. You can configure the assistant instructions and which skills - to include here. - """ - # Get an OpenAI client. - try: - async_client = openai_client.create_client(service_config) - except Exception as e: - logging.exception("Failed to create OpenAI client") - await conversation_context.send_messages( - NewConversationMessage(message_type=MessageType.note, content=f"Could not create an OpenAI client: {e}") - ) - return - - # Create the assistant. - assistant = Assistant( - name="Assistant", - chat_driver_config=ChatDriverConfig( - openai_client=async_client, - model=chat_driver_config.openai_model, - instructions=chat_driver_config.instructions, - ), - session_id=str(conversation_context.id), - ) - - # Define the skills this assistant should have. - posix_skill = PosixSkill( - context=assistant.run_context, - sandbox_dir=Path(".data"), - mount_dir="/mnt/data", - chat_driver_config=ChatDriverConfig( - openai_client=async_client, - model=chat_driver_config.openai_model, - ), - ) - - document_skill = DocumentSkill( - context=assistant.run_context, - chat_driver_config=ChatDriverConfig( - openai_client=async_client, - model=chat_driver_config.openai_model, - ), - ) - - # Register the skills with the assistant. - assistant.register_skills([posix_skill, document_skill]) - - return assistant diff --git a/assistants/skill-assistant/assistant/skill_event_mapper.py b/assistants/skill-assistant/assistant/skill_event_mapper.py new file mode 100644 index 00000000..bf273da7 --- /dev/null +++ b/assistants/skill-assistant/assistant/skill_event_mapper.py @@ -0,0 +1,70 @@ +import logging +from typing import Protocol + +from events import events as skill_events +from semantic_workbench_api_model.workbench_model import ( + MessageType, + NewConversationMessage, + UpdateParticipant, +) +from semantic_workbench_assistant.assistant_app import ( + ConversationContext, +) + +logger = logging.getLogger(__name__) + + +# TODO: Put this protocol in the skill library. +class SkillEventMapperProtocol(Protocol): + @staticmethod + async def map( + skill_event: skill_events.EventProtocol, + ) -> None: ... + + +class SkillEventMapper(SkillEventMapperProtocol): + def __init__(self, conversation_context: ConversationContext) -> None: + self.conversation_context = conversation_context + + async def map( + self, + skill_event: skill_events.EventProtocol, + ) -> None: + """ + Maps events emitted by the skill assistant (from running actions or + routines) to message types understood by the Semantic Workbench. + """ + metadata = {"debug": skill_event.metadata} if skill_event.metadata else None + + match skill_event: + case skill_events.MessageEvent(): + await self.conversation_context.send_messages( + NewConversationMessage( + content=skill_event.message or "", + metadata=metadata, + ) + ) + + case skill_events.InformationEvent(): + if skill_event.message: + await self.conversation_context.send_messages( + NewConversationMessage( + content=f"Information event: {skill_event.message}", + message_type=MessageType.note, + metadata=metadata, + ), + ) + + case skill_events.ErrorEvent(): + await self.conversation_context.send_messages( + NewConversationMessage( + content=skill_event.message or "", + metadata=metadata, + ) + ) + + case skill_events.StatusUpdatedEvent(): + await self.conversation_context.update_participant_me(UpdateParticipant(status=skill_event.message)) + + case _: + logger.warning("Unhandled event: %s", skill_event) diff --git a/assistants/skill-assistant/pyproject.toml b/assistants/skill-assistant/pyproject.toml index e9328917..7742b8ba 100644 --- a/assistants/skill-assistant/pyproject.toml +++ b/assistants/skill-assistant/pyproject.toml @@ -7,26 +7,29 @@ readme = "README.md" requires-python = ">=3.11" dependencies = [ "azure-ai-contentsafety>=1.0.0", - "azure-identity>=1.16.0", "azure-core[aio]>=1.30.0", - "openai>=1.3.9", - "semantic-workbench-assistant>=0.1.0", + "azure-identity>=1.16.0", "content-safety>=0.1.0", - "posix-skill>=0.1.0", - "document-skill>=0.1.0", + "context>=0.1.0", + # "document-skill>=0.1.0", + "form-filler-skill>=0.1.0", "openai-client>=0.1.0", + "openai>=1.3.9", + "posix-skill>=0.1.0", + "semantic-workbench-assistant>=0.1.0", ] [tool.uv] package = true [tool.uv.sources] -# If you copy this file to your project, you should verify the relative path to the following: -semantic-workbench-assistant = { path = "../../libraries/python/semantic-workbench-assistant", editable = true } content-safety = { path = "../../libraries/python/content-safety", editable = true } -posix-skill = { path = "../../libraries/python/skills/skills/posix-skill", editable = true } -document-skill = { path = "../../libraries/python/skills/skills/document-skill", editable = true } +context = { path = "../../libraries/python/context", editable = true } +# document-skill = { path = "../../libraries/python/skills/skills/document-skill", editable = true } +form-filler-skill = { path = "../../libraries/python/skills/skills/form-filler-skill", editable = true } openai-client = { path = "../../libraries/python/openai-client", editable = true } +posix-skill = { path = "../../libraries/python/skills/skills/posix-skill", editable = true } +semantic-workbench-assistant = { path = "../../libraries/python/semantic-workbench-assistant", editable = true } [build-system] requires = ["hatchling"] diff --git a/assistants/skill-assistant/uv.lock b/assistants/skill-assistant/uv.lock index bf45b297..86b8595d 100644 --- a/assistants/skill-assistant/uv.lock +++ b/assistants/skill-assistant/uv.lock @@ -131,7 +131,8 @@ dependencies = [ { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, { name = "content-safety" }, - { name = "document-skill" }, + { name = "context" }, + { name = "form-filler-skill" }, { name = "openai" }, { name = "openai-client" }, { name = "posix-skill" }, @@ -144,7 +145,8 @@ requires-dist = [ { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.16.0" }, { name = "content-safety", editable = "../../libraries/python/content-safety" }, - { name = "document-skill", editable = "../../libraries/python/skills/skills/document-skill" }, + { name = "context", editable = "../../libraries/python/context" }, + { name = "form-filler-skill", editable = "../../libraries/python/skills/skills/form-filler-skill" }, { name = "openai", specifier = ">=1.3.9" }, { name = "openai-client", editable = "../../libraries/python/openai-client" }, { name = "posix-skill", editable = "../../libraries/python/skills/skills/posix-skill" }, @@ -364,6 +366,7 @@ dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, + { name = "python-liquid" }, { name = "requests" }, { name = "tiktoken" }, ] @@ -379,6 +382,7 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, + { name = "python-liquid", specifier = ">=1.12.1" }, { name = "requests", specifier = ">=2.32.0" }, { name = "tiktoken", specifier = ">=0.7.0" }, ] @@ -584,6 +588,25 @@ standard = [ { name = "uvicorn", extra = ["standard"] }, ] +[[package]] +name = "form-filler-skill" +version = "0.1.0" +source = { editable = "../../libraries/python/skills/skills/form-filler-skill" } +dependencies = [ + { name = "chat-driver" }, + { name = "context" }, + { name = "events" }, + { name = "skill-library" }, +] + +[package.metadata] +requires-dist = [ + { name = "chat-driver", editable = "../../libraries/python/chat-driver" }, + { name = "context", editable = "../../libraries/python/context" }, + { name = "events", editable = "../../libraries/python/events" }, + { name = "skill-library", editable = "../../libraries/python/skills/skill-library" }, +] + [[package]] name = "frozenlist" version = "1.5.0" diff --git a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/__init__.py b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/__init__.py new file mode 100644 index 00000000..58a4b776 --- /dev/null +++ b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/__init__.py @@ -0,0 +1,11 @@ +from .draft_content import draft_content +from .draft_outline import draft_outline +from .get_user_feedback_for_outline_decision import get_user_feedback_for_outline_decision +from .get_user_feedback_for_page_decision import get_user_feedback_for_page_decision + +__all__ = [ + "draft_content", + "draft_outline", + "get_user_feedback_for_outline_decision", + "get_user_feedback_for_page_decision", +] diff --git a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_content.py b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_content.py new file mode 100644 index 00000000..5c6b39ad --- /dev/null +++ b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_content.py @@ -0,0 +1,78 @@ +from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider +from chat_driver.message_formatter import liquid_format +from openai import AsyncAzureOpenAI, AsyncOpenAI + +from ..document_skill import Outline, Paper + + +async def draft_content( + context: ContextProtocol, + open_ai_client: AsyncOpenAI | AsyncAzureOpenAI, + chat_history: str, + attachments: list, + outline_versions: list[Outline] = [], + paper_versions: list[Paper] = [], + user_feedback: str | None = None, + decision: str | None = None, +): + history = InMemoryMessageHistoryProvider(formatter=liquid_format) + + if decision == "[ITERATE]": + history.append_system_message( + ( + "Following the structure of the outline, iterate on the currently drafted page of the" + " document. It's more important to maintain an appropriately useful level of detail. " + " After this page is iterated upon, the system will follow up" + " and ask for the next page." + ) + ) + + else: + history.append_system_message( + ( + "Following the structure of the outline, create the content for the next (or first) page of the" + " document - don't try to create the entire document in one pass nor wrap it up too quickly, it will be a" + " multi-page document so just create the next page. It's more important to maintain" + " an appropriately useful level of detail. After this page is generated, the system will follow up" + " and ask for the next page. If you have already generated all the pages for the" + " document as defined in the outline, return empty content." + ) + ) + + history.append_system_message("{{chat_history}}", {"chat_history": chat_history}) + + for item in attachments: + history.append_system_message( + "{{item.filename}}{{item.content}}", + {"item": item}, + ) + + if outline_versions: + last_outline = outline_versions[-1] + history.append_system_message( + "{{last_outline}}", {"last_outline": last_outline} + ) + + if paper_versions: + if decision == "[ITERATE]" and user_feedback: + content = paper_versions[-1].contents[-1].content + history.append_system_message("{{content}}", {"content": content}) + history.append_system_message( + "{{user_feedback}}", {"user_feedback": user_feedback} + ) + else: + full_content = "" + for content in paper_versions[-1].contents: + full_content += content.content + history.append_system_message("{{content}}", {"content": content}) + + config = ChatDriverConfig( + context=context, + openai_client=open_ai_client, + model="gpt-3.5-turbo", + message_provider=history, + ) + + chat_driver = ChatDriver(config) + return await chat_driver.respond() diff --git a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_outline.py b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_outline.py new file mode 100644 index 00000000..96d7a7c5 --- /dev/null +++ b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_outline.py @@ -0,0 +1,56 @@ +from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider +from chat_driver.message_formatter import liquid_format +from openai import AsyncAzureOpenAI, AsyncOpenAI + +from ..document_skill import Outline + + +async def draft_outline( + context: ContextProtocol, + open_ai_client: AsyncOpenAI | AsyncAzureOpenAI, + chat_history: str, + attachments: list, + outline_versions: list[Outline] = [], + user_feedback: str | None = None, +): + history = InMemoryMessageHistoryProvider(formatter=liquid_format) + + history.append_system_message( + ( + "Generate an outline for the document, including title. The outline should include the key points that will" + " be covered in the document. Consider the attachments, the rationale for why they were uploaded, and the" + " conversation that has taken place. The outline should be a hierarchical structure with multiple levels of" + " detail, and it should be clear and easy to understand. The outline should be generated in a way that is" + " consistent with the document that will be generated from it." + ) + ) + + history.append_system_message("{{chat_history}}", {"chat_history": chat_history}) + + for item in attachments: + history.append_system_message( + "{{item.filename}}{{item.content}}", + {"item": item}, + ) + + if len(outline_versions): + last_outline = outline_versions[-1] + history.append_system_message( + "{{last_outline}}", {"last_outline": last_outline} + ) + + if user_feedback is not None: + history.append_system_message( + "{{user_feedback}}", {"user_feedback": user_feedback} + ) + + config = ChatDriverConfig( + context=context, + openai_client=open_ai_client, + model="gpt-3.5-turbo", + message_provider=history, + ) + + chat_driver = ChatDriver(config) + return await chat_driver.respond() diff --git a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_outline_decision.py b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_outline_decision.py new file mode 100644 index 00000000..a8ef2fa6 --- /dev/null +++ b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_outline_decision.py @@ -0,0 +1,75 @@ +from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider +from chat_driver.message_formatter import liquid_format +from openai import AsyncAzureOpenAI, AsyncOpenAI + +from ..document_skill import Outline, Paper + + +async def get_user_feedback_for_outline_decision( + context: ContextProtocol, + open_ai_client: AsyncOpenAI | AsyncAzureOpenAI, + chat_history: str, + outline_versions: list[Outline] = [], + paper_versions: list[Paper] = [], + user_feedback: str | None = None, + outline: bool = False, +): + history = InMemoryMessageHistoryProvider(formatter=liquid_format) + + if outline: + history.append_system_message( + ( + "Use the user's most recent feedback to determine if the user wants to iterate further on the" + " provided outline [ITERATE], or if the user is ready to move on to drafting a paper from the" + " provided outline [CONTINUE]. Based on the user's feedback on the provided outline, determine if" + " the user wants to [ITERATE], [CONTINUE], or [QUIT]. Reply with ONLY [ITERATE], [CONTINUE], or [QUIT]." + ) + ) + else: + history.append_system_message( + ( + "You are an AI assistant that helps draft outlines for a future flushed-out document." + " You use the user's most recent feedback to determine if the user wants to iterate further on the" + " provided draft content [ITERATE], or if the user is ready to move on to drafting new additional content" + " [CONTINUE]. Based on the user's feedback on the provided drafted content, determine if" + " the user wants to [ITERATE], [CONTINUE], or [QUIT]. Reply with ONLY [ITERATE], [CONTINUE], or [QUIT]." + ) + ) + + history.append_system_message("{{chat_history}}", {"chat_history": chat_history}) + + if len(outline_versions): + last_outline_content = outline_versions[-1].content + if outline: + history.append_system_message( + "{{outline}}", {"outline": last_outline_content} + ) + else: + history.append_system_message( + "{{outline}}", {"outline": last_outline_content} + ) + + if not outline: + if paper_versions: + full_paper_content = "" + for content in paper_versions[-1].contents: + full_paper_content += content.content + history.append_system_message( + "{{content}}", {"content": full_paper_content} + ) + + if user_feedback is not None: + history.append_system_message( + "{{user_feedback}}", {"user_feedback": user_feedback} + ) + + config = ChatDriverConfig( + context=context, + openai_client=open_ai_client, + model="gpt-3.5-turbo", + message_provider=history, + ) + + chat_driver = ChatDriver(config) + return await chat_driver.respond() diff --git a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_page_decision.py b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_page_decision.py new file mode 100644 index 00000000..7a10e00d --- /dev/null +++ b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_page_decision.py @@ -0,0 +1,75 @@ +from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider +from chat_driver.message_formatter import liquid_format +from openai import AsyncAzureOpenAI, AsyncOpenAI + +from ..document_skill import Outline, Paper + + +async def get_user_feedback_for_page_decision( + context: ContextProtocol, + open_ai_client: AsyncOpenAI | AsyncAzureOpenAI, + chat_history: str, + outline_versions: list[Outline] = [], + paper_versions: list[Paper] = [], + user_feedback: str | None = None, + outline: bool = False, +): + history = InMemoryMessageHistoryProvider(formatter=liquid_format) + + if outline: + history.append_system_message( + ( + "Use the user's most recent feedback to determine if the user wants to iterate further on the" + " provided outline [ITERATE], or if the user is ready to move on to drafting a paper from the" + " provided outline [CONTINUE]. Based on the user's feedback on the provided outline, determine if" + " the user wants to [ITERATE], [CONTINUE], or [QUIT]. Reply with ONLY [ITERATE], [CONTINUE], or [QUIT]." + ) + ) + else: + history.append_system_message( + ( + "You are an AI assistant that helps draft outlines for a future flushed-out document." + " You use the user's most recent feedback to determine if the user wants to iterate further on the" + " provided draft content [ITERATE], or if the user is ready to move on to drafting new additional content" + " [CONTINUE]. Based on the user's feedback on the provided drafted content, determine if" + " the user wants to [ITERATE], [CONTINUE], or [QUIT]. Reply with ONLY [ITERATE], [CONTINUE], or [QUIT]." + ) + ) + + history.append_system_message("{{chat_history}}", {"chat_history": chat_history}) + + if len(outline_versions): + last_outline_content = outline_versions[-1].content + if outline: + history.append_system_message( + "{{outline}}", {"outline": last_outline_content} + ) + else: + history.append_system_message( + "{{outline}}", {"outline": last_outline_content} + ) + + if not outline: + if paper_versions: + full_paper_content = "" + for content in paper_versions[-1].contents: + full_paper_content += content.content + history.append_system_message( + "{{content}}", {"content": full_paper_content} + ) + + if user_feedback is not None: + history.append_system_message( + "{{user_feedback}}", {"user_feedback": user_feedback} + ) + + config = ChatDriverConfig( + context=context, + openai_client=open_ai_client, + model="gpt-3.5-turbo", + message_provider=history, + ) + + chat_driver = ChatDriver(config) + return await chat_driver.respond() diff --git a/libraries/python/skills/skills/document-skill/document_skill/document_skill.py b/libraries/python/skills/skills/document-skill/document_skill/document_skill.py index 8604bee1..063bc5f2 100644 --- a/libraries/python/skills/skills/document-skill/document_skill/document_skill.py +++ b/libraries/python/skills/skills/document-skill/document_skill/document_skill.py @@ -4,6 +4,8 @@ from skill_library import RoutineTypes, Skill from skill_library.routine import InstructionRoutine, ProgramRoutine +from .chat_drivers import draft_content, draft_outline, get_user_feedback_decision + NAME = "document_skill" DESCRIPTION = "Anything related to documents - creation, edit, translation" @@ -28,15 +30,14 @@ class Paper(BaseModel): contents: list[Content] = [] -class DocumentSkillContext(Context): - def __init__(self) -> None: +class DocumentSkillContext: + def __init__(self, context: ContextProtocol) -> None: + # TODO: Pull in all this state from a Drive. self.chat_history: str = "" self.attachments_list: list[Attachment] = [] self.outline_versions: list[Outline] = [] self.paper_versions: list[Paper] = [] - super().__init__() # currently all params of Context can be None. - class DocumentSkill(Skill): def __init__( @@ -44,35 +45,20 @@ def __init__( context: ContextProtocol, chat_driver_config: ChatDriverConfig, ) -> None: - self.document_skill_context: DocumentSkillContext = DocumentSkillContext() + self.document_skill_context: DocumentSkillContext = DocumentSkillContext(context) actions = [ - self.test_action, + self.ask_user, + self.draft_content, + self.draft_outline, + self.get_user_feedback_decision, ] - # however, with current skill chat driver config (no chat connection setup), - # i see an issue when running the instruction routine as a command. It correctly detects the - # test_action step to run... but the I get the response: "Error running function: 'NoneType' object has no attribute 'chat'" - # it looks like information events after actions run in posix command are passed through a chat driver with model - # connectivity... as it explains the result in a natural language response wrapper (not the simple result of directly calling each command). - # i'm wondering if this is where the skill chat driver gets used as a chat connection? - # YES. look at instruction_routine_runner. This is how it is designed currently. - # i.r.r. will use the configured chat driver of the routine's skill to call "respond" with message being the "step" (the function in the routine)... - # but this means it is passed to the language model with the tool choices (assuming the action/function has also been registered as a function not just - # as a command... so that it can be included in the tool selection for the skill's chat driver to pass to the language model). Our code will execute (code in the - # chat driver... i think... i need to look into chat driver code more...) but the wrapped response out of the respond function is returned and messaged - # out as an information event. - # so big Q here... should a program routine or instruction routine be run by a language model? I'm not sure I want this... can we have an option? routines: list[RoutineTypes] = [ self.test_instruction_routine(), ] # Configure the skill's chat driver. - ##### - # EVEN IF, the skill will not use the chat driver for any llm call, right now - # the skill's chat driver is used to forward available skill commands and functions to - # any higher level assistant that has those skills registered. - ##### chat_driver_config.commands = actions chat_driver_config.functions = actions @@ -114,303 +100,91 @@ def template_example_routine(self) -> ProgramRoutine: ################################## # Actions ################################## - def test_action( + async def draft_content( self, - context: Context, + context: ContextProtocol, + decision: str | None = None, + user_feedback: str | None = None, ) -> str: - return "hello world" # - - # This may not be needed as an action... not sure yet how context will be set. + response = await draft_content( + context=context, + open_ai_client=self.open_ai_client, + chat_history=self.document_skill_context.chat_history, + attachments=self.document_skill_context.attachments_list, + outline_versions=self.document_skill_context.outline_versions, + paper_versions=self.document_skill_context.paper_versions, + user_feedback=user_feedback, + decision=decision, + ) + return response.message or "" + async def draft_outline( + self, context: ContextProtocol, decision: str | None = None, user_feedback: str | None = None + ) -> str: + response = await draft_outline( + context=context, + open_ai_client=self.open_ai_client, + chat_history=self.document_skill_context.chat_history, + attachments=self.document_skill_context.attachments_list, + outline_versions=self.document_skill_context.outline_versions, + user_feedback=user_feedback, + ) + return response.message or "" -# def set_context( -# self, -# context: Context, -# chat_history: str, -# attachments_list: list[Attachment] -# ) -> None: -# self.context.chat_history = chat_history -# self.context.attachments_list = attachments_list -# -# async def draft_outline( -# self, -# context: Context, -# openai_client: AsyncOpenAI, -# model: str, -# user_feedback: str | None = None -# ) -> None: -# -# # construct completion request - draft outline from existing info -# messages: list[ChatCompletionMessageParam] = [] -# _add_main_system_message(messages, draft_outline_main_system_message) -# _add_chat_history_system_message(messages, self.context.chat_history) -# _add_attachments_system_message(messages, self.context.attachments_list) -# -# if len(self.context.outline_versions) != 0: -# _add_existing_outline_system_message(messages, self.context.outline_versions[-1].content) -# -# if user_feedback is not None: -# _add_user_feedback_system_message(messages, user_feedback) -# -# completion_args = { -# "messages": messages, -# "model": model, -# "response_format": { -# "type": "text" -# } -# } -# completion = await openai_client.chat.completions.create(**completion_args) -# outline = completion.choices[0].message.content -# -# debug_log = json.dumps(completion_args, indent=2) + "\n\n" -# debug_log += f"Response:\n{completion.model_dump_json(indent=2)}\n\n" -# #print(debug_log) -# -# # message event should be sent from within this action. For now using stdout. -# chat_output = f"\nAssistant: Outline drafted\n\n{outline}\n" -# sys.stdout.write(chat_output) -# sys.stdout.flush() -# -# # store generated outline -# version_no = len(self.context.outline_versions) + 1 -# self.context.outline_versions.append(Outline(version=version_no, content=outline)) -# -# # update chat_history. -# self.context.chat_history = self.context.chat_history + chat_output -# return -# -# async def draft_content( -# self, -# context: Context, -# openai_client: AsyncOpenAI, -# model: str, -# user_feedback: str | None = None, -# decision: str | None = None -# ) -> None: -# # construct completion request - draft content/page/fragment from existing info -# messages: list[ChatCompletionMessageParam] = [] -# -# if decision == "[ITERATE]": -# _add_main_system_message(messages, draft_page_iterate_main_system_message) -# else: -# _add_main_system_message(messages, draft_page_continue_main_system_message) -# -# _add_chat_history_system_message(messages, self.context.chat_history) -# _add_attachments_system_message(messages, self.context.attachments_list) -# _add_approved_outline_system_message(messages, self.context.outline_versions[-1].content) -# -# if len(self.context.paper_versions) != 0: -# if decision == "[ITERATE]" and user_feedback is not None: -# _add_existing_content_system_message(messages, self.context.paper_versions[-1].contents[-1].content) -# _add_user_feedback_system_message(messages, user_feedback) -# else: -# full_content = "" -# for content in self.context.paper_versions[-1].contents: -# full_content += content.content -# _add_existing_content_system_message(messages, full_content) -# -# completion_args = { -# "messages": messages, -# "model": model, -# "response_format": { -# "type": "text" -# } -# } -# completion = await openai_client.chat.completions.create(**completion_args) -# draft = completion.choices[0].message.content -# -# debug_log = json.dumps(completion_args, indent=2) + "\n\n" -# debug_log += f"Response:\n{completion.model_dump_json(indent=2)}\n\n" -# #print(debug_log) -# -# # message event should be sent from within this action. For now using stdout. -# if decision == "[ITERATE]": -# chat_output = f"\nAssistant: Updated page based on your feedback:\n\n{draft}\n" -# else: -# chat_output = f"\nAssistant: Page drafted:\n\n{draft}\n" -# sys.stdout.write(chat_output) -# sys.stdout.flush() -# -# # store generated content/page/fragment -# version_no = len(self.context.paper_versions) + 1 -# if len(self.context.paper_versions) == 0: -# self.context.paper_versions.append(Paper(version=version_no, contents=[Content(content=draft)])) -# else: -# existing_contents = self.context.paper_versions[-1].contents -# if decision == "[ITERATE]": -# existing_contents[-1].content = draft -# else: -# existing_contents.append(Content(content=draft)) -# self.context.paper_versions.append(Paper(version=version_no, contents=existing_contents)) -# -# # update chat_history. -# self.context.chat_history = self.context.chat_history + chat_output -# return -# -# async def get_user_feedback( -# self, -# context: Context, -# openai_client: AsyncOpenAI, -# model: str, -# outline: bool -# ) -> tuple[str, str]: -# -# # message event should be sent from within this action. For now using stdout. -# event_message = ("Please review the above draft and provide me any feedback. You can also " -# "let me know if you are ready to continue drafting the paper or would like" -# " to iterate on the current content.") -# # msg_event = MessageEvent(message=event_message) -# chat_output = f"\nAssistant: {event_message}\n" -# sys.stdout.write(chat_output) -# sys.stdout.flush() -# self.context.chat_history = self.context.chat_history + chat_output -# -# #user response input should be awaited for here from interface. For now using stdout. -# sys.stdout.write("\nUser: ") -# user_feedback = input() -# sys.stdout.write(user_feedback) -# sys.stdout.flush() -# chat_output = f"\nUser: {user_feedback}" -# self.context.chat_history = self.context.chat_history + chat_output -# -# # construct completion request - determine user intent from feedback -# messages: list[ChatCompletionMessageParam] = [] -# if outline is True: -# _add_main_system_message(messages, outline_feedback_main_system_message) -# else: -# _add_main_system_message(messages, draft_page_feedback_main_system_message) -# -# _add_chat_history_system_message(messages, self.context.chat_history) -# -# if len(self.context.outline_versions) != 0: -# if outline is True: -# _add_existing_outline_system_message(messages, self.context.outline_versions[-1].content) -# else: -# _add_approved_outline_system_message(messages, self.context.outline_versions[-1].content) -# -# if outline is False: -# if len(self.context.paper_versions) != 0: -# full_content = "" -# for content in self.context.paper_versions[-1].contents: -# full_content += content.content -# _add_existing_content_system_message(messages, full_content) -# -# _add_user_feedback_system_message(messages, user_feedback) -# -# completion_args = { -# "messages": messages, -# "model": model, -# "response_format": { -# "type": "text" -# } -# } -# completion = await openai_client.chat.completions.create(**completion_args) -# decision = completion.choices[0].message.content # this should NOT be done as a string. -# -# debug_log = json.dumps(completion_args, indent=2) + "\n\n" -# debug_log += f"Response:\n{completion.model_dump_json(indent=2)}\n\n" -# #print(debug_log) -# -# return decision, user_feedback -# -# # A little helper -# def print_final_doc(self, context: Context) -> None: -# print("Assistant: Looks like we have a completed doc. Here it is!\n") -# # compose full content for existing paper (the latest version) -# full_content = "" -# for content in self.context.paper_versions[-1].contents: -# full_content += content.content -# print(full_content) -# -# -## Current approach uses system messages for everything. -# draft_outline_main_system_message = ("Generate an outline for the document, including title. The outline should include the key points that will" -# " be covered in the document. Consider the attachments, the rationale for why they were uploaded, and the" -# " conversation that has taken place. The outline should be a hierarchical structure with multiple levels of" -# " detail, and it should be clear and easy to understand. The outline should be generated in a way that is" -# " consistent with the document that will be generated from it.") -# #("You are an AI assistant that helps draft outlines for a future flushed-out document." -# # " You use information from a chat history between a user and an assistant, a prior version of a draft" -# # " outline if it exists, as well as any other attachments provided by the user to inform a newly revised " -# # "outline draft. Provide ONLY any outline. Provide no further instructions to the user.") -# -# outline_feedback_main_system_message = ("Use the user's most recent feedback to determine if the user wants to iterate further on the" -# " provided outline [ITERATE], or if the user is ready to move on to drafting a paper from the" -# " provided outline [CONTINUE]. Based on the user's feedback on the provided outline, determine if" -# " the user wants to [ITERATE], [CONTINUE], or [QUIT]. Reply with ONLY [ITERATE], [CONTINUE], or [QUIT].") -# -# draft_page_continue_main_system_message = ("Following the structure of the outline, create the content for the next (or first) page of the" -# " document - don't try to create the entire document in one pass nor wrap it up too quickly, it will be a" -# " multi-page document so just create the next page. It's more important to maintain" -# " an appropriately useful level of detail. After this page is generated, the system will follow up" -# " and ask for the next page. If you have already generated all the pages for the" -# " document as defined in the outline, return empty content.") -# #("You are an AI assistant that helps draft new content of a document based on an outline." -# # " You use information from a chat history between a user and an assistant, the approved outline from the user," -# # "and an existing version of drafted content if it exists, as well as any other attachments provided by the user to inform newly revised " -# # "content. Newly drafted content does not need to cover the entire outline. Instead it should be limited to a reasonable 100 lines of natural language" -# # " or subsection of the outline (which ever is shorter). The newly drafted content should be written as to append to any existing drafted content." -# # " This way the user can review newly drafted content as a subset of the future full document and not be overwhelmed." -# # "Only provide the newly drafted content. Provide no further instructions to the user.") -# -# draft_page_iterate_main_system_message = ("Following the structure of the outline, iterate on the currently drafted page of the" -# " document. It's more important to maintain" -# " an appropriately useful level of detail. After this page is iterated upon, the system will follow up" -# " and ask for the next page.") -# -# draft_page_feedback_main_system_message = ("You are an AI assistant that helps draft outlines for a future flushed-out document." -# " You use the user's most recent feedback to determine if the user wants to iterate further on the" -# " provided draft content [ITERATE], or if the user is ready to move on to drafting new additional content" -# " [CONTINUE]. Based on the user's feedback on the provided drafted content, determine if" -# " the user wants to [ITERATE], [CONTINUE], or [QUIT]. Reply with ONLY [ITERATE], [CONTINUE], or [QUIT].") -# -# def _add_main_system_message(messages: list[ChatCompletionMessageParam], prompt: str) -> None: -# message: ChatCompletionSystemMessageParam = { -# "role": "system", -# "content": prompt -# } -# messages.append(message) -# -# def _add_chat_history_system_message(messages: list[ChatCompletionMessageParam], chat_history: str) -> None: -# message: ChatCompletionSystemMessageParam = { -# "role": "system", -# "content": f"{chat_history}" -# } -# messages.append(message) -# -# def _add_attachments_system_message(messages: list[ChatCompletionMessageParam], attachments: list[Attachment]) -> None: -# for item in attachments: -# message: ChatCompletionSystemMessageParam = { -# "role": "system", -# "content": (f"{item.filename}{item.content}") -# } -# messages.append(message) -# -# def _add_existing_outline_system_message(messages: list[ChatCompletionMessageParam], outline: str) -> None: -# message: ChatCompletionSystemMessageParam = { -# "role": "system", -# "content": (f"{outline}") -# } -# messages.append(message) -# -# def _add_approved_outline_system_message(messages: list[ChatCompletionMessageParam], outline: str) -> None: -# message: ChatCompletionSystemMessageParam = { -# "role": "system", -# "content": (f"{outline}") -# } -# messages.append(message) -# -# def _add_existing_content_system_message(messages: list[ChatCompletionMessageParam], content: str) -> None: -# message: ChatCompletionSystemMessageParam = { -# "role": "system", -# "content": (f"{content}") -# } -# messages.append(message) -# -# def _add_user_feedback_system_message(messages: list[ChatCompletionMessageParam], user_feedback: str) -> None: -# message: ChatCompletionSystemMessageParam = { -# "role": "system", -# "content": (f"{user_feedback}") -# } -# messages.append(message) -# + async def get_user_feedback_decision(self, context: ContextProtocol, user_feedback: str, outline: bool) -> str: + response = await get_user_feedback_decision( + context=context, + open_ai_client=self.open_ai_client, + chat_history=self.document_skill_context.chat_history, + attachments=self.document_skill_context.attachments_list, + outline_versions=self.document_skill_context.outline_versions, + paper_versions=self.document_skill_context.paper_versions, + user_feedback=user_feedback, + outline=outline, + ) + return response.message or "" + + async def routine(self, context: ContextProtocol): + # Define these vars here to make the following routine look more like a PROGRAM routine. + document_skill = self + + async def ask_user(question: str) -> str: + return "hello world" + + # Routine. + decision = "[ITERATE]" + while decision == "[ITERATE]": + await document_skill.draft_outline(context, user_feedback=user_feedback) + user_feedback = await ask_user("This look good?") + decision = await document_skill.get_user_feedback_decision(context, user_feedback, outline=True) + if decision == "[QUIT]": + exit() + await document_skill.draft_content(context) + user_feedback = await ask_user("This look good?") + decision = await document_skill.get_user_feedback_decision(context, user_feedback, outline=False) + while decision != "[QUIT]": + content = await document_skill.draft_content( + context, user_feedback=user_feedback, chat_history=[], decision=decision + ) + decision, user_feedback = await document_skill.get_user_feedback_decision( + context, user_feedback, outline=False + ) + return content + + # decision = "[ITERATE]" + # while decision == "[ITERATE]": + # document_skill.draft_outline(user_feedback=user_feedback, history=assistant.chat_history) + # guided_conversation.run() + # user_feedback = await ask_user("This look good?") + # decision = document_skill.get_user_feedback_decision(user_feedback, outline=True) + # if decision == "[QUIT]": + # exit() + # document_skill.draft_content() + # user_feedback = ask_user("This look good?") + # decision = document_skill.get_user_feedback_decision(user_feedback, outline=False) + # while decision != "[QUIT]": + # content = document_skill.draft_content(user_feedback=user_feedback, decision=decision) + # decision, user_feedback = await document_skill.get_user_feedback_decision( + # context, user_feedback, outline=False + # ) + # return content diff --git a/libraries/python/skills/skills/document-skill/uv.lock b/libraries/python/skills/skills/document-skill/uv.lock index 2a8ddd7d..54dbb947 100644 --- a/libraries/python/skills/skills/document-skill/uv.lock +++ b/libraries/python/skills/skills/document-skill/uv.lock @@ -320,6 +320,7 @@ dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, + { name = "python-liquid" }, { name = "requests" }, { name = "tiktoken" }, ] @@ -335,6 +336,7 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, + { name = "python-liquid", specifier = ">=1.12.1" }, { name = "requests", specifier = ">=2.32.0" }, { name = "tiktoken", specifier = ">=0.7.0" }, ] diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/agenda.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/agenda.py new file mode 100644 index 00000000..9d5623e9 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/agenda.py @@ -0,0 +1,24 @@ +import logging + +from pydantic import Field + +from form_filler_skill.base_model_llm import BaseModelLLM +from form_filler_skill.resources import ( + ResourceConstraintMode, +) + +logger = logging.getLogger(__name__) + + +class AgendaItem(BaseModelLLM): + title: str = Field(description="Brief description of the item") + resource: int = Field(description="Number of turns required for the item") + + +class Agenda(BaseModelLLM): + resource_constraint_mode: ResourceConstraintMode | None = Field(default=None) + max_agenda_retries: int = Field(default=2) + items: list[AgendaItem] = Field( + description="Ordered list of items to be completed in the remainder of the conversation", + default_factory=list, + ) diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/artifact.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/artifact.py new file mode 100644 index 00000000..44ef224f --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/artifact.py @@ -0,0 +1,463 @@ +# Copyright (c) Microsoft. All rights reserved. + + +import json +import logging +from typing import Any, Literal, TypeVar, Union, get_args, get_origin, get_type_hints + +from pydantic import BaseModel, ValidationError, create_model + +from form_filler_skill.base_model_llm import BaseModelLLM + + +from .chat_drivers.fix_artifact_error import fix_artifact_error +from .message import Conversation, ConversationMessageType, Message + +logger = logging.getLogger(__name__) + + +class Artifact: + """The Artifact plugin takes in a Pydantic base model, and robustly handles updating the fields of the model + A typical use case is as a form an agent must complete throughout a conversation. + Another use case is as a working memory for the agent. + + The primary interface is update_artifact, which takes in the field_name to update and its new value. + Additionally, the chat_history is passed in to help the agent make informed decisions in case an error occurs. + + The Artifact also exposes several functions to access internal state: + get_artifact_for_prompt, get_schema_for_prompt, and get_failed_fields. + """ + + def __init__(self, input_artifact: BaseModel, max_artifact_field_retries: int = 2) -> None: + """ + Initialize the Artifact plugin with the given Pydantic base model. + + Args: + input_artifact (BaseModel): The Pydantic base model to use as the artifact + max_artifact_field_retries (int): The maximum number of times to retry updating a field in the artifact + """ + + self.max_artifact_field_retries = max_artifact_field_retries + + self.original_schema = input_artifact.model_json_schema() + + # Create a new artifact model based on the one provided by the user with + # "Unanswered" set for all fields. + modified_classes = self._modify_classes(input_artifact) + self.artifact = self._modify_base_artifact(input_artifact, modified_classes)() + + # failed_artifact_fields maps a field name to a list of the history of + # the failed attempts to update it. + # dict: key = field, value = list of tuple[attempt, error message] + self.failed_artifact_fields: dict[str, list[tuple[str, str]]] = {} + + async def update_artifact(self, field_name: str, field_value: Any) -> tuple[bool, Conversation]: + """ + The core interface for the Artifact plugin. This function will attempt + to update the given field_name to the given field_value. If the + field_value fails Pydantic validation, an LLM will determine one of two + actions to take. + + Given the conversation as additional context the two actions are: + - Retry the update the artifact by fixing the formatting using the + previous failed attempts as guidance + - Take no action or in other words, resume the conversation to ask + the user for more information because the user gave incomplete or + incorrect information + + Args: + field_name (str): The name of the field to update in the artifact + field_value (Any): The value to set the field to conversation + (Conversation): The conversation object that contains the history of + the conversation + + Returns: + A tuple with two fields: a boolean indicating + success and a list of conversation messages that may have been + generated. + + Several outcomes can happen: + + - The update may have failed due to: + - A field_name that is not valid in the artifact. + - The field_value failing Pydantic validation and all retries + failed. + - The model failed to correctly call a tool. + In this case, the boolean will be False and the list may contain + a message indicating the failure. + + - The agent may have successfully updated the artifact or fixed it. + In this case, the boolean will be True and the list will contain + a message indicating the update and possibly intermediate + messages. + + - The agent may have decided to resume the conversation. + In this case, the boolean will be True and the messages may only + contain messages indicated previous errors. + """ + + conversation = Conversation() + + # Check if the field name is valid, and return with a failure message if + # not. + is_valid_field, msg = self._is_valid_field(field_name) + if not is_valid_field: + if msg is not None: + conversation.messages.append(msg) + return False, conversation + + # Try to update the field, and handle any errors that occur until the + # field is successfully updated or skipped according to + # max_artifact_field_retries. + while True: + try: + # Check if there have been too many previous failed attempts to + # update the field. + if ( + len(self.failed_artifact_fields.get(field_name, [])) + >= self.max_artifact_field_retries + ): + logger.warning( + f"Updating field {field_name} has failed too many times. Skipping." + ) + return False, conversation + + # Attempt to update the artifact. + self.artifact.__setattr__(field_name, field_value) + + # This will only be reached if there were no exceptions setting + # the artifact field. + msg = Message( + { + "role": "assistant", + "content": f"Assistant updated {field_name} to {field_value}", + }, + type=ConversationMessageType.ARTIFACT_UPDATE, + turn=None, + ) + conversation.messages.append(msg) + return True, conversation + + except Exception as e: + logger.warning(f"Error updating field {field_name}: {e}. Retrying...") + # Handle update error will increment failed_artifact_fields, once it has failed + # greater than self.max_artifact_field_retries the field will be skipped and the loop will break + success, new_field_value = await self._handle_update_error( + field_name, field_value, conversation, e + ) + + # The agent has successfully fixed the field. + if success: + if new_field_value is not None: + logger.info( + f"Agent successfully fixed field {field_name}. New value: {new_field_value}" + ) + field_value = new_field_value + else: + # This is the case where the agent has decided to resume the conversation. + logger.info( + f"Agent could not fix the field itself & decided to resume conversation to fix field {field_name}" + ) + return True, conversation + + logger.warning(f"Agent failed to fix field {field_name}. Retrying...") + # Otherwise, the agent has failed and we will go through the loop again + + def get_artifact_for_prompt(self) -> str: + """ + Returns a formatted JSON-like representation of the current state of the + fields artifact. Any fields that were failed are completely omitted. + """ + failed_fields = self.get_failed_fields() + return json.dumps({ + k: v for k, v in self.artifact.model_dump().items() if k not in failed_fields + }) + + def get_schema_for_prompt(self, filter_one_field: str | None = None) -> str: + """Gets a clean version of the original artifact schema, optimized for use in an LLM prompt. + + Args: + filter_one_field (str | None): If this is provided, only the schema for this one field will be returned. + + Returns: + str: The cleaned schema + """ + + def _clean_properties(schema: dict, failed_fields: list[str]) -> str: + properties = schema.get("properties", {}) + clean_properties = {} + for name, property_dict in properties.items(): + if name not in failed_fields: + cleaned_property = {} + for k, v in property_dict.items(): + if k in ["title", "default"]: + continue + cleaned_property[k] = v + clean_properties[name] = cleaned_property + + clean_properties_str = str(clean_properties) + clean_properties_str = clean_properties_str.replace("$ref", "type") + clean_properties_str = clean_properties_str.replace("#/$defs/", "") + return clean_properties_str + + # If filter_one_field is provided, only get the schema for that one field + if filter_one_field: + if not self._is_valid_field(filter_one_field): + logger.error(f'Field "{filter_one_field}" is not a valid field in the artifact.') + raise ValueError( + f'Field "{filter_one_field}" is not a valid field in the artifact.' + ) + filtered_schema = { + "properties": { + filter_one_field: self.original_schema["properties"][filter_one_field] + } + } + filtered_schema.update( + (k, v) for k, v in self.original_schema.items() if k != "properties" + ) + schema = filtered_schema + else: + schema = self.original_schema + + failed_fields = self.get_failed_fields() + properties = _clean_properties(schema, failed_fields) + if not properties: + logger.error("No properties found in the schema.") + raise ValueError("No properties found in the schema.") + + types_schema = schema.get("$defs", {}) + custom_types = [] + for type_name, type_info in types_schema.items(): + if f"'type': '{type_name}'" in properties: + clean_schema = _clean_properties(type_info, []) + if clean_schema != "{}": + custom_types.append(f"{type_name} = {clean_schema}") + + if custom_types: + explanation = ( + f"If you wanted to create a {type_name} object, for example, you " + "would make a JSON object with the following keys: " + "{', '.join(types_schema[type_name]['properties'].keys())}." + ) + custom_types_str = "\n".join(custom_types) + return ( + f"{properties}\n\n" + "Here are the definitions for the custom types referenced in the artifact schema:\n" + f"{custom_types_str}\n\n" + f"{explanation}\n" + "Remember that when updating the artifact, the field will be the original " + "field name in the artifact and the JSON object(s) will be the value." + ) + else: + return properties + + def get_failed_fields(self) -> list[str]: + """Get a list of fields that have failed all attempts to update. + + Returns: + list[str]: A list of field names that have failed all attempts to update. + """ + fields = [] + for field, attempts in self.failed_artifact_fields.items(): + if len(attempts) >= self.max_artifact_field_retries: + fields.append(field) + return fields + + + T = TypeVar("T") + + def _get_type_if_subtype(self, target_type: type[T], base_type: type[Any]) -> type[T] | None: + """ + Recursively checks the target_type to see if it is a subclass of + base_type or a generic including base_type. + + Args: + target_type: The type to check. + base_type: The type to check against. + + Returns: + The class type if target_type is base_type, a subclass of base_type, + or a generic including base_type; otherwise, None. + """ + origin = get_origin(target_type) + if origin is None: + if issubclass(target_type, base_type): + return target_type + else: + # Recursively check if any of the arguments are the target type. + for arg in get_args(target_type): + result = self._get_type_if_subtype(arg, base_type) + if result is not None: + return result + return None + + def _modify_classes(self, artifact_class: BaseModel) -> dict[str, type[BaseModelLLM]]: + """Find all classes used as type hints in the artifact, and modify them to set 'Unanswered' as a default and valid value for all fields.""" + modified_classes = {} + # Find any instances of BaseModel in the artifact class in the first "level" of type hints + for field_name, field_type in get_type_hints(artifact_class).items(): + is_base_model = self._get_type_if_subtype(field_type, BaseModel) + if is_base_model is not None: + modified_classes[field_name] = self._modify_base_artifact(is_base_model) + + return modified_classes + + def _replace_type_annotations( + self, field_annotation: type[Any] | None, modified_classes: dict[str, type[BaseModelLLM]] + ) -> type: + """ + Recursively replace type annotations with modified classes where + applicable. + """ + # Get the origin of the field annotation, which is the base type for + # generic types (e.g., List[str] -> list, Dict[str, int] -> dict) + origin = get_origin(field_annotation) + + # Get the type arguments of the generic type (e.g., List[str] -> str, + # Dict[str, int] -> str, int) + args = get_args(field_annotation) + + if origin is None: + # The type is not generic; check if it's a subclass that needs to be replaced + if isinstance(field_annotation, type) and issubclass(field_annotation, BaseModelLLM): + return modified_classes.get(field_annotation.__name__, field_annotation) + return field_annotation if field_annotation is not None else object + else: + # The type is generic; recursively replace the type annotations of the arguments + new_args = tuple(self._replace_type_annotations(arg, modified_classes) for arg in args) + return origin[new_args] + + def _modify_base_artifact( + self, + artifact_model: BaseModel, + modified_classes: dict[str, type[BaseModelLLM]] | None = None, + ) -> type[BaseModelLLM]: + """ + Create a new artifact model with 'Unanswered' as a default and valid + value for all fields. + """ + field_definitions = {} + for name, field_info in artifact_model.model_fields.items(): + # Replace original classes with modified version. + if modified_classes is not None: + field_info.annotation = self._replace_type_annotations( + field_info.annotation, modified_classes + ) + + # This makes it possible to always set a field to "Unanswered". + annotation = Union[field_info.annotation, Literal["Unanswered"]] + + # This sets the default value to "Unanswered". + default = "Unanswered" + + # This adds "Unanswered" as a possible value to any regex patterns. + metadata = field_info.metadata + for m in metadata: + if hasattr(m, "pattern"): + m.pattern += "|Unanswered" + + field_definitions[name] = (annotation, default, *metadata) + + return create_model("Artifact", __base__=BaseModelLLM, **field_definitions) + + def _is_valid_field(self, field_name: str) -> tuple[bool, Message | None]: + """ + Check if the field_name is a valid field in the artifact. Returns True + if it is, False and an error message otherwise. + """ + if field_name not in self.artifact.model_fields: + error_message = f'Field "{field_name}" is not a valid field in the artifact.' + msg = Message( + {"role": "assistant", "content": error_message}, + type=ConversationMessageType.ARTIFACT_UPDATE, + turn=None, + ) + return False, msg + return True, None + + async def _handle_update_error( + self, field_name: str, field_value: Any, conversation: Conversation, error: Exception + ) -> tuple[bool, Any]: + """ + Handles the logic for when an error occurs while updating a field. + Creates the appropriate context for the model and calls the LLM to fix + the error. + + Args: + field_name (str): The name of the field to update in the artifact + field_value (Any): The value to set the field to conversation + (Conversation): The conversation object that contains the history of + the conversation error (Exception): The error that occurred while + updating the field + + Returns: + tuple[bool, Any]: A tuple containing a boolean indicating success + and the new field value if successful (if not, then None) + """ + + # Keep track of history of failed attempts for each field. + previous_attempts = self.failed_artifact_fields.get(field_name, []) + error_str = ( + str(error) + if not isinstance(error, ValidationError) + else "; ".join([e.get("msg") for e in error.errors()]).replace( + "; Input should be 'Unanswered'", " or input should be 'Unanswered'" + ) + ) + attempt = (str(field_value), error_str) + self.failed_artifact_fields[field_name] = previous_attempts + [attempt] + + result = await fix_artifact_error( + self.context, + self.openai_client, + previous_attempts="\n".join([ + f"Attempt: {attempt}\nError: {error}" for attempt, error in previous_attempts + ]), + artifact_schema=self.get_schema_for_prompt(filter_one_field=field_name), + conversation=conversation, + field_name=field_name, + ) + + # Handling the result of the LLM call + if result.message not in ["UPDATE_ARTIFACT", "RESUME_CONVERSATION"]: + logger.warning( + f"Failed to fix the artifact error due to an invalid response from the LLM: {result.message}" + ) + return False, None + + if result.message == "RESUME_CONVERSATION": + return True, None + + if result.message.startswith("UPDATE_ARTIFACT("): + field_value = result.message.split("(")[1].split(")")[0] + return True, field_value + + logger.warning( + f"Failed to fix the artifact error due to an invalid response from the LLM: {result.message}" + ) + return False, None + + def to_json(self) -> dict: + artifact_fields = self.artifact.model_dump() + return { + "artifact": artifact_fields, + "failed_fields": self.failed_artifact_fields, + } + + @classmethod + def from_json( + cls, + json_data: dict, + input_artifact: BaseModel, + max_artifact_field_retries: int = 2, + ) -> "Artifact": + artifact = cls(input_artifact, max_artifact_field_retries) + + artifact.failed_artifact_fields = json_data["failed_fields"] + + # Iterate over artifact fields and set them to the values in the json data + # Skip any fields that are set as "Unanswered" + for field_name, field_value in json_data["artifact"].items(): + if field_value != "Unanswered": + setattr(artifact.artifact, field_name, field_value) + return artifact diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/base_model_llm.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/base_model_llm.py new file mode 100644 index 00000000..06407695 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/base_model_llm.py @@ -0,0 +1,53 @@ +# Copyright (c) Microsoft. All rights reserved. + +import ast +from types import NoneType +from typing import Any, get_args + +from pydantic import BaseModel, ValidationInfo, field_validator + + +class BaseModelLLM(BaseModel): + """ + A Pydantic base class for use when an LLM is completing fields. Provides a + custom field validator and Pydantic Config. + """ + + @field_validator("*", mode="before") + def parse_literal_eval(cls, value: str, info: ValidationInfo) -> NoneType | str | Any: + """ + An LLM will always result in a string (e.g. '["x", "y"]'), so we need to + parse it to the correct type. + """ + + # Get the type hints for the field. We know the field is present because + # pydantic gave it to us, so we can ignore this type error. + annotation = cls.model_fields[info.field_name].annotation # type: ignore + typehints = get_args(annotation) + if len(typehints) == 0: + typehints = [annotation] + + # Usually fields that are NoneType have another type hint as well, e.g. + # str | None. If the LLM returns "None" and the field allows NoneType, + # we should return None without this code, the next if-block would leave + # the string "None" as the value + if (NoneType in typehints) and (value == "None"): + return None + + # If the field allows strings, we don't parse it - otherwise a + # validation error might be raised e.g. phone_number = "1234567890" + # should not be converted to an int if the type hint is str + if str in typehints: + return value + try: + evaluated_value = ast.literal_eval(value) + return evaluated_value + except Exception: + return value + + class Config: + # Ensure that validation happens every time a field is updated, not just + # when the artifact is created. + validate_assignment = True + # Do not allow extra fields to be added to the artifact. + extra = "forbid" diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/extract_form_fields.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/extract_form_fields.py new file mode 100644 index 00000000..26839318 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/extract_form_fields.py @@ -0,0 +1,74 @@ +from typing import Any, Literal + +import openai_client +from openai import AsyncOpenAI +from openai.types.chat import ChatCompletionMessageParam +from pydantic import BaseModel, Field + + +class FormField(BaseModel): + id: str = Field(description="The unique identifier of the field.") + name: str = Field(description="The name of the field.") + description: str = Field(description="The description of the field.") + type: Literal["string", "bool", "multiple_choice"] = Field(description="The type of the field.") + options: list[str] = Field(description="The options for multiple choice fields.") + required: bool = Field(description="Whether the field is required or not.") + + +class FormFields(BaseModel): + error_message: str = Field( + description="The error message in the case that the form fields could not be extracted." + ) + fields: list[FormField] = Field(description="The fields in the form.") + + +class NoResponseChoicesError(Exception): + pass + + +class NoParsedMessageError(Exception): + pass + + +async def extract( + async_openai_client: AsyncOpenAI, openai_model: str, max_response_tokens: int, form_content: str +) -> tuple[FormFields, dict[str, Any]]: + messages: list[ChatCompletionMessageParam] = [ + { + "role": "system", + "content": ( + "Extract the form fields from the provided form attachment. Any type of form is allowed, including for example" + " tax forms, address forms, surveys, and other official or unofficial form-types. If the content is not a form," + " or the fields cannot be determined, then set the error_message." + ), + }, + { + "role": "user", + "content": form_content, + }, + ] + + async with async_openai_client as client: + response = await client.beta.chat.completions.parse( + messages=messages, + model=openai_model, + response_format=FormFields, + ) + + if not response.choices: + raise NoResponseChoicesError() + + if not response.choices[0].message.parsed: + raise NoParsedMessageError() + + metadata = { + "request": { + "model": openai_model, + "messages": openai_client.truncate_messages_for_logging(messages), + "max_tokens": max_response_tokens, + "response_format": FormFields.model_json_schema(), + }, + "response": response.model_dump(), + } + + return response.choices[0].message.parsed, metadata diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/final_update.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/final_update.py new file mode 100644 index 00000000..e92814bc --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/final_update.py @@ -0,0 +1,91 @@ +import logging + +from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider +from chat_driver.message_formatter import liquid_format +from form_filler_skill.artifact import Artifact +from form_filler_skill.definition import GCDefinition +from form_filler_skill.message import Conversation +from openai import AsyncAzureOpenAI, AsyncOpenAI + +logger = logging.getLogger(__name__) + + +final_update_template = """You are a helpful, thoughtful, and meticulous assistant. +You just finished a conversation with a user.{% if context %} Here is some additional context about the conversation: +{{ context }}{% endif %} + +Your goal is to complete an artifact as thoroughly and accurately as possible based on the conversation. + +This is the schema of the artifact: +{{ artifact_schema }} + +You will be given the current state of the artifact as well as the conversation history. +Note that if the value for a field in the artifact is 'Unanswered', it means that the field was not completed. \ +Some fields may have already been completed during the conversation. + +Your need to determine whether there are any fields that need to be updated, and if so, update them. +- You should only update a field if both of the following conditions are met: (a) the current state does NOT adequately reflect the conversation \ +and (b) you are able to submit a valid value for a field. \ +You are allowed to update completed fields, but you should only do so if the current state is inadequate, \ +e.g. the user corrected a mistake in their date of birth, but the artifact does not show the corrected version. \ +Remember that it's always an option to reset a field to "Unanswered" - this is often the best choice if the artifact contains incorrect information that cannot be corrected. \ +Do not submit a value that is identical to the current state of the field (e.g. if the field is already "Unanswered" and the user didn't provide any new information about it, you should not submit "Unanswered"). \ +- Make sure the value adheres to the constraints of the field as specified in the artifact schema. \ +If it's not possible to update a field with a valid value (e.g., the user provided an invalid date of birth), you should not update the field. +- If the artifact schema is open-ended (e.g. it asks you to rate how pressing the user's issue is, without specifying rules for doing so), \ +use your best judgment to determine whether you have enough information to complete the field based on the conversation. +- Prioritize accuracy over completion. You should never make up information or make assumptions in order to complete a field. \ +For example, if the field asks for a 10-digit phone number, and the user provided a 9-digit phone number, you should not add a digit to the phone number in order to complete the field. +- If the user wasn't able to provide all of the information needed to complete a field, \ +use your best judgment to determine if a partial answer is appropriate (assuming it adheres to the formatting requirements of the field). \ +For example, if the field asks for a description of symptoms along with details about when the symptoms started, but the user wasn't sure when their symptoms started, \ +it's better to record the information they do have rather than to leave the field unanswered (and to indicate that the user was unsure about the start date). +- It's possible to update multiple fields at once (assuming you're adhering to the above rules in all cases). It's also possible that no fields need to be updated. + +Your task is to state your step-by-step reasoning about what to update, followed by a final recommendation. +Someone else will be responsible for executing the updates and they will only have access to your output \ +(not any of the conversation history, artifact schema, or other context) so make sure to specify exactly which \ +fields to update and the values to update them with, or to state that no fields need to be updated. +""" + +USER_MESSAGE_TEMPLATE = """Conversation history: +{{ conversation_history }} + +Current state of the artifact: +{{ artifact_state }}""" + + +async def final_update( + context: ContextProtocol, + open_ai_client: AsyncOpenAI | AsyncAzureOpenAI, + definition: GCDefinition, + chat_history: Conversation, + artifact: Artifact, +): + history = InMemoryMessageHistoryProvider(formatter=liquid_format) + + history.append_system_message( + final_update_template, + { + "context": definition.conversation_context, + "artifact_schema": artifact.get_schema_for_prompt(), + }, + ) + history.append_user_message( + USER_MESSAGE_TEMPLATE, + { + "conversation_history": str(chat_history), + "artifact_state": artifact.get_artifact_for_prompt(), + }, + ) + + config = ChatDriverConfig( + context=context, + openai_client=open_ai_client, + model="gpt-3.5-turbo", + message_provider=history, + ) + + chat_driver = ChatDriver(config) + return await chat_driver.respond() diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_agenda_error.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_agenda_error.py new file mode 100644 index 00000000..f577b301 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_agenda_error.py @@ -0,0 +1,57 @@ +import logging + +from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider +from chat_driver.message_formatter import liquid_format +from form_filler_skill.message import Conversation, ConversationMessageType +from openai import AsyncAzureOpenAI, AsyncOpenAI + +logger = logging.getLogger(__name__) + +AGENDA_ERROR_CORRECTION_SYSTEM_TEMPLATE = """You are a helpful, thoughtful, and meticulous assistant. +You are conducting a conversation with a user. You tried to update the agenda, but the update was invalid. + +You will be provided the history of your conversation with the user, your previous attempt(s) at updating the agenda, and the error message(s) that resulted from your attempt(s). +Your task is to correct the update so that it is valid. + +Your changes should be as minimal as possible - you are focused on fixing the error(s) that caused the update to be invalid. + +Note that if the resource allocation is invalid, you must follow these rules: + +1. You should not change the description of the first item (since it has already been executed), but you can change its resource allocation. +2. For all other items, you can combine or split them, or assign them fewer or more resources, but the content they cover collectively should not change (i.e. don't eliminate or add new topics). +For example, the invalid attempt was "item 1 = ask for date of birth (1 turn), item 2 = ask for phone number (1 turn), item 3 = ask for phone type (1 turn), item 4 = explore treatment history (6 turns)", and the error says you need to correct the total resource allocation to 7 turns. A bad solution is "item 1 = ask for date of birth (1 turn), item 2 = explore treatment history (6 turns)" because it eliminates the phone number and phone type topics. A good solution is "item 1 = ask for date of birth (2 turns), item 2 = ask for phone number, phone type, and treatment history (2 turns), item 3 = explore treatment history (3 turns)." +""" + + +async def fix_agenda_error( + context: ContextProtocol, + openai_client: AsyncOpenAI | AsyncAzureOpenAI, + previous_attempts: str, + conversation: Conversation, +): + history = InMemoryMessageHistoryProvider(formatter=liquid_format) + + history.append_system_message(AGENDA_ERROR_CORRECTION_SYSTEM_TEMPLATE) + history.append_user_message( + ( + "Conversation history:\n" + "{{ conversation_history }}\n\n" + "Previous attempts to update the agenda:\n" + "{{ previous_attempts }}" + ), + { + "conversation_history": str(conversation.exclude([ConversationMessageType.REASONING])), + "previous_attempts": previous_attempts, + }, + ) + + config = ChatDriverConfig( + context=context, + openai_client=openai_client, + model="gpt-3.5-turbo", + message_provider=history, + ) + + chat_driver = ChatDriver(config) + return await chat_driver.respond() diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_artifact_error.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_artifact_error.py new file mode 100644 index 00000000..cfd3b842 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_artifact_error.py @@ -0,0 +1,67 @@ +import logging + +from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider +from chat_driver.message_formatter import liquid_format +from events import BaseEvent +from form_filler_skill.message import Conversation, ConversationMessageType +from openai import AsyncAzureOpenAI, AsyncOpenAI + +logger = logging.getLogger(__name__) + +ARTIFACT_ERROR_CORRECTION_SYSTEM_TEMPLATE = """You are a helpful, thoughtful, and meticulous assistant. + +You are conducting a conversation with a user. Your goal is to complete an artifact as thoroughly as possible by the end of the conversation. + +You have tried to update a field in the artifact, but the value you provided did not adhere to the constraints of the field as specified in the artifact schema. + +You will be provided the history of your conversation with the user, the schema for the field, your previous attempt(s) at updating the field, and the error message(s) that resulted from your attempt(s). + +Your task is to return the best possible action to take next: + +1. UPDATE_FIELD(value) +- You should pick this action if you have a valid value to submit for the field in question. Replace "value" with the correct value. + +2. RESUME_CONVERSATION +- You should pick this action if: (a) you do NOT have a valid value to submit for the field in question, and (b) you need to ask the user for more information in order to obtain a valid value. For example, if the user stated that their date of birth is June 2000, but the artifact field asks for the date of birth in the format "YYYY-MM-DD", you should resume the conversation and ask the user for the day. + +Return only the action, either UPDATE_ARTIFACT(value) or RESUME_CONVERSATION, as your response. If you selected, UPDATE_ARTIFACT, make sure to replace "value" with the correct value. +""" + + +async def fix_artifact_error( + context: ContextProtocol, + openai_client: AsyncOpenAI | AsyncAzureOpenAI, + previous_attempts: str, + artifact_schema: str, + conversation: Conversation, + field_name: str, +) -> BaseEvent: + history = InMemoryMessageHistoryProvider(formatter=liquid_format) + history.append_system_message(ARTIFACT_ERROR_CORRECTION_SYSTEM_TEMPLATE) + history.append_user_message( + ( + "Conversation history:\n" + "{{ conversation_history }}\n\n" + "Schema:\n" + "{{ artifact_schema }}\n\n" + 'Previous attempts to update the field "{{ field_name }}" in the artifact:\n' + "{{ previous_attempts }}" + ), + { + "conversation_history": str(conversation.exclude([ConversationMessageType.REASONING])), + "artifact_schema": artifact_schema, + "field_name": field_name, + "previous_attempts": previous_attempts, + }, + ) + + config = ChatDriverConfig( + context=context, + openai_client=openai_client, + model="gpt-3.5-turbo", + message_provider=history, + ) + + chat_driver = ChatDriver(config) + return await chat_driver.respond() diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_update_agenda.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_update_agenda.py deleted file mode 100644 index fd5a5e23..00000000 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_update_agenda.py +++ /dev/null @@ -1,247 +0,0 @@ -import logging - -from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol -from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider -from chat_driver.message_formatter import liquid_format -from form_filler_skill.guided_conversation.agenda import Agenda -from form_filler_skill.guided_conversation.definition import GCDefinition -from form_filler_skill.guided_conversation.resources import GCResource, ResourceConstraintMode -from openai import AsyncAzureOpenAI, AsyncOpenAI - -from ..guided_conversation.artifact import Artifact - -logger = logging.getLogger(__name__) - -conversation_plan_template = """You are a helpful, thoughtful, and meticulous assistant. -You are conducting a conversation with a user. \ -Your goal is to complete an artifact as thoroughly as possible by the end of the conversation, and to ensure a -smooth experience for the user. - -This is the schema of the artifact you are completing: -{{ artifact_schema }}{% if context %} - -Here is some additional context about the conversation: -{{ context }}{% endif %} - -Throughout the conversation, you must abide by these rules: -{{ rules }}{% if current_state_description %} - -Here's a description of the conversation flow: -{{ current_state_description }} -Follow this description, and exercise good judgment about when it is appropriate to deviate.{% endif %} - -You will be provided the history of your conversation with the user up until now and the current state of the artifact. -Note that if the value for a field in the artifact is 'Unanswered', it means that the field has not been completed. -You need to select the best possible action(s), given the state of the conversation and the artifact. -These are the possible actions you can take: - -{% if show_agenda %}Update agenda (required parameters: items) -- If the latest agenda is set to "None", you should always pick this action. -- You should pick this action if you need to change your plan for the conversation to make the best use of the -remaining turns available to you. \ -Consider how long it usually takes to get the information you need (which is a function of the quality and pace of -the user's responses), \ -the number, complexity, and importance of the remaining fields in the artifact, and the number of turns remaining -({{ remaining_resource }}). \ -Based on these factors, you might need to accelerate (e.g. combine several topics) or slow down the conversation -(e.g. spread out a topic), in which case you should update the agenda accordingly. \ -Note that skipping an artifact field is NOT a valid way to accelerate the conversation. -- You must provide an ordered list of items to be completed sequentially, where the first item contains everything -you will do in the current turn of the conversation (in addition to updating the agenda). \ -For example, if you choose to send a message to the user asking for their name and medical history, then you would -write "ask for name and medical history" as the first item. \ -If you think medical history will take longer than asking for the name, then you would write -"complete medical history" as the second item, with an estimate of how many turns you think it will take. \ -Do NOT include items that have already been completed. \ -Items must always represent a conversation topic (corresponding to the "Send message to user" action). Updating the -artifact (e.g. "update field X based on the discussion") or terminating the conversation is NOT a valid item. -- The latest agenda was created in the previous turn of the conversation. \ -Even if the total turns in the latest agenda equals the remaining turns, you should still update the agenda if you -think the current plan is suboptimal (e.g. the first item was completed, the order of items is not ideal, an item is -too broad or not a conversation topic, etc.). -- Each item must have a description and and your best guess for the number of turns required to complete it. Do not -provide a range of turns. \ -It is EXTREMELY important that the total turns allocated across all items in the updated agenda (including the first -item for the current turn) {{ total_resource_str }} \ -Everything in the agenda should be something you expect to complete in the remaining turns - there shouldn't be any -optional "buffer" items. \ -It can be helpful to include the cumulative turns allocated for each item in the agenda to ensure you adhere to this -rule, e.g. item 1 = 2 turns (cumulative total = 2), item 2 = 4 turns (cumulative total = 6), etc. -- Avoid high-level items like "ask follow-up questions" - be specific about what you need to do. -- Do NOT include wrap-up items such as "review and confirm all information with the user" (you should be doing this -throughout the conversation) or "thank the user for their time". \ -Do NOT repeat topics that have already been sufficiently addressed. {{ ample_time_str }}{% endif %} - -Send message to user (required parameters: message) -- If there is no conversation history, you should always pick this action. -- You should pick this action if (a) the user asked a question or made a statement that you need to respond to, \ -or (b) you need to follow-up with the user because the information they provided is incomplete, invalid, ambiguous, -or in some way insufficient to complete the artifact. \ -For example, if the artifact schema indicates that the "date of birth" field must be in the format "YYYY-MM-DD", but -the user has only provided the month and year, you should send a message to the user asking for the day. \ -Likewise, if the user claims that their date of birth is February 30, you should send a message to the user asking -for a valid date. \ -If the artifact schema is open-ended (e.g. it asks you to rate how pressing the user's issue is, without specifying -rules for doing so), use your best judgment to determine whether you have enough information or you need to continue -probing the user. \ -It's important to be thorough, but also to avoid asking the user for unnecessary information. - -Update artifact fields (required parameters: field, value) -- You should pick this action as soon as (a) the user provides new information that is not already reflected in the -current state of the artifact and (b) you are able to submit a valid value for a field in the artifact using this new -information. \ -If you have already updated a field in the artifact and there is no new information to update the field with, you -should not pick this action. -- Make sure the value adheres to the constraints of the field as specified in the artifact schema. -- If the user has provided all required information to complete a field (i.e. the criteria for "Send message to user" -are not satisfied) but the information is in the wrong format, you should not ask the user to reformat their response. \ -Instead, you should simply update the field with the correctly formatted value. For example, if the artifact asks for -the date of birth in the format "YYYY-MM-DD", and the user provides their date of birth as "June 15, 2000", you should -update the field with the value "2000-06-15". -- Prioritize accuracy over completion. You should never make up information or make assumptions in order to complete -a field. \ -For example, if the field asks for a 10-digit phone number, and the user provided a 9-digit phone number, you should -not add a digit to the phone number in order to complete the field. \ -Instead, you should follow-up with the user to ask for the correct phone number. If they still aren't able to provide -one, you should leave the field unanswered. -- If the user isn't able to provide all of the information needed to complete a field, \ -use your best judgment to determine if a partial answer is appropriate (assuming it adheres to the formatting -requirements of the field). \ -For example, if the field asks for a description of symptoms along with details about when the symptoms started, but -the user isn't sure when their symptoms started, \ -it's better to record the information they do have rather than to leave the field unanswered (and to indicate that -the user was unsure about the start date). -- If it's possible to update multiple fields at once (assuming you're adhering to the above rules in all cases), you -should do so. \ -For example, if the user provides their full name and date of birth in the same message, you should select the -"update artifact fields" action twice, once for each field. - -End conversation (required parameters: None) -{{ termination_instructions }} -{{ resource_instructions }} - -If you select the "Update artifact field" action or the "Update agenda" action, you should also select one of the -"Send message to user" or "End conversation" actions. \ -Note that artifact and updates updates will always be executed before a message is sent to the user or the -conversation is terminated. \ -Also note that only one message can be sent to the user at a time. - -Your task is to state your step-by-step reasoning for the best possible action(s), followed by a final recommendation -of which action(s) to take, including all required parameters. -Someone else will be responsible for executing the action(s) you select and they will only have access to your output \ -(not any of the conversation history, artifact schema, or other context) so it is EXTREMELY important \ -that you clearly specify the value of all required parameters for each action you select. - -Conversation history: -{{ chat_history }} - -Latest agenda: -{{ agenda_state }} - -Current state of the artifact: -{{ artifact_state }}""" - - -def _get_termination_instructions(resource: GCResource): - """ - Get the termination instructions for the conversation. This is contingent on the resources mode, - if any, that is available. - - Assumes we're always using turns as the resource unit. - - Args: - resource (GCResource): The resource object. - - Returns: - str: the termination instructions - """ - # Termination condition under no resource constraints - if resource.resource_constraint is None: - return ( - "- You should pick this action as soon as you have completed the artifact to the best of your ability, the" - " conversation has come to a natural conclusion, or the user is not cooperating so you cannot continue the" - " conversation." - ) - - # Termination condition under exact resource constraints - if resource.resource_constraint.mode == ResourceConstraintMode.EXACT: - return ( - "- You should only pick this action if the user is not cooperating so you cannot continue the conversation." - ) - - # Termination condition under maximum resource constraints - elif resource.resource_constraint.mode == ResourceConstraintMode.MAXIMUM: - return ( - "- You should pick this action as soon as you have completed the artifact to the best of your ability, the" - " conversation has come to a natural conclusion, or the user is not cooperating so you cannot continue the" - " conversation." - ) - - else: - logger.error("Invalid resource mode provided.") - return "" - - -async def update_agenda( - context: ContextProtocol, - open_ai_client: AsyncOpenAI | AsyncAzureOpenAI, - definition: GCDefinition, - chat_history: str, - agenda: Agenda, - artifact: Artifact, - resource: GCResource, -): - remaining_resource = resource.remaining_units if resource.remaining_units else 0 - resource_instructions = resource.get_resource_instructions() - total_resource_str = "" - ample_time_str = "" - - # if there is a resource constraint and there's more than one turn left, include the update agenda action - if (resource_instructions != "") and (remaining_resource > 1): - if resource.get_resource_mode() == ResourceConstraintMode.MAXIMUM: - total_resource_str = f"does not exceed the remaining turns ({remaining_resource})." - ample_time_str = "" - elif resource.get_resource_mode() == ResourceConstraintMode.EXACT: - total_resource_str = ( - f"is equal to the remaining turns ({remaining_resource}). Do not leave any turns unallocated." - ) - ample_time_str = """If you have many turns remaining, instead of including wrap-up items or repeating - topics, you should include items that increase the breadth and/or depth of the conversation \ -in a way that's directly relevant to the artifact (e.g. "collect additional details about X", "ask for clarification -about Y", "explore related topic Z", etc.).""" - else: - logger.error("Invalid resource mode.") - else: - total_resource_str = "" - ample_time_str = "" - - history = InMemoryMessageHistoryProvider(formatter=liquid_format) - - history.append_system_message( - conversation_plan_template, - { - "context": definition.conversation_context, - "artifact_schema": definition.artifact_schema, - "rules": definition.rules, - "current_state_description": definition.conversation_flow, - "show_agenda": True, - "remaining_resource": remaining_resource, - "total_resource_str": total_resource_str, - "ample_time_str": ample_time_str, - "termination_instructions": _get_termination_instructions(resource), - "resource_instructions": resource_instructions, - "chat_history": chat_history, - "agenda_state": agenda.get_agenda_for_prompt(), - "artifact_state": artifact.get_artifact_for_prompt(), - }, - ) - - config = ChatDriverConfig( - context=context, - openai_client=open_ai_client, - model="gpt-3.5-turbo", - message_provider=history, - ) - - chat_driver = ChatDriver(config) - return await chat_driver.respond() diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action.py new file mode 100644 index 00000000..24a2fee3 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action.py @@ -0,0 +1,248 @@ +import logging + +from chat_driver import ChatDriver, ChatDriverConfig +from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider +from chat_driver.message_formatter import liquid_format +from form_filler_skill.agenda import Agenda, AgendaItem +from form_filler_skill.definition import GCDefinition +from form_filler_skill.message import Conversation +from form_filler_skill.resources import ( + GCResource, + ResourceConstraintMode, + ResourceConstraintUnit, + format_resource, +) +from openai import AsyncAzureOpenAI, AsyncOpenAI +from pydantic import ValidationError +from skill_library.run_context import RunContext + +from ...artifact import Artifact +from ..fix_agenda_error import fix_agenda_error +from ..update_agenda_template import update_agenda_template + +logger = logging.getLogger(__name__) + + +def _get_termination_instructions(resource: GCResource): + """ + Get the termination instructions for the conversation. This is contingent on + the resources mode, if any, that is available. Assumes we're always using + turns as the resource unit. + """ + # Termination condition under no resource constraints + if resource.resource_constraint is None: + return ( + "- You should pick this action as soon as you have completed the artifact to the best of your ability, the" + " conversation has come to a natural conclusion, or the user is not cooperating so you cannot continue the" + " conversation." + ) + + # Termination condition under exact resource constraints + if resource.resource_constraint.mode == ResourceConstraintMode.EXACT: + return "- You should only pick this action if the user is not cooperating so you cannot continue the conversation." + + # Termination condition under maximum resource constraints + elif resource.resource_constraint.mode == ResourceConstraintMode.MAXIMUM: + return ( + "- You should pick this action as soon as you have completed the artifact to the best of your ability, the" + " conversation has come to a natural conclusion, or the user is not cooperating so you cannot continue the" + " conversation." + ) + + else: + logger.error("Invalid resource mode provided.") + return "" + + +async def update_agenda( + context: RunContext, + openai_client: AsyncOpenAI | AsyncAzureOpenAI, + definition: GCDefinition, + chat_history: Conversation, + agenda: Agenda, + artifact: Artifact, + resource: GCResource, +) -> bool: + # STEP 1: Generate an updated agenda. + + # If there is a resource constraint and there's more than one turn left, + # include additional constraint instructions. + remaining_resource = resource.remaining_units if resource.remaining_units else 0 + resource_instructions = resource.get_resource_instructions() + if (resource_instructions != "") and (remaining_resource > 1): + match resource.get_resource_mode(): + case ResourceConstraintMode.MAXIMUM: + total_resource_str = f"does not exceed the remaining turns ({remaining_resource})." + ample_time_str = "" + case ResourceConstraintMode.EXACT: + total_resource_str = f"is equal to the remaining turns ({remaining_resource}). Do not leave any turns unallocated." + ample_time_str = ( + "If you have many turns remaining, instead of including wrap-up items or repeating " + "topics, you should include items that increase the breadth and/or depth of the conversation " + 'in a way that\'s directly relevant to the artifact (e.g. "collect additional details about X", ' + '"ask for clarification about Y", "explore related topic Z", etc.).' + ) + case _: + logger.error("Invalid resource mode.") + else: + total_resource_str = "" + ample_time_str = "" + + history = InMemoryMessageHistoryProvider(formatter=liquid_format) + history.append_system_message( + update_agenda_template, + { + "context": definition.conversation_context, + "artifact_schema": definition.artifact_schema, + "rules": definition.rules, + "current_state_description": definition.conversation_flow, + "show_agenda": True, + "remaining_resource": remaining_resource, + "total_resource_str": total_resource_str, + "ample_time_str": ample_time_str, + "termination_instructions": _get_termination_instructions(resource), + "resource_instructions": resource_instructions, + }, + ) + history.append_user_message( + ( + "Conversation history:\n" + "{{ chat_history }}\n\n" + "Latest agenda:\n" + "{{ agenda_state }}\n\n" + "Current state of the artifact:\n" + "{{ artifact_state }}" + ), + { + "chat_history": str(chat_history), + "agenda_state": get_agenda_for_prompt(agenda), + "artifact_state": artifact.get_artifact_for_prompt(), + }, + ) + + config = ChatDriverConfig( + context=context, + openai_client=openai_client, + model="gpt-4o", + message_provider=history, + ) + + chat_driver = ChatDriver(config) + response = await chat_driver.respond() + items = response.message + + # STEP 2: Validate/fix the updated agenda. + + previous_attempts = [] + while True: + try: + # Pydantic type validation. + agenda.items = items # type: ignore + + # Check resource constraints. + if agenda.resource_constraint_mode is not None: + check_item_constraints( + agenda.resource_constraint_mode, + agenda.items, + resource.estimate_remaining_turns(), + ) + + logger.info(f"Agenda updated successfully: {get_agenda_for_prompt(agenda)}") + return True + + except (ValidationError, ValueError) as e: + # If we have reached the maximum number of retries return a failure. + if len(previous_attempts) >= agenda.max_agenda_retries: + logger.warning( + f"Failed to update agenda after {agenda.max_agenda_retries} attempts." + ) + return False + + # Otherwise, get an error string. + if isinstance(e, ValidationError): + error_str = "; ".join([e.get("msg") for e in e.errors()]) + error_str = error_str.replace( + "; Input should be 'Unanswered'", " or input should be 'Unanswered'" + ) + else: + error_str = str(e) + + # Add it to our list of previous attempts. + previous_attempts.append((str(items), error_str)) + + # And try again. + logger.info(f"Attempting to fix the agenda error. Attempt {len(previous_attempts)}.") + llm_formatted_attempts = "\n".join([ + f"Attempt: {attempt}\nError: {error}" for attempt, error in previous_attempts + ]) + response = await fix_agenda_error( + context, openai_client, llm_formatted_attempts, chat_history + ) + + # Now, update the items with the corrected agenda and try to + # validate again. + items = response.message + + +def check_item_constraints( + resource_constraint_mode: ResourceConstraintMode, + items: list[AgendaItem], + remaining_turns: int, +) -> None: + """ + Validates if any constraints were violated while performing the agenda + update. + """ + # The total, proposed allocation of resources. + total_resources = sum([item.resource for item in items]) + + violations = [] + # In maximum mode, the total resources should not exceed the remaining + # turns. + if (resource_constraint_mode == ResourceConstraintMode.MAXIMUM) and ( + total_resources > remaining_turns + ): + violations.append( + "The total turns allocated in the agenda " + f"must not exceed the remaining amount ({remaining_turns}); " + f"but the current total is {total_resources}." + ) + + # In exact mode if the total resources were not exactly equal to the + # remaining turns. + if (resource_constraint_mode == ResourceConstraintMode.EXACT) and ( + total_resources != remaining_turns + ): + violations.append( + "The total turns allocated in the agenda " + f"must equal the remaining amount ({remaining_turns}); " + f"but the current total is {total_resources}." + ) + + # Check if any item has a resource value of 0. + if any(item.resource <= 0 for item in items): + violations.append("All items must have a resource value greater than 0.") + + # Raise an error if any violations were found. + if len(violations) > 0: + logger.debug(f"Agenda update failed due to the following violations: {violations}.") + raise ValueError(" ".join(violations)) + + +def get_agenda_for_prompt(agenda: Agenda) -> str: + """ + Gets a string representation of the agenda for use in an LLM prompt. + """ + agenda_json = agenda.model_dump() + agenda_items = agenda_json.get("items", []) + if len(agenda_items) == 0: + return "None" + agenda_str = "\n".join([ + f"{i + 1}. [{format_resource(item['resource'], ResourceConstraintUnit.TURNS)}] {item['title']}" + for i, item in enumerate(agenda_items) + ]) + total_resource = format_resource( + sum([item["resource"] for item in agenda_items]), ResourceConstraintUnit.TURNS + ) + agenda_str += f"\nTotal = {total_resource}" + return agenda_str diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action_template.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action_template.py new file mode 100644 index 00000000..3e533f63 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action_template.py @@ -0,0 +1,52 @@ +update_agenda_template = """You are a helpful, thoughtful, and meticulous assistant. You are conducting a conversation with a user. Your goal is to complete an artifact as thoroughly as possible by the end of the conversation, and to ensure a smooth experience for the user. + +This is the schema of the artifact you are completing: +{{ artifact_schema }}{% if context %} + +Here is some additional context about the conversation: +{{ context }}{% endif %} + +Throughout the conversation, you must abide by these rules: +{{ rules }}{% if current_state_description %} + +Here's a description of the conversation flow: +{{ current_state_description }} +Follow this description, and exercise good judgment about when it is appropriate to deviate.{% endif %} + +You will be provided the history of your conversation with the user up until now and the current state of the artifact. +Note that if the value for a field in the artifact is 'Unanswered', it means that the field has not been completed. +You need to select the best possible action(s), given the state of the conversation and the artifact. + +These are the possible actions you can take: + +{% if show_agenda %}Update agenda (required parameters: items) +- If the latest agenda is set to "None", you should always pick this action. +- You should pick this action if you need to change your plan for the conversation to make the best use of the remaining turns available to you. Consider how long it usually takes to get the information you need (which is a function of the quality and pace of the user's responses), the number, complexity, and importance of the remaining fields in the artifact, and the number of turns remaining ({{ remaining_resource }}). Based on these factors, you might need to accelerate (e.g. combine several topics) or slow down the conversation (e.g. spread out a topic), in which case you should update the agenda accordingly. Note that skipping an artifact field is NOT a valid way to accelerate the conversation. +- You must provide an ordered list of items to be completed sequentially, where the first item contains everything you will do in the current turn of the conversation (in addition to updating the agenda). For example, if you choose to send a message to the user asking for their name and medical history, then you would write "ask for name and medical history" as the first item. If you think medical history will take longer than asking for the name, then you would write "complete medical history" as the second item, with an estimate of how many turns you think it will take. Do NOT include items that have already been completed. Items must always represent a conversation topic (corresponding to the "Send message to user" action). Updating the artifact (e.g. "update field X based on the discussion") or terminating the conversation is NOT a valid item. +- The latest agenda was created in the previous turn of the conversation. Even if the total turns in the latest agenda equals the remaining turns, you should still update the agenda if you +think the current plan is suboptimal (e.g. the first item was completed, the order of items is not ideal, an item is too broad or not a conversation topic, etc.). +- Each item must have a description and and your best guess for the number of turns required to complete it. Do not provide a range of turns. It is EXTREMELY important that the total turns allocated across all items in the updated agenda (including the first item for the current turn) {{ total_resource_str }} Everything in the agenda should be something you expect to complete in the remaining turns - there shouldn't be any optional "buffer" items. It can be helpful to include the cumulative turns allocated for each item in the agenda to ensure you adhere to this rule, e.g. item 1 = 2 turns (cumulative total = 2), item 2 = 4 turns (cumulative total = 6), etc. +- Avoid high-level items like "ask follow-up questions" - be specific about what you need to do. +- Do NOT include wrap-up items such as "review and confirm all information with the user" (you should be doing this throughout the conversation) or "thank the user for their time". Do NOT repeat topics that have already been sufficiently addressed. {{ ample_time_str }}{% endif %} + +Send message to user (required parameters: message) +- If there is no conversation history, you should always pick this action. +- You should pick this action if (a) the user asked a question or made a statement that you need to respond to, or (b) you need to follow-up with the user because the information they provided is incomplete, invalid, ambiguous, or in some way insufficient to complete the artifact. For example, if the artifact schema indicates that the "date of birth" field must be in the format "YYYY-MM-DD", but the user has only provided the month and year, you should send a message to the user asking for the day. Likewise, if the user claims that their date of birth is February 30, you should send a message to the user asking for a valid date. If the artifact schema is open-ended (e.g. it asks you to rate how pressing the user's issue is, without specifying rules for doing so), use your best judgment to determine whether you have enough information or you need to continue probing the user. It's important to be thorough, but also to avoid asking the user for unnecessary information. + +Update artifact fields (required parameters: field, value) +- You should pick this action as soon as (a) the user provides new information that is not already reflected in the current state of the artifact and (b) you are able to submit a valid value for a field in the artifact using this new information. If you have already updated a field in the artifact and there is no new information to update the field with, you should not pick this action. +- Make sure the value adheres to the constraints of the field as specified in the artifact schema. +- If the user has provided all required information to complete a field (i.e. the criteria for "Send message to user" are not satisfied) but the information is in the wrong format, you should not ask the user to reformat their response. Instead, you should simply update the field with the correctly formatted value. For example, if the artifact asks for the date of birth in the format "YYYY-MM-DD", and the user provides their date of birth as "June 15, 2000", you should update the field with the value "2000-06-15". +- Prioritize accuracy over completion. You should never make up information or make assumptions in order to complete a field. For example, if the field asks for a 10-digit phone number, and the user provided a 9-digit phone number, you should not add a digit to the phone number in order to complete the field. Instead, you should follow-up with the user to ask for the correct phone number. If they still aren't able to provide one, you should leave the field unanswered. +- If the user isn't able to provide all of the information needed to complete a field, use your best judgment to determine if a partial answer is appropriate (assuming it adheres to the formatting requirements of the field). For example, if the field asks for a description of symptoms along with details about when the symptoms started, but the user isn't sure when their symptoms started, it's better to record the information they do have rather than to leave the field unanswered (and to indicate that the user was unsure about the start date). +- If it's possible to update multiple fields at once (assuming you're adhering to the above rules in all cases), you should do so. For example, if the user provides their full name and date of birth in the same message, you should select the "update artifact fields" action twice, once for each field. + +End conversation (required parameters: None) +{{ termination_instructions }} +{{ resource_instructions }} + +If you select the "Update artifact field" action or the "Update agenda" action, you should also select one of the "Send message to user" or "End conversation" actions. Note that artifact and updates updates will always be executed before a message is sent to the user or the +conversation is terminated. Also note that only one message can be sent to the user at a time. + +Your task is to state your step-by-step reasoning for the best possible action(s), followed by a final recommendation of which action(s) to take, including all required parameters. Someone else will be responsible for executing the action(s) you select and they will only have access to your output (not any of the conversation history, artifact schema, or other context) so it is EXTREMELY important that you clearly specify the value of all required parameters for each action you select. +""" diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/execute_reasoning.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/execute_reasoning.py new file mode 100644 index 00000000..48d48750 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/execute_reasoning.py @@ -0,0 +1,61 @@ +import logging + +from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider +from chat_driver.message_formatter import liquid_format +from openai import AsyncAzureOpenAI, AsyncOpenAI + +logger = logging.getLogger(__name__) + +SYSTEM_TEMPLATE = """You are a helpful, thoughtful, and meticulous assistant. You are conducting a conversation with a user. Your goal is to complete an artifact as thoroughly as possible by the end of the conversation. + +You will be given some reasoning about the best possible action(s) to take next given the state of the conversation as well as the artifact schema. + +The reasoning is supposed to state the recommended action(s) to take next, along with all required parameters for each action. + +Your task is to execute ALL actions recommended in the reasoning in the order they are listed. +If the reasoning's specification of an action is incomplete (e.g. it doesn't include all required parameters for the action, or some parameters are specified implicitly, such as "send a message that contains a greeting" instead of explicitly providing the value of the "message" parameter), do not execute the action. You should never fill in missing or imprecise +parameters yourself. + +If the reasoning is not clear about which actions to take, or all actions are specified in an incomplete way, return 'None' without selecting any action.""" + +USER_TEMPLATE = """Artifact schema: +{{ artifact_schema }} + +If the type in the schema is str, the "field_value" parameter in the action should be also be a string. +These are example parameters for the update_artifact action: {"field_name": "company_name", "field_value": "Contoso"} +DO NOT write JSON in the "field_value" parameter in this case. +{"field_name": "company_name", "field_value": "{"value": "Contoso"}"} is INCORRECT. + +Reasoning: +{{ reasoning }}""" + + +async def execute_reasoning( + context: ContextProtocol, + open_ai_client: AsyncOpenAI | AsyncAzureOpenAI, + reasoning: str, + artifact_schema: str, +): + history = InMemoryMessageHistoryProvider(formatter=liquid_format) + + history.append_system_message( + SYSTEM_TEMPLATE, + ) + history.append_user_message( + USER_TEMPLATE, + { + "artifact_schema": artifact_schema, + "reasoning": reasoning, + }, + ) + + config = ChatDriverConfig( + context=context, + openai_client=open_ai_client, + model="gpt-3.5-turbo", + message_provider=history, + ) + + chat_driver = ChatDriver(config) + return await chat_driver.respond() diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_agenda.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_agenda.py index e69de29b..2f99a17b 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_agenda.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_agenda.py @@ -0,0 +1,140 @@ +import logging + +from form_filler_skill.agenda import Agenda, AgendaItem +from form_filler_skill.message import Conversation +from form_filler_skill.resources import ( + GCResource, + ResourceConstraintMode, + ResourceConstraintUnit, + format_resource, +) +from openai import AsyncAzureOpenAI, AsyncOpenAI +from pydantic import ValidationError +from skill_library.run_context import RunContext + +from .fix_agenda_error import fix_agenda_error + +logger = logging.getLogger(__name__) + + +async def update_agenda( + context: RunContext, + openai_client: AsyncOpenAI | AsyncAzureOpenAI, + items: str, + chat_history: Conversation, + agenda: Agenda, + resource: GCResource, +) -> bool: + previous_attempts = [] + while True: + try: + # Pydantic type validation. + agenda.items = items # type: ignore + + # Check resource constraints. + if agenda.resource_constraint_mode is not None: + check_item_constraints( + agenda.resource_constraint_mode, + agenda.items, + resource.estimate_remaining_turns(), + ) + + logger.info(f"Agenda updated successfully: {get_agenda_for_prompt(agenda)}") + return True + + except (ValidationError, ValueError) as e: + # If we have reached the maximum number of retries return a failure. + if len(previous_attempts) >= agenda.max_agenda_retries: + logger.warning( + f"Failed to update agenda after {agenda.max_agenda_retries} attempts." + ) + return False + + # Otherwise, get an error string. + if isinstance(e, ValidationError): + error_str = "; ".join([e.get("msg") for e in e.errors()]) + error_str = error_str.replace( + "; Input should be 'Unanswered'", " or input should be 'Unanswered'" + ) + else: + error_str = str(e) + + # Add it to our list of previous attempts. + previous_attempts.append((str(items), error_str)) + + # And try again. + logger.info(f"Attempting to fix the agenda error. Attempt {len(previous_attempts)}.") + llm_formatted_attempts = "\n".join([ + f"Attempt: {attempt}\nError: {error}" for attempt, error in previous_attempts + ]) + response = await fix_agenda_error( + context, openai_client, llm_formatted_attempts, chat_history + ) + + # Now, update the items with the corrected agenda and try to + # validate again. + items = response.message or "" + + +def check_item_constraints( + resource_constraint_mode: ResourceConstraintMode, + items: list[AgendaItem], + remaining_turns: int, +) -> None: + """ + Validates if any constraints were violated while performing the agenda + update. + """ + # The total, proposed allocation of resources. + total_resources = sum([item.resource for item in items]) + + violations = [] + # In maximum mode, the total resources should not exceed the remaining + # turns. + if (resource_constraint_mode == ResourceConstraintMode.MAXIMUM) and ( + total_resources > remaining_turns + ): + violations.append( + "The total turns allocated in the agenda " + f"must not exceed the remaining amount ({remaining_turns}); " + f"but the current total is {total_resources}." + ) + + # In exact mode if the total resources were not exactly equal to the + # remaining turns. + if (resource_constraint_mode == ResourceConstraintMode.EXACT) and ( + total_resources != remaining_turns + ): + violations.append( + "The total turns allocated in the agenda " + f"must equal the remaining amount ({remaining_turns}); " + f"but the current total is {total_resources}." + ) + + # Check if any item has a resource value of 0. + if any(item.resource <= 0 for item in items): + violations.append("All items must have a resource value greater than 0.") + + # Raise an error if any violations were found. + if len(violations) > 0: + logger.debug(f"Agenda update failed due to the following violations: {violations}.") + raise ValueError(" ".join(violations)) + + +def get_agenda_for_prompt(agenda: Agenda) -> str: + """ + Gets a string representation of the agenda for use in an LLM prompt. + """ + agenda_json = agenda.model_dump() + agenda_items = agenda_json.get("items", []) + if len(agenda_items) == 0: + return "None" + agenda_str = "\n".join([ + f"{i + 1}. [{format_resource(item['resource'], ResourceConstraintUnit.TURNS)}] {item['title']}" + for i, item in enumerate(agenda_items) + ]) + total_resource = format_resource( + sum([item["resource"] for item in agenda_items]), ResourceConstraintUnit.TURNS + ) + agenda_str += f"\nTotal = {total_resource}" + return agenda_str diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_agenda_template.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_agenda_template.py new file mode 100644 index 00000000..5bf468ce --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_agenda_template.py @@ -0,0 +1,31 @@ +update_agenda_template = """You are a helpful, thoughtful, and meticulous assistant. You are conducting a conversation with a user. Your goal is to complete an artifact as thoroughly as possible by the end of the conversation, and to ensure a smooth experience for the user. + +This is the schema of the artifact you are completing: +{{ artifact_schema }}{% if context %} + +Here is some additional context about the conversation: +{{ context }}{% endif %} + +Throughout the conversation, you must abide by these rules: +{{ rules }}{% if current_state_description %} + +Here's a description of the conversation flow: +{{ current_state_description }} +Follow this description, and exercise good judgment about when it is appropriate to deviate.{% endif %} + +You will be provided the history of your conversation with the user up until now and the current state of the artifact. +Note that if the value for a field in the artifact is 'Unanswered', it means that the field has not been completed. +You need to select the best possible action(s), given the state of the conversation and the artifact. + +Here is the action to take: + +- If the latest agenda is set to "None", you should always pick this action. +- You should pick this action if you need to change your plan for the conversation to make the best use of the remaining turns available to you. Consider how long it usually takes to get the information you need (which is a function of the quality and pace of the user's responses), the number, complexity, and importance of the remaining fields in the artifact, and the number of turns remaining ({{ remaining_resource }}). Based on these factors, you might need to accelerate (e.g. combine several topics) or slow down the conversation (e.g. spread out a topic), in which case you should update the agenda accordingly. Note that skipping an artifact field is NOT a valid way to accelerate the conversation. +- You must provide an ordered list of items to be completed sequentially, where the first item contains everything you will do in the current turn of the conversation (in addition to updating the agenda). For example, if you choose to send a message to the user asking for their name and medical history, then you would write "ask for name and medical history" as the first item. If you think medical history will take longer than asking for the name, then you would write "complete medical history" as the second item, with an estimate of how many turns you think it will take. Do NOT include items that have already been completed. Items must always represent a conversation topic (corresponding to the "Send message to user" action). Updating the artifact (e.g. "update field X based on the discussion") or terminating the conversation is NOT a valid item. +- The latest agenda was created in the previous turn of the conversation. Even if the total turns in the latest agenda equals the remaining turns, you should still update the agenda if you +think the current plan is suboptimal (e.g. the first item was completed, the order of items is not ideal, an item is too broad or not a conversation topic, etc.). +- Each item must have a description and and your best guess for the number of turns required to complete it. Do not provide a range of turns. It is EXTREMELY important that the total turns allocated across all items in the updated agenda (including the first item for the current turn) {{ total_resource_str }} Everything in the agenda should be something you expect to complete in the remaining turns - there shouldn't be any optional "buffer" items. It can be helpful to include the cumulative turns allocated for each item in the agenda to ensure you adhere to this rule, e.g. item 1 = 2 turns (cumulative total = 2), item 2 = 4 turns (cumulative total = 6), etc. +- Avoid high-level items like "ask follow-up questions" - be specific about what you need to do. +- Do NOT include wrap-up items such as "review and confirm all information with the user" (you should be doing this throughout the conversation) or "thank the user for their time". Do NOT repeat topics that have already been sufficiently addressed. {{ ample_time_str }}{% endif %} + +""" diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact.py new file mode 100644 index 00000000..44b50a4d --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact.py @@ -0,0 +1,219 @@ +import logging + +from chat_driver import ChatDriver, ChatDriverConfig +from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider +from chat_driver.message_formatter import liquid_format +from form_filler_skill.agenda import Agenda, AgendaItem +from form_filler_skill.definition import GCDefinition +from form_filler_skill.message import Conversation +from form_filler_skill.resources import ( + GCResource, + ResourceConstraintMode, + ResourceConstraintUnit, + format_resource, +) +from openai import AsyncAzureOpenAI, AsyncOpenAI +from pydantic import ValidationError +from skill_library.run_context import RunContext + +from ..artifact import Artifact +from .fix_agenda_error import fix_agenda_error +from .update_artifact_template import update_artifact_template + +logger = logging.getLogger(__name__) + + +def _get_termination_instructions(resource: GCResource): + """ + Get the termination instructions for the conversation. This is contingent on + the resources mode, if any, that is available. Assumes we're always using + turns as the resource unit. + """ + # Termination condition under no resource constraints + if resource.resource_constraint is None: + return ( + "- You should pick this action as soon as you have completed the artifact to the best of your ability, the" + " conversation has come to a natural conclusion, or the user is not cooperating so you cannot continue the" + " conversation." + ) + + # Termination condition under exact resource constraints + if resource.resource_constraint.mode == ResourceConstraintMode.EXACT: + return "- You should only pick this action if the user is not cooperating so you cannot continue the conversation." + + # Termination condition under maximum resource constraints + elif resource.resource_constraint.mode == ResourceConstraintMode.MAXIMUM: + return ( + "- You should pick this action as soon as you have completed the artifact to the best of your ability, the" + " conversation has come to a natural conclusion, or the user is not cooperating so you cannot continue the" + " conversation." + ) + + else: + logger.error("Invalid resource mode provided.") + return "" + + +async def update_agenda( + context: RunContext, + openai_client: AsyncOpenAI | AsyncAzureOpenAI, + definition: GCDefinition, + chat_history: Conversation, + agenda: Agenda, + artifact: Artifact, + resource: GCResource, +) -> bool: + # STEP 1: Generate an updated agenda. + + history = InMemoryMessageHistoryProvider(formatter=liquid_format) + history.append_system_message( + update_artifact_template, + { + "context": definition.conversation_context, + "artifact_schema": definition.artifact_schema, + "rules": definition.rules, + "current_state_description": definition.conversation_flow, + }, + ) + history.append_user_message( + ( + "Conversation history:\n" + "{{ chat_history }}\n\n" + "Latest agenda:\n" + "{{ agenda_state }}\n\n" + "Current state of the artifact:\n" + "{{ artifact_state }}" + ), + { + "chat_history": str(chat_history), + "agenda_state": get_agenda_for_prompt(agenda), + "artifact_state": artifact.get_artifact_for_prompt(), + }, + ) + + config = ChatDriverConfig( + context=context, + openai_client=openai_client, + model="gpt-4o", + message_provider=history, + ) + + chat_driver = ChatDriver(config) + response = await chat_driver.respond() + items = response.message + + # STEP 2: Validate/fix the updated agenda. + + previous_attempts = [] + while True: + try: + # Pydantic type validation. + agenda.items = items # type: ignore + + # Check resource constraints. + if agenda.resource_constraint_mode is not None: + check_item_constraints( + agenda.resource_constraint_mode, + agenda.items, + resource.estimate_remaining_turns(), + ) + + logger.info(f"Agenda updated successfully: {get_agenda_for_prompt(agenda)}") + return True + + except (ValidationError, ValueError) as e: + # If we have reached the maximum number of retries return a failure. + if len(previous_attempts) >= agenda.max_agenda_retries: + logger.warning( + f"Failed to update agenda after {agenda.max_agenda_retries} attempts." + ) + return False + + # Otherwise, get an error string. + if isinstance(e, ValidationError): + error_str = "; ".join([e.get("msg") for e in e.errors()]) + error_str = error_str.replace( + "; Input should be 'Unanswered'", " or input should be 'Unanswered'" + ) + else: + error_str = str(e) + + # Add it to our list of previous attempts. + previous_attempts.append((str(items), error_str)) + + # And try again. + logger.info(f"Attempting to fix the agenda error. Attempt {len(previous_attempts)}.") + llm_formatted_attempts = "\n".join([ + f"Attempt: {attempt}\nError: {error}" for attempt, error in previous_attempts + ]) + response = await fix_agenda_error( + context, openai_client, llm_formatted_attempts, chat_history + ) + + # Now, update the items with the corrected agenda and try to + # validate again. + items = response.message + + +def check_item_constraints( + resource_constraint_mode: ResourceConstraintMode, + items: list[AgendaItem], + remaining_turns: int, +) -> None: + """ + Validates if any constraints were violated while performing the agenda + update. + """ + # The total, proposed allocation of resources. + total_resources = sum([item.resource for item in items]) + + violations = [] + # In maximum mode, the total resources should not exceed the remaining + # turns. + if (resource_constraint_mode == ResourceConstraintMode.MAXIMUM) and ( + total_resources > remaining_turns + ): + violations.append( + "The total turns allocated in the agenda " + f"must not exceed the remaining amount ({remaining_turns}); " + f"but the current total is {total_resources}." + ) + + # In exact mode if the total resources were not exactly equal to the + # remaining turns. + if (resource_constraint_mode == ResourceConstraintMode.EXACT) and ( + total_resources != remaining_turns + ): + violations.append( + "The total turns allocated in the agenda " + f"must equal the remaining amount ({remaining_turns}); " + f"but the current total is {total_resources}." + ) + + # Check if any item has a resource value of 0. + if any(item.resource <= 0 for item in items): + violations.append("All items must have a resource value greater than 0.") + + # Raise an error if any violations were found. + if len(violations) > 0: + logger.debug(f"Agenda update failed due to the following violations: {violations}.") + raise ValueError(" ".join(violations)) + + +def get_agenda_for_prompt(agenda: Agenda) -> str: + """ + Gets a string representation of the agenda for use in an LLM prompt. + """ + agenda_json = agenda.model_dump() + agenda_items = agenda_json.get("items", []) + if len(agenda_items) == 0: + return "None" + agenda_str = "\n".join([ + f"{i + 1}. [{format_resource(item['resource'], ResourceConstraintUnit.TURNS)}] {item['title']}" + for i, item in enumerate(agenda_items) + ]) + total_resource = format_resource( + sum([item["resource"] for item in agenda_items]), ResourceConstraintUnit.TURNS + ) + agenda_str += f"\nTotal = {total_resource}" + return agenda_str diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact_template.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact_template.py new file mode 100644 index 00000000..33d8e454 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact_template.py @@ -0,0 +1,32 @@ +update_artifact_template = """You are a helpful, thoughtful, and meticulous assistant. You are conducting a conversation with a user. Your goal is to complete an artifact as thoroughly as possible by the end of the conversation, and to ensure a smooth experience for the user. + +This is the schema of the artifact you are completing: +{{ artifact_schema }}{% if context %} + +Here is some additional context about the conversation: +{{ context }}{% endif %} + +Throughout the conversation, you must abide by these rules: +{{ rules }}{% if current_state_description %} + +Here's a description of the conversation flow: +{{ current_state_description }} +Follow this description, and exercise good judgment about when it is appropriate to deviate.{% endif %} + +You will be provided the history of your conversation with the user up until now and the current state of the artifact. +Note that if the value for a field in the artifact is 'Unanswered', it means that the field has not been completed. +You need to select the best possible action(s), given the state of the conversation and the artifact. + +Your job is to create a list of field updates to update the artifact. Each update should be listed as: + +update_artifact_field(required parameters: field, value) + +- You should pick this action as soon as (a) the user provides new information that is not already reflected in the current state of the artifact and (b) you are able to submit a valid value for a field in the artifact using this new information. If you have already updated a field in the artifact and there is no new information to update the field with, you should not pick this action. +- Make sure the value adheres to the constraints of the field as specified in the artifact schema. +- If the user has provided all required information to complete a field (i.e. the criteria for "Send message to user" are not satisfied) but the information is in the wrong format, you should not ask the user to reformat their response. Instead, you should simply update the field with the correctly formatted value. For example, if the artifact asks for the date of birth in the format "YYYY-MM-DD", and the user provides their date of birth as "June 15, 2000", you should update the field with the value "2000-06-15". +- Prioritize accuracy over completion. You should never make up information or make assumptions in order to complete a field. For example, if the field asks for a 10-digit phone number, and the user provided a 9-digit phone number, you should not add a digit to the phone number in order to complete the field. Instead, you should follow-up with the user to ask for the correct phone number. If they still aren't able to provide one, you should leave the field unanswered. +- If the user isn't able to provide all of the information needed to complete a field, use your best judgment to determine if a partial answer is appropriate (assuming it adheres to the formatting requirements of the field). For example, if the field asks for a description of symptoms along with details about when the symptoms started, but the user isn't sure when their symptoms started, it's better to record the information they do have rather than to leave the field unanswered (and to indicate that the user was unsure about the start date). +- If it's possible to update multiple fields at once (assuming you're adhering to the above rules in all cases), you should do so. For example, if the user provides their full name and date of birth in the same message, you should select the "update artifact fields" action twice, once for each field. + +Your task is to state your step-by-step reasoning for the best possible action(s), followed by a final recommendation of which update(s) to make, including all required parameters. Someone else will be responsible for executing the update(s) you select and they will only have access to your output (not any of the conversation history, artifact schema, or other context) so it is EXTREMELY important that you clearly specify the value of all required parameters for each update you make. +""" diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/definition.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/definition.py new file mode 100644 index 00000000..b2480218 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/definition.py @@ -0,0 +1,14 @@ +from dataclasses import dataclass +from typing import Optional + +from form_filler_skill.resources import ResourceConstraint + + +@dataclass +class GCDefinition: + artifact_schema: str + rules: str + conversation_flow: Optional[str] + conversation_context: str + resource_constraint: Optional[ResourceConstraint] + service_id: str = "gc_main" diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/agenda.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/agenda.py index 0bf202fd..9d5623e9 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/agenda.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/agenda.py @@ -1,208 +1,24 @@ -# FIXME: Copied code from Semantic Kernel repo, using as-is despite type errors -# TODO: Search for and find the `# type: ignore` comments in the copied code and remove them - import logging -from typing import Annotated -from context import ContextProtocol -from openai import AsyncAzureOpenAI, AsyncOpenAI -from pydantic import Field, ValidationError +from pydantic import Field -from form_filler_skill.chat_drivers.gc_fix_agenda_error import fix_agenda_error -from form_filler_skill.guided_conversation.base_model_llm import BaseModelLLM -from form_filler_skill.guided_conversation.conversation_helpers import Conversation -from form_filler_skill.guided_conversation.openai_tool_calling import ToolValidationResult -from form_filler_skill.guided_conversation.plugin_helpers import PluginOutput, update_attempts -from form_filler_skill.guided_conversation.resources import ( +from form_filler_skill.base_model_llm import BaseModelLLM +from form_filler_skill.resources import ( ResourceConstraintMode, - ResourceConstraintUnit, - format_resource, ) logger = logging.getLogger(__name__) -UPDATE_AGENDA_TOOL = "update_agenda" - - -class _BaseAgendaItem(BaseModelLLM): +class AgendaItem(BaseModelLLM): title: str = Field(description="Brief description of the item") resource: int = Field(description="Number of turns required for the item") -class _BaseAgenda(BaseModelLLM): - items: list[_BaseAgendaItem] = Field( +class Agenda(BaseModelLLM): + resource_constraint_mode: ResourceConstraintMode | None = Field(default=None) + max_agenda_retries: int = Field(default=2) + items: list[AgendaItem] = Field( description="Ordered list of items to be completed in the remainder of the conversation", default_factory=list, ) - - -class Agenda: - """An abstraction to manage a conversation agenda. The expected use case is that another agent will generate an agenda. - This class will validate if it is valid, and help correct it if it is not. - - Args: - kernel (Kernel): The Semantic Kernel instance to use for calling the LLM. Don't forget to set your - req_settings since this class uses tool calling functionality from the Semantic Kernel. - service_id (str): The service ID to use for the Semantic Kernel tool calling. One kernel can have multiple - services. The service ID is used to identify which service to use for LLM calls. The Agenda object - assumes that the service has tool calling capabilities and is some flavor of chat completion. - resource_constraint_mode (ResourceConstraintMode): The mode for resource constraints. - max_agenda_retries (int): The maximum number of retries for updating the agenda. - """ - - def __init__( - self, - service_id: str, - resource_constraint_mode: ResourceConstraintMode | None, - max_agenda_retries: int = 2, - ) -> None: - self.id = "agenda_plugin" - self.service_id = service_id - - self.resource_constraint_mode = resource_constraint_mode - self.max_agenda_retries = max_agenda_retries - - self.agenda = _BaseAgenda() - - async def update_agenda( - self, - context: ContextProtocol, - openai_client: AsyncOpenAI | AsyncAzureOpenAI, - items: list[dict[str, str]], - remaining_turns: int, - conversation: Conversation, - ) -> PluginOutput: - """Updates the agenda model with the given items (generally generated by an LLM) and validates if the update is valid. - The agenda update reasons in terms of turns for validating the if the proposed agenda is valid. - If you wish to use a different resource unit, convert the value to turns in some way because - we found that LLMs do much better at reasoning in terms of turns. - - Args: - items (list[dict[str, str]]): A list of agenda items. - Each item should have the following keys: - - title (str): A brief description of the item. - - resource (int): The number of turns required for the item. - remaining_turns (int): The number of remaining turns. - conversation (Conversation): The conversation object. - - Returns: - PluginOutput: A PluginOutput object with the success status. Does not generate any messages. - """ - previous_attempts = [] - while True: - try: - # Try to update the agenda, and do extra validation checks - self.agenda.items = items # type: ignore - self._validate_agenda_update(items, remaining_turns) - logger.info(f"Agenda updated successfully: {self.get_agenda_for_prompt()}") - return PluginOutput(True, []) - except (ValidationError, ValueError) as e: - # Update the previous attempts and get instructions for the LLM - previous_attempts, llm_formatted_attempts = update_attempts( - error=e, - attempt_id=str(items), - previous_attempts=previous_attempts, - ) - - # If we have reached the maximum number of retries return a failure - if len(previous_attempts) > self.max_agenda_retries: - logger.warning(f"Failed to update agenda after {self.max_agenda_retries} attempts.") - return PluginOutput(False, []) - else: - logger.info(f"Attempting to fix the agenda error. Attempt {len(previous_attempts)}.") - response = await fix_agenda_error(context, openai_client, llm_formatted_attempts, conversation) - if response is None: - raise ValueError("Invalid response from the LLM.") - if response.metadata["validation_result"] != ToolValidationResult.SUCCESS: - logger.warning( - f"Failed to fix the agenda error due to a failure in the LLM tool call: {response.metadata['validation_result']}" - ) - return PluginOutput(False, []) - else: - # Use the result of the first tool call to try the update again - items = response.metadata["tool_args_list"][0]["items"] - - def get_agenda_for_prompt(self) -> str: - """Gets a string representation of the agenda for use in an LLM prompt. - - Returns: - str: A string representation of the agenda. - """ - agenda_json = self.agenda.model_dump() - agenda_items = agenda_json.get("items", []) - if len(agenda_items) == 0: - return "None" - agenda_str = "\n".join([ - f"{i + 1}. [{format_resource(item['resource'], ResourceConstraintUnit.TURNS)}] {item['title']}" - for i, item in enumerate(agenda_items) - ]) - total_resource = format_resource(sum([item["resource"] for item in agenda_items]), ResourceConstraintUnit.TURNS) - agenda_str += f"\nTotal = {total_resource}" - return agenda_str - - # The following is the kernel function that will be provided to the LLM call - class Items: - title: Annotated[str, "Description of the item"] - resource: Annotated[int, "Number of turns required for the item"] - - def update_agenda_items( - self, - items: Annotated[list[Items], "Ordered list of items to be completed in the remainder of the conversation"], - ): - pass - - def _validate_agenda_update(self, items: list[dict[str, str]], remaining_turns: int) -> None: - """Validates if any constraints were violated while performing the agenda update. - - Args: - items (list[dict[str, str]]): A list of agenda items. - remaining_turns (int): The number of remaining turns. - - Raises: - ValueError: If any validation checks fail. - """ - # The total, proposed allocation of resources. - total_resources = sum([item["resource"] for item in items]) # type: ignore - - violations = [] - # In maximum mode, the total resources should not exceed the remaining turns - if (self.resource_constraint_mode == ResourceConstraintMode.MAXIMUM) and (total_resources > remaining_turns): - total_resource_instruction = ( - f"The total turns allocated in the agenda must not exceed the remaining amount ({remaining_turns})" - ) - violations.append(f"{total_resource_instruction}; but the current total is {total_resources}.") - - # In exact mode if the total resources were not exactly equal to the remaining turns - if (self.resource_constraint_mode == ResourceConstraintMode.EXACT) and (total_resources != remaining_turns): - total_resource_instruction = ( - f"The total turns allocated in the agenda must equal the remaining amount ({remaining_turns})" - ) - violations.append(f"{total_resource_instruction}; but the current total is {total_resources}.") - - # Check if any item has a resource value of 0 - if any(item["resource"] <= 0 for item in items): # type: ignore - violations.append("All items must have a resource value greater than 0.") - - # Raise an error if any violations were found - if len(violations) > 0: - logger.debug(f"Agenda update failed due to the following violations: {violations}.") - raise ValueError(" ".join(violations)) - - def to_json(self) -> dict: - agenda_dict = self.agenda.model_dump() - return { - "agenda": agenda_dict, - } - - @classmethod - def from_json( - cls, - json_data: dict, - service_id: str, - resource_constraint_mode: ResourceConstraintMode | None, - max_agenda_retries: int = 2, - ) -> "Agenda": - agenda = cls(service_id, resource_constraint_mode, max_agenda_retries) - agenda.agenda.items = json_data["agenda"]["items"] - return agenda diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/base_model_llm.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/base_model_llm.py index 12085752..4c75f22c 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/base_model_llm.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/base_model_llm.py @@ -5,31 +5,40 @@ import ast from types import NoneType -from typing import get_args +from typing import Any, get_args from pydantic import BaseModel, ValidationInfo, field_validator class BaseModelLLM(BaseModel): - """A Pydantic base class for use when an LLM is completing fields. Provides a custom field validator and Pydantic Config.""" + """ + A Pydantic base class for use when an LLM is completing fields. Provides a + custom field validator and Pydantic Config. + """ @field_validator("*", mode="before") - def parse_literal_eval(cls, value: str, info: ValidationInfo): # noqa: N805 - """An LLM will always result in a string (e.g. '["x", "y"]'), so we need to parse it to the correct type""" - # Get the type hints for the field + def parse_literal_eval(cls, value: str, info: ValidationInfo) -> NoneType | str | Any: + """ + An LLM will always result in a string (e.g. '["x", "y"]'), so we need to + parse it to the correct type. + """ + + # Get the type hints for the field. annotation = cls.model_fields[info.field_name].annotation typehints = get_args(annotation) if len(typehints) == 0: typehints = [annotation] - # Usually fields that are NoneType have another type hint as well, e.g. str | None - # if the LLM returns "None" and the field allows NoneType, we should return None - # without this code, the next if-block would leave the string "None" as the value + # Usually fields that are NoneType have another type hint as well, e.g. + # str | None. If the LLM returns "None" and the field allows NoneType, + # we should return None without this code, the next if-block would leave + # the string "None" as the value if (NoneType in typehints) and (value == "None"): return None - # If the field allows strings, we don't parse it - otherwise a validation error might be raised - # e.g. phone_number = "1234567890" should not be converted to an int if the type hint is str + # If the field allows strings, we don't parse it - otherwise a + # validation error might be raised e.g. phone_number = "1234567890" + # should not be converted to an int if the type hint is str if str in typehints: return value try: @@ -39,7 +48,8 @@ def parse_literal_eval(cls, value: str, info: ValidationInfo): # noqa: N805 return value class Config: - # Ensure that validation happens every time a field is updated, not just when the artifact is created + # Ensure that validation happens every time a field is updated, not just + # when the artifact is created. validate_assignment = True - # Do not allow extra fields to be added to the artifact + # Do not allow extra fields to be added to the artifact. extra = "forbid" diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_final_update.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_final_update.py similarity index 100% rename from libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_final_update.py rename to libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_final_update.py diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_fix_agenda_error.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_fix_agenda_error.py similarity index 95% rename from libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_fix_agenda_error.py rename to libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_fix_agenda_error.py index 0638c62b..2dded40a 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_fix_agenda_error.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_fix_agenda_error.py @@ -3,7 +3,10 @@ from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider from chat_driver.message_formatter import liquid_format -from form_filler_skill.guided_conversation.conversation_helpers import Conversation, ConversationMessageType +from form_filler_skill.guided_conversation.conversation_helpers import ( + Conversation, + ConversationMessageType, +) from openai import AsyncAzureOpenAI, AsyncOpenAI logger = logging.getLogger(__name__) @@ -44,7 +47,9 @@ async def fix_agenda_error( history.append_system_message( AGENDA_ERROR_CORRECTION_SYSTEM_TEMPLATE, { - "conversation_history": conversation.get_repr_for_prompt(exclude_types=[ConversationMessageType.REASONING]), + "conversation_history": conversation.get_repr_for_prompt( + exclude_types=[ConversationMessageType.REASONING] + ), "previous_attempts": previous_attempts, }, ) diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_agenda.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_agenda.py new file mode 100644 index 00000000..65eb70b1 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_agenda.py @@ -0,0 +1,250 @@ +import logging + +from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider +from chat_driver.message_formatter import liquid_format +from form_filler_skill.agenda import Agenda, AgendaItem +from form_filler_skill.guided_conversation.definition import GCDefinition +from form_filler_skill.message import Conversation +from form_filler_skill.resources import ( + GCResource, + ResourceConstraintMode, + ResourceConstraintUnit, + format_resource, +) +from openai import AsyncAzureOpenAI, AsyncOpenAI +from pydantic import ValidationError + +from ..guided_conversation.artifact import Artifact +from .fix_agenda_error import fix_agenda_error +from .update_agenda_template import update_agenda_template + +logger = logging.getLogger(__name__) + + +def _get_termination_instructions(resource: GCResource): + """ + Get the termination instructions for the conversation. This is contingent on the resources mode, + if any, that is available. + + Assumes we're always using turns as the resource unit. + + Args: + resource (GCResource): The resource object. + + Returns: + str: the termination instructions + """ + # Termination condition under no resource constraints + if resource.resource_constraint is None: + return ( + "- You should pick this action as soon as you have completed the artifact to the best of your ability, the" + " conversation has come to a natural conclusion, or the user is not cooperating so you cannot continue the" + " conversation." + ) + + # Termination condition under exact resource constraints + if resource.resource_constraint.mode == ResourceConstraintMode.EXACT: + return "- You should only pick this action if the user is not cooperating so you cannot continue the conversation." + + # Termination condition under maximum resource constraints + elif resource.resource_constraint.mode == ResourceConstraintMode.MAXIMUM: + return ( + "- You should pick this action as soon as you have completed the artifact to the best of your ability, the" + " conversation has come to a natural conclusion, or the user is not cooperating so you cannot continue the" + " conversation." + ) + + else: + logger.error("Invalid resource mode provided.") + return "" + + +async def update_agenda( + context: ContextProtocol, + openai_client: AsyncOpenAI | AsyncAzureOpenAI, + definition: GCDefinition, + chat_history: Conversation, + agenda: Agenda, + artifact: Artifact, + resource: GCResource, +) -> bool: + # STEP 1: Generate an updated agenda. + + # If there is a resource constraint and there's more than one turn left, + # include additional constraint instructions. + remaining_resource = resource.remaining_units if resource.remaining_units else 0 + resource_instructions = resource.get_resource_instructions() + if (resource_instructions != "") and (remaining_resource > 1): + match resource.get_resource_mode(): + case ResourceConstraintMode.MAXIMUM: + total_resource_str = f"does not exceed the remaining turns ({remaining_resource})." + ample_time_str = "" + case ResourceConstraintMode.EXACT: + total_resource_str = f"is equal to the remaining turns ({remaining_resource}). Do not leave any turns unallocated." + ample_time_str = ( + "If you have many turns remaining, instead of including wrap-up items or repeating " + "topics, you should include items that increase the breadth and/or depth of the conversation " + 'in a way that\'s directly relevant to the artifact (e.g. "collect additional details about X", ' + '"ask for clarification about Y", "explore related topic Z", etc.).' + ) + case _: + logger.error("Invalid resource mode.") + else: + total_resource_str = "" + ample_time_str = "" + + history = InMemoryMessageHistoryProvider(formatter=liquid_format) + history.append_system_message( + update_agenda_template, + { + "context": definition.conversation_context, + "artifact_schema": definition.artifact_schema, + "rules": definition.rules, + "current_state_description": definition.conversation_flow, + "show_agenda": True, + "remaining_resource": remaining_resource, + "total_resource_str": total_resource_str, + "ample_time_str": ample_time_str, + "termination_instructions": _get_termination_instructions(resource), + "resource_instructions": resource_instructions, + "chat_history": chat_history, + "agenda_state": get_agenda_for_prompt(agenda), + "artifact_state": artifact.get_artifact_for_prompt(), + }, + ) + + config = ChatDriverConfig( + context=context, + openai_client=openai_client, + model="gpt-4o", + message_provider=history, + ) + + chat_driver = ChatDriver(config) + response = await chat_driver.respond() + items = response.message + + # STEP 2: Validate/fix the updated agenda. + + previous_attempts = [] + while True: + try: + # Pydantic type validation. + agenda.items = items # type: ignore + + # Check resource constraints. + if agenda.resource_constraint_mode is not None: + check_item_constraints( + agenda.resource_constraint_mode, + agenda.items, + resource.estimate_remaining_turns(), + ) + + logger.info(f"Agenda updated successfully: {get_agenda_for_prompt(agenda)}") + return True + + except (ValidationError, ValueError) as e: + # If we have reached the maximum number of retries return a failure. + if len(previous_attempts) >= agenda.max_agenda_retries: + logger.warning( + f"Failed to update agenda after {agenda.max_agenda_retries} attempts." + ) + return False + + # Otherwise, get an error string. + if isinstance(e, ValidationError): + error_str = "; ".join([e.get("msg") for e in e.errors()]) + error_str = error_str.replace( + "; Input should be 'Unanswered'", " or input should be 'Unanswered'" + ) + else: + error_str = str(e) + + # Add it to our list of previous attempts. + previous_attempts.append((str(items), error_str)) + + # And try again. + logger.info(f"Attempting to fix the agenda error. Attempt {len(previous_attempts)}.") + llm_formatted_attempts = "\n".join([ + f"Attempt: {attempt}\nError: {error}" for attempt, error in previous_attempts + ]) + response = await fix_agenda_error( + context, openai_client, llm_formatted_attempts, chat_history + ) + + if response is None: + raise ValueError("Invalid response from the LLM.") + + if response["validation_result"] != ToolValidationResult.SUCCESS: + logger.warning( + f"Failed to fix the agenda error due to a failure in the LLM tool call: {response['validation_result']}" + ) + return False + else: + # Use the result of the first tool call to try the update again + items = response + + +def check_item_constraints( + resource_constraint_mode: ResourceConstraintMode, + items: list[AgendaItem], + remaining_turns: int, +) -> None: + """ + Validates if any constraints were violated while performing the agenda + update. + """ + # The total, proposed allocation of resources. + total_resources = sum([item.resource for item in items]) + + violations = [] + # In maximum mode, the total resources should not exceed the remaining + # turns. + if (resource_constraint_mode == ResourceConstraintMode.MAXIMUM) and ( + total_resources > remaining_turns + ): + violations.append( + "The total turns allocated in the agenda " + f"must not exceed the remaining amount ({remaining_turns}); " + f"but the current total is {total_resources}." + ) + + # In exact mode if the total resources were not exactly equal to the + # remaining turns. + if (resource_constraint_mode == ResourceConstraintMode.EXACT) and ( + total_resources != remaining_turns + ): + violations.append( + "The total turns allocated in the agenda " + f"must equal the remaining amount ({remaining_turns}); " + f"but the current total is {total_resources}." + ) + + # Check if any item has a resource value of 0. + if any(item.resource <= 0 for item in items): + violations.append("All items must have a resource value greater than 0.") + + # Raise an error if any violations were found. + if len(violations) > 0: + logger.debug(f"Agenda update failed due to the following violations: {violations}.") + raise ValueError(" ".join(violations)) + + +def get_agenda_for_prompt(agenda: Agenda) -> str: + """ + Gets a string representation of the agenda for use in an LLM prompt. + """ + agenda_json = agenda.model_dump() + agenda_items = agenda_json.get("items", []) + if len(agenda_items) == 0: + return "None" + agenda_str = "\n".join([ + f"{i + 1}. [{format_resource(item['resource'], ResourceConstraintUnit.TURNS)}] {item['title']}" + for i, item in enumerate(agenda_items) + ]) + total_resource = format_resource( + sum([item["resource"] for item in agenda_items]), ResourceConstraintUnit.TURNS + ) + agenda_str += f"\nTotal = {total_resource}" + return agenda_str diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_update_artifact.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_artifact.py similarity index 100% rename from libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/gc_update_artifact.py rename to libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_artifact.py diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/conversation_helpers.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/conversation_helpers.py index 49662a21..1b9502d3 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/conversation_helpers.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/conversation_helpers.py @@ -105,6 +105,7 @@ def get_repr_for_prompt( to_join.append(f"{participant_name}: ") else: to_join.append(f"{participant_name}: {user_string}") + conversation_string = "\n".join(to_join) return conversation_string diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/resources.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/resources.py index 103966f5..f39d0253 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/resources.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/resources.py @@ -1,7 +1,5 @@ # Copyright (c) Microsoft. All rights reserved. -# FIXME: Copied code from Semantic Kernel repo, using as-is despite type errors -# type: ignore import logging import math @@ -10,10 +8,14 @@ from pydantic import BaseModel +logger = logging.getLogger(__name__) + class ResourceConstraintUnit(StrEnum): - """Choose the unit of the resource constraint. - Seconds and Minutes are real-time and will be impacted by the latency of the model.""" + """ + Choose the unit of the resource constraint. Seconds and Minutes are + real-time and will be impacted by the latency of the model. + """ SECONDS = "seconds" MINUTES = "minutes" @@ -21,21 +23,23 @@ class ResourceConstraintUnit(StrEnum): class ResourceConstraintMode(StrEnum): - """Choose how the agent should use the resource. - Maximum: is an upper bound, i.e. the agent can end the conversation before the resource is exhausted - Exact: the agent should aim to use exactly the given amount of the resource""" + """ + Choose how the agent should use the resource. + + Maximum: is an upper bound, i.e. the agent can end the conversation before + the resource is exhausted. + + Exact: The agent should aim to use exactly the given amount of the resource. + """ MAXIMUM = "maximum" EXACT = "exact" class ResourceConstraint(BaseModel): - """A structured representation of the resource constraint for the GuidedConversation agent. - - Args: - quantity (float | int): The quantity of the resource constraint. - unit (ResourceConstraintUnit): The unit of the resource constraint. - mode (ResourceConstraintMode): The mode of the resource constraint. + """ + A structured representation of the resource constraint for the + GuidedConversation agent. """ quantity: float | int @@ -47,21 +51,31 @@ class Config: def format_resource(quantity: float, unit: ResourceConstraintUnit) -> str: - """Get formatted string for a given quantity and unit (e.g. 1 second, 20 seconds)""" + """ + Get formatted string for a given quantity and unit (e.g. 1 second, 20 + seconds) + """ if unit != ResourceConstraintUnit.TURNS: quantity = round(quantity, 1) - unit = unit.value - return f"{quantity} {unit[:-1] if quantity == 1 else unit}" + if quantity == 1: + return f"{quantity} {unit.value.rstrip('s')}" + else: + return f"{quantity} {unit.value}" class GCResource: - """Resource constraints for the GuidedConversation agent. This class is used to keep track of the resource - constraints. If resource_constraint is None, then the agent can continue indefinitely. This also means - that no agenda will be created for the conversation. + """ + Resource constraints for the GuidedConversation agent. This class is used to + keep track of the resource constraints. If resource_constraint is None, then + the agent can continue indefinitely. This also means that no agenda will be + created for the conversation. Args: - resource_constraint (ResourceConstraint | None): The resource constraint for the conversation. - initial_seconds_per_turn (int): The initial number of seconds per turn. Defaults to 120 seconds. + resource_constraint (ResourceConstraint | None): The resource constraint + for the conversation. + + initial_seconds_per_turn (int): The initial number of seconds per turn. + Defaults to 120 seconds. """ def __init__( @@ -69,18 +83,17 @@ def __init__( resource_constraint: ResourceConstraint | None, initial_seconds_per_turn: int = 120, ): - logger = logging.getLogger(__name__) - self.logger = logger self.resource_constraint: ResourceConstraint | None = resource_constraint self.initial_seconds_per_turn: int = initial_seconds_per_turn self.turn_number: int = 0 - self.remaining_units: float | None = None - self.elapsed_units: float | None = None if resource_constraint is not None: self.elapsed_units = 0 self.remaining_units = resource_constraint.quantity + else: + self.elapsed_units = 0 + self.remaining_units = 0 def start_resource(self) -> None: """To be called at the start of a conversation turn""" @@ -93,33 +106,36 @@ def start_resource(self) -> None: def increment_resource(self) -> None: """Increment the resource counter by one turn.""" if self.resource_constraint is not None: - if self.resource_constraint.unit == ResourceConstraintUnit.SECONDS: - self.elapsed_units += time.time() - self.start_time - self.remaining_units = self.resource_constraint.quantity - self.elapsed_units - elif self.resource_constraint.unit == ResourceConstraintUnit.MINUTES: - self.elapsed_units += (time.time() - self.start_time) / 60 - self.remaining_units = self.resource_constraint.quantity - self.elapsed_units - elif self.resource_constraint.unit == ResourceConstraintUnit.TURNS: - self.elapsed_units += 1 - self.remaining_units -= 1 - + match self.resource_constraint.unit: + case ResourceConstraintUnit.SECONDS: + self.elapsed_units += time.time() - self.start_time + self.remaining_units = self.resource_constraint.quantity - self.elapsed_units + case ResourceConstraintUnit.MINUTES: + self.elapsed_units += (time.time() - self.start_time) / 60 + self.remaining_units = self.resource_constraint.quantity - self.elapsed_units + case ResourceConstraintUnit.TURNS: + self.elapsed_units += 1 + self.remaining_units -= 1 + case _: + raise ValueError("Invalid resource unit provided.") self.turn_number += 1 - def get_resource_mode(self) -> ResourceConstraintMode: - """Get the mode of the resource constraint. - - Returns: - ResourceConstraintMode | None: The mode of the resource constraint, or None if there is no - resource constraint. + def get_resource_mode(self) -> ResourceConstraintMode | None: + """ + Get the mode of the resource constraint. """ - return self.resource_constraint.mode if self.resource_constraint is not None else None + if self.resource_constraint is None: + return None + return self.resource_constraint.mode def get_elapsed_turns(self, formatted_repr: bool = False) -> str | int: - """Get the number of elapsed turns. + """ + Get the number of elapsed turns. Args: - formatted_repr (bool): If true, return a formatted string representation of the elapsed turns. - If false, return an integer. Defaults to False. + formatted_repr (bool): If true, return a formatted string + representation of the elapsed turns. If false, return an integer. + Defaults to False. Returns: str | int: The description/number of elapsed turns. @@ -130,10 +146,12 @@ def get_elapsed_turns(self, formatted_repr: bool = False) -> str | int: return self.turn_number def get_remaining_turns(self, formatted_repr: bool = False) -> str | int: - """Get the number of remaining turns. + """ + Get the number of remaining turns. Args: - formatted_repr (bool): If true, return a formatted string representation of the remaining turns. + formatted_repr (bool): If true, return a formatted string + representation of the remaining turns. Returns: str | int: The description/number of remaining turns. @@ -144,47 +162,49 @@ def get_remaining_turns(self, formatted_repr: bool = False) -> str | int: return self.estimate_remaining_turns() def estimate_remaining_turns(self) -> int: - """Estimate the remaining turns based on the resource constraint, thereby translating certain - resource units (e.g. seconds, minutes) into turns. - - Returns: - int: The estimated number of remaining turns. """ - if self.resource_constraint is not None: - if ( - self.resource_constraint.unit == ResourceConstraintUnit.SECONDS - or self.resource_constraint.unit == ResourceConstraintUnit.MINUTES - ): - elapsed_turns = self.turn_number - - # TODO: This can likely be simplified - if self.resource_constraint.unit == ResourceConstraintUnit.MINUTES: - time_per_turn = ( - self.initial_seconds_per_turn - if elapsed_turns == 0 - else (self.elapsed_units * 60) / elapsed_turns - ) - time_per_turn /= 60 - else: - time_per_turn = ( - self.initial_seconds_per_turn if elapsed_turns == 0 else self.elapsed_units / elapsed_turns - ) - remaining_turns = self.remaining_units / time_per_turn - - # Round down, unless it's less than 1, in which case round up - remaining_turns = math.ceil(remaining_turns) if remaining_turns < 1 else math.floor(remaining_turns) - return remaining_turns - elif self.resource_constraint.unit == ResourceConstraintUnit.TURNS: - return self.resource_constraint.quantity - self.turn_number - else: - self.logger.error( + Estimate the remaining turns based on the resource constraint, thereby + translating certain resource units (e.g. seconds, minutes) into turns. + """ + if self.resource_constraint is None: + logger.error( "Resource constraint is not set, so turns cannot be estimated using function estimate_remaining_turns" ) raise ValueError( "Resource constraint is not set. Do not try to call this method without a resource constraint." ) - def get_resource_instructions(self) -> tuple[str, str]: + match self.resource_constraint.unit: + case ResourceConstraintUnit.MINUTES: + if self.turn_number == 0: + time_per_turn = self.initial_seconds_per_turn + else: + time_per_turn = (self.elapsed_units * 60) / self.turn_number + time_per_turn /= 60 + remaining_turns = self.remaining_units / time_per_turn + if remaining_turns < 1: + return math.ceil(remaining_turns) + else: + return math.floor(remaining_turns) + + case ResourceConstraintUnit.SECONDS: + if self.turn_number == 0: + time_per_turn = self.initial_seconds_per_turn + else: + time_per_turn = self.elapsed_units / self.turn_number + remaining_turns = self.remaining_units / time_per_turn + if remaining_turns < 1: + return math.ceil(remaining_turns) + else: + return math.floor(remaining_turns) + + case ResourceConstraintUnit.TURNS: + return int(self.resource_constraint.quantity - self.turn_number) + + case _: + raise ValueError("Invalid resource unit provided.") + + def get_resource_instructions(self) -> str: """Get the resource instructions for the conversation. Assumes we're always using turns as the resource unit. @@ -195,8 +215,12 @@ def get_resource_instructions(self) -> tuple[str, str]: if self.resource_constraint is None: return "" - formatted_elapsed_resource = format_resource(self.elapsed_units, ResourceConstraintUnit.TURNS) - formatted_remaining_resource = format_resource(self.remaining_units, ResourceConstraintUnit.TURNS) + formatted_elapsed_resource = format_resource( + self.elapsed_units, ResourceConstraintUnit.TURNS + ) + formatted_remaining_resource = format_resource( + self.remaining_units, ResourceConstraintUnit.TURNS + ) # if the resource quantity is anything other than 1, the resource unit should be plural (e.g. "minutes" instead of "minute") is_plural_elapsed = self.elapsed_units != 1 @@ -208,10 +232,17 @@ def get_resource_instructions(self) -> tuple[str, str]: resource_instructions = "" if self.resource_constraint.mode == ResourceConstraintMode.EXACT: - exact_mode_instructions = f"""There {"are" if is_plural_remaining else "is"} {formatted_remaining_resource} remaining (including this one) - the conversation will automatically terminate when 0 turns are left. \ -You should continue the conversation until it is automatically terminated. This means you should NOT preemptively end the conversation, \ -either explicitly (by selecting the "End conversation" action) or implicitly (e.g. by telling the user that you have all required information and they should wait for the next step). \ -Your goal is not to maximize efficiency (i.e. complete the artifact as quickly as possible then end the conversation), but rather to make the best use of ALL remaining turns available to you""" + exact_mode_instructions = ( + f"There {'are' if is_plural_remaining else 'is'} {formatted_remaining_resource} " + "remaining (including this one) - the conversation will automatically terminate " + "when 0 turns are left. You should continue the conversation until it is " + "automatically terminated. This means you should NOT preemptively end the " + 'conversation, either explicitly (by selecting the "End conversation" action) ' + "or implicitly (e.g. by telling the user that you have all required information " + "and they should wait for the next step). Your goal is not to maximize efficiency " + "(i.e. complete the artifact as quickly as possible then end the conversation), " + "but rather to make the best use of ALL remaining turns available to you" + ) if is_plural_remaining: resource_instructions += f"""{exact_mode_instructions}. This will require you to plan your actions carefully using the agenda: you want to avoid the situation where you have to pack too many topics into the final turns because you didn't account for them earlier, \ @@ -228,7 +259,7 @@ def get_resource_instructions(self) -> tuple[str, str]: You will need to plan your actions carefully using the agenda: you want to avoid the situation where you have to pack too many topics into the final turns because you didn't account for them earlier.""" else: - self.logger.error("Invalid resource mode provided.") + logger.error("Invalid resource mode provided.") return resource_instructions diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py index 1701d37d..7f40955e 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py @@ -1,15 +1,19 @@ from typing import Any, Optional from chat_driver import ChatDriverConfig -from context import Context +from events import BaseEvent from skill_library import FunctionRoutine, RoutineTypes, Skill -from skill_library.skill_registry import SkillRegistry +from skill_library.run_context import RunContext -from form_filler_skill.guided_conversation.definition import GCDefinition +from form_filler_skill.agenda import Agenda +from form_filler_skill.artifact import Artifact +from form_filler_skill.definition import GCDefinition +from form_filler_skill.message import Conversation +from form_filler_skill.resources import GCResource -from .chat_drivers.gc_final_update import final_update -from .chat_drivers.gc_update_agenda import update_agenda -from .chat_drivers.gc_update_artifact import update_artifact +from .chat_drivers.unneeded.execute_reasoning import execute_reasoning +from .chat_drivers.final_update import final_update +from .chat_drivers.update_agenda import update_agenda NAME = "guided-conversation" CLASS_NAME = "GuidedConversationSkill" @@ -24,6 +28,9 @@ class GuidedConversationSkill(Skill): def __init__( self, chat_driver_config: ChatDriverConfig, + agenda: Agenda, + artifact: Artifact, + resource: GCResource, ) -> None: # Put all functions in a group. We are going to use all these as (1) # skill actions, but also as (2) chat functions and (3) chat commands. @@ -31,20 +38,28 @@ def __init__( # between these. functions = [ self.update_agenda, - self.update_artifact, + self.execute_reasoning, self.final_update, ] # Add some skill routines. routines: list[RoutineTypes] = [ - self.conversation_routine, + self.conversation_routine(), ] # Configure the skill's chat driver. + self.openai_client = chat_driver_config.openai_client chat_driver_config.instructions = INSTRUCTIONS chat_driver_config.commands = functions chat_driver_config.functions = functions + # TODO: Persist these. They should be saved in the skills state by + # session_id. + self.agenda = agenda + self.artifact = artifact + self.resource = resource + self.chat_history = Conversation() + # Initialize the skill! super().__init__( name=NAME, @@ -68,21 +83,21 @@ def conversation_routine(self) -> FunctionRoutine: ) async def conversation_init_function( - self, skill_registry: SkillRegistry, context: Context, vars: Optional[dict[str, Any]] + self, context: RunContext, vars: dict[str, Any] | None = None ): if vars is None: return state = {"definition": vars["definition"]} - skill_registry.routine_stack.update_current_state(state) - await self.conversation_step_function(skill_registry, context) + await context.routine_stack.set_current_state(state) + await self.conversation_step_function(context) async def conversation_step_function( self, - skill_registry: SkillRegistry, - context: Context, + context: RunContext, message: Optional[str] = None, ): - frame = skill_registry.routine_stack.peek() + # TODO: Where is this conversation maintained? + frame = await context.routine_stack.peek() state = frame.state if frame else {} definition = GCDefinition(**state["definition"]) while True: @@ -91,22 +106,24 @@ async def conversation_step_function( state["mode"] = "init" case "init": state["chat_history"] = [] - message, done = self.update_agenda(context, definition) + message, done = await self.update_agenda(context, definition) if done: state["mode"] = "finalize" state["mode"] = "conversation" - runner.send(message) + context.emit(message) return case "conversation": state["chat_history"] += message state["artifact"] = self.update_artifact(context) - message, done = self.update_agenda() + agenda, done = self.update_agenda() + if agenda: + state["agenda"] = agenda if done: state["mode"] = "finalize" - runner.send(message) + await self.message_user(context, agenda) # generates the next message return case "finalize": - message = self.final_update() + self.final_update() # Generates the final message. state["state"] = "done" runner.send(message) return @@ -117,16 +134,23 @@ async def conversation_step_function( # Actions ################################## - def update_agenda(self, context: Context, definition: GCDefinition): - update_agenda( + async def update_agenda(self, context: RunContext, definition: GCDefinition): + return await update_agenda( context, self.openai_client, definition, - self.chat_driver.message_provider.get(), + self.chat_history, + agenda=self.agenda, + artifact=self.artifact, + resource=self.resource, ) - def update_artifact(self, context: Context): - update_artifact(context) + async def execute_reasoning(self, context: RunContext, reasoning: str) -> BaseEvent: + return await execute_reasoning( + context, self.openai_client, reasoning, self.artifact.get_schema_for_prompt() + ) - def final_update(self, context: Context): - final_update(context) + async def final_update(self, context: RunContext, definition: GCDefinition): + await final_update( + context, self.openai_client, definition, self.chat_history, artifact=self.artifact + ) diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/message.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/message.py new file mode 100644 index 00000000..4b128656 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/message.py @@ -0,0 +1,61 @@ +from enum import StrEnum + +from attr import dataclass +from openai.types.chat import ChatCompletionMessageParam + + +class ConversationMessageType(StrEnum): + DEFAULT = "default" + ARTIFACT_UPDATE = "artifact-update" + REASONING = "reasoning" + + +class Message: + def __init__( + self, + chat_completion_message_param: ChatCompletionMessageParam, + type: ConversationMessageType | None = None, + turn: int | None = None, + ) -> None: + self.param = chat_completion_message_param + self.turn = turn + self.type = type or ConversationMessageType.DEFAULT + + +@dataclass +class Conversation: + messages: list[Message] = [] + + def exclude(self, types: list[ConversationMessageType]) -> list[Message]: + return [message for message in self.messages if message.type not in types] + + def __str__(self) -> str: + message_strs = [] + current_turn = None + for message in self.messages: + # Modify the default user to be capitalized for consistency with how + # assistant is written. + name = message.param["role"] + if name == "user": + name = "User" + + # Append the turn number if it has changed. + if message.turn is not None and current_turn != message.turn: + current_turn = message.turn + message_strs.append(f"[Turn {current_turn}]") + + # Append the message content. + content = message.param.get("content", "") + if message.param["role"] == "assistant": + if message.type == ConversationMessageType.ARTIFACT_UPDATE: + message_strs.append(content) + else: + message_strs.append(f"Assistant: {content}") + else: + user_string = str(content).strip() + if user_string == "": + message_strs.append(f"{name}: ") + else: + message_strs.append(f"{name}: {user_string}") + + return "\n".join(message_strs) diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/resources.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/resources.py new file mode 100644 index 00000000..7d0b5f58 --- /dev/null +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/resources.py @@ -0,0 +1,275 @@ +# Copyright (c) Microsoft. All rights reserved. + + +import logging +import math +import time +from enum import StrEnum + +from pydantic import BaseModel + +logger = logging.getLogger(__name__) + + +class ResourceConstraintUnit(StrEnum): + """ + Choose the unit of the resource constraint. Seconds and Minutes are + real-time and will be impacted by the latency of the model. + """ + + SECONDS = "seconds" + MINUTES = "minutes" + TURNS = "turns" + + +class ResourceConstraintMode(StrEnum): + """ + Choose how the agent should use the resource. + + Maximum: is an upper bound, i.e. the agent can end the conversation before + the resource is exhausted. + + Exact: The agent should aim to use exactly the given amount of the resource. + """ + + MAXIMUM = "maximum" + EXACT = "exact" + + +class ResourceConstraint(BaseModel): + """ + A structured representation of the resource constraint for the + GuidedConversation agent. + """ + + quantity: float | int + unit: ResourceConstraintUnit + mode: ResourceConstraintMode + + class Config: + arbitrary_types_allowed = True + + +def format_resource(quantity: float, unit: ResourceConstraintUnit) -> str: + """ + Get formatted string for a given quantity and unit (e.g. 1 second, 20 + seconds) + """ + if unit != ResourceConstraintUnit.TURNS: + quantity = round(quantity, 1) + if quantity == 1: + return f"{quantity} {unit.value.rstrip('s')}" + else: + return f"{quantity} {unit.value}" + + +class GCResource: + """ + Resource constraints for the GuidedConversation agent. This class is used to + keep track of the resource constraints. If resource_constraint is None, then + the agent can continue indefinitely. This also means that no agenda will be + created for the conversation. + + Args: + resource_constraint (ResourceConstraint | None): The resource constraint + for the conversation. + + initial_seconds_per_turn (int): The initial number of seconds per turn. + Defaults to 120 seconds. + """ + + def __init__( + self, + resource_constraint: ResourceConstraint | None, + initial_seconds_per_turn: int = 120, + ): + self.resource_constraint: ResourceConstraint | None = resource_constraint + self.initial_seconds_per_turn: int = initial_seconds_per_turn + + self.turn_number: int = 0 + + if resource_constraint is not None: + self.elapsed_units = 0 + self.remaining_units = resource_constraint.quantity + else: + self.elapsed_units = 0 + self.remaining_units = 0 + + def start_resource(self) -> None: + """To be called at the start of a conversation turn""" + if self.resource_constraint is not None and ( + self.resource_constraint.unit == ResourceConstraintUnit.SECONDS + or self.resource_constraint.unit == ResourceConstraintUnit.MINUTES + ): + self.start_time = time.time() + + def increment_resource(self) -> None: + """Increment the resource counter by one turn.""" + if self.resource_constraint is not None: + match self.resource_constraint.unit: + case ResourceConstraintUnit.SECONDS: + self.elapsed_units += time.time() - self.start_time + self.remaining_units = self.resource_constraint.quantity - self.elapsed_units + case ResourceConstraintUnit.MINUTES: + self.elapsed_units += (time.time() - self.start_time) / 60 + self.remaining_units = self.resource_constraint.quantity - self.elapsed_units + case ResourceConstraintUnit.TURNS: + self.elapsed_units += 1 + self.remaining_units -= 1 + case _: + raise ValueError("Invalid resource unit provided.") + self.turn_number += 1 + + def get_resource_mode(self) -> ResourceConstraintMode | None: + """ + Get the mode of the resource constraint. + """ + if self.resource_constraint is None: + return None + return self.resource_constraint.mode + + def get_elapsed_turns(self, formatted_repr: bool = False) -> str | int: + """ + Get the number of elapsed turns. + + Args: + formatted_repr (bool): If true, return a formatted string + representation of the elapsed turns. If false, return an integer. + Defaults to False. + + Returns: + str | int: The description/number of elapsed turns. + """ + if formatted_repr: + return format_resource(self.turn_number, ResourceConstraintUnit.TURNS) + else: + return self.turn_number + + def estimate_remaining_turns_formatted(self) -> str: + """ + Get the number of remaining turns in a formatted string. + """ + return format_resource(self.estimate_remaining_turns(), ResourceConstraintUnit.TURNS) + + def estimate_remaining_turns(self) -> int: + """ + Estimate the remaining turns based on the resource constraint, thereby + translating certain resource units (e.g. seconds, minutes) into turns. + """ + if self.resource_constraint is None: + logger.error( + "Resource constraint is not set, so turns cannot be estimated using function estimate_remaining_turns" + ) + raise ValueError( + "Resource constraint is not set. Do not try to call this method without a resource constraint." + ) + + match self.resource_constraint.unit: + case ResourceConstraintUnit.MINUTES: + if self.turn_number == 0: + time_per_turn = self.initial_seconds_per_turn + else: + time_per_turn = (self.elapsed_units * 60) / self.turn_number + time_per_turn /= 60 + remaining_turns = self.remaining_units / time_per_turn + if remaining_turns < 1: + return math.ceil(remaining_turns) + else: + return math.floor(remaining_turns) + + case ResourceConstraintUnit.SECONDS: + if self.turn_number == 0: + time_per_turn = self.initial_seconds_per_turn + else: + time_per_turn = self.elapsed_units / self.turn_number + remaining_turns = self.remaining_units / time_per_turn + if remaining_turns < 1: + return math.ceil(remaining_turns) + else: + return math.floor(remaining_turns) + + case ResourceConstraintUnit.TURNS: + return int(self.resource_constraint.quantity - self.turn_number) + + case _: + raise ValueError("Invalid resource unit provided.") + + def get_resource_instructions(self) -> str: + """Get the resource instructions for the conversation. + + Assumes we're always using turns as the resource unit. + + Returns: + str: the resource instructions + """ + if self.resource_constraint is None: + return "" + + formatted_elapsed_resource = format_resource( + self.elapsed_units, ResourceConstraintUnit.TURNS + ) + formatted_remaining_resource = format_resource( + self.remaining_units, ResourceConstraintUnit.TURNS + ) + + # if the resource quantity is anything other than 1, the resource unit should be plural (e.g. "minutes" instead of "minute") + is_plural_elapsed = self.elapsed_units != 1 + is_plural_remaining = self.remaining_units != 1 + + if self.elapsed_units > 0: + resource_instructions = f"So far, {formatted_elapsed_resource} {'have' if is_plural_elapsed else 'has'} elapsed since the conversation began. " + else: + resource_instructions = "" + + if self.resource_constraint.mode == ResourceConstraintMode.EXACT: + exact_mode_instructions = ( + f"There {'are' if is_plural_remaining else 'is'} {formatted_remaining_resource} " + "remaining (including this one) - the conversation will automatically terminate " + "when 0 turns are left. You should continue the conversation until it is " + "automatically terminated. This means you should NOT preemptively end the " + 'conversation, either explicitly (by selecting the "End conversation" action) ' + "or implicitly (e.g. by telling the user that you have all required information " + "and they should wait for the next step). Your goal is not to maximize efficiency " + "(i.e. complete the artifact as quickly as possible then end the conversation), " + "but rather to make the best use of ALL remaining turns available to you" + ) + + if is_plural_remaining: + resource_instructions += f"""{exact_mode_instructions}. This will require you to plan your actions carefully using the agenda: you want to avoid the situation where you have to pack too many topics into the final turns because you didn't account for them earlier, \ +or where you've rushed through the conversation and all fields are completed but there are still many turns left.""" + + # special instruction for the final turn (i.e. 1 remaining) in exact mode + else: + resource_instructions += f"""{exact_mode_instructions}, including this one. Therefore, you should use this turn to ask for any remaining information needed to complete the artifact, \ + or, if the artifact is already completed, continue to broaden/deepen the discussion in a way that's directly relevant to the artifact. Do NOT indicate to the user that the conversation is ending.""" + + elif self.resource_constraint.mode == ResourceConstraintMode.MAXIMUM: + resource_instructions += f"""You have a maximum of {formatted_remaining_resource} (including this one) left to complete the conversation. \ +You can decide to terminate the conversation at any point (including now), otherwise the conversation will automatically terminate when 0 turns are left. \ +You will need to plan your actions carefully using the agenda: you want to avoid the situation where you have to pack too many topics into the final turns because you didn't account for them earlier.""" + + else: + logger.error("Invalid resource mode provided.") + + return resource_instructions + + def to_json(self) -> dict: + return { + "turn_number": self.turn_number, + "remaining_units": self.remaining_units, + "elapsed_units": self.elapsed_units, + } + + @classmethod + def from_json( + cls, + json_data: dict, + ) -> "GCResource": + gc_resource = cls( + resource_constraint=None, + initial_seconds_per_turn=120, + ) + gc_resource.turn_number = json_data["turn_number"] + gc_resource.remaining_units = json_data["remaining_units"] + gc_resource.elapsed_units = json_data["elapsed_units"] + return gc_resource diff --git a/libraries/python/skills/skills/form-filler-skill/pyproject.toml b/libraries/python/skills/skills/form-filler-skill/pyproject.toml index 83139534..5ea6b681 100644 --- a/libraries/python/skills/skills/form-filler-skill/pyproject.toml +++ b/libraries/python/skills/skills/form-filler-skill/pyproject.toml @@ -10,6 +10,8 @@ dependencies = [ "chat-driver>=0.1.0", "context>=0.1.0", "events>=0.1.0", + "openai-client>=0.1.0", + # "guided-conversation>=0.1.0", ] [tool.uv] @@ -20,6 +22,8 @@ skill-library = { path = "../../skill-library", editable= true } chat-driver = { path = "../../../chat-driver", editable = true } context = { path = "../../../context", editable = true } events = { path = "../../../events", editable = true } +openai-client = { path = "../../../openai-client", editable = true } +# guided-conversation = { path = "../../../guided-conversation", editable = true } [build-system] requires = ["hatchling"] diff --git a/libraries/python/skills/skills/form-filler-skill/uv.lock b/libraries/python/skills/skills/form-filler-skill/uv.lock index 0bb68af5..f14275b7 100644 --- a/libraries/python/skills/skills/form-filler-skill/uv.lock +++ b/libraries/python/skills/skills/form-filler-skill/uv.lock @@ -5,6 +5,97 @@ resolution-markers = [ "python_full_version >= '3.13'", ] +[[package]] +name = "aiofiles" +version = "24.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/03/a88171e277e8caa88a4c77808c20ebb04ba74cc4681bf1e9416c862de237/aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c", size = 30247 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5", size = 15896 }, +] + +[[package]] +name = "aiohappyeyeballs" +version = "2.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bc/69/2f6d5a019bd02e920a3417689a89887b39ad1e350b562f9955693d900c40/aiohappyeyeballs-2.4.3.tar.gz", hash = "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586", size = 21809 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/d8/120cd0fe3e8530df0539e71ba9683eade12cae103dd7543e50d15f737917/aiohappyeyeballs-2.4.3-py3-none-any.whl", hash = "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572", size = 14742 }, +] + +[[package]] +name = "aiohttp" +version = "3.10.10" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/17/7e/16e57e6cf20eb62481a2f9ce8674328407187950ccc602ad07c685279141/aiohttp-3.10.10.tar.gz", hash = "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a", size = 7542993 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/31/3c351d17596194e5a38ef169a4da76458952b2497b4b54645b9d483cbbb0/aiohttp-3.10.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c30a0eafc89d28e7f959281b58198a9fa5e99405f716c0289b7892ca345fe45f", size = 586501 }, + { url = "https://files.pythonhosted.org/packages/a4/a8/a559d09eb08478cdead6b7ce05b0c4a133ba27fcdfa91e05d2e62867300d/aiohttp-3.10.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:258c5dd01afc10015866114e210fb7365f0d02d9d059c3c3415382ab633fcbcb", size = 398993 }, + { url = "https://files.pythonhosted.org/packages/c5/47/7736d4174613feef61d25332c3bd1a4f8ff5591fbd7331988238a7299485/aiohttp-3.10.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:15ecd889a709b0080f02721255b3f80bb261c2293d3c748151274dfea93ac871", size = 390647 }, + { url = "https://files.pythonhosted.org/packages/27/21/e9ba192a04b7160f5a8952c98a1de7cf8072ad150fa3abd454ead1ab1d7f/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3935f82f6f4a3820270842e90456ebad3af15810cf65932bd24da4463bc0a4c", size = 1306481 }, + { url = "https://files.pythonhosted.org/packages/cf/50/f364c01c8d0def1dc34747b2470969e216f5a37c7ece00fe558810f37013/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:413251f6fcf552a33c981c4709a6bba37b12710982fec8e558ae944bfb2abd38", size = 1344652 }, + { url = "https://files.pythonhosted.org/packages/1d/c2/74f608e984e9b585649e2e83883facad6fa3fc1d021de87b20cc67e8e5ae/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1720b4f14c78a3089562b8875b53e36b51c97c51adc53325a69b79b4b48ebcb", size = 1378498 }, + { url = "https://files.pythonhosted.org/packages/9f/a7/05a48c7c0a7a80a5591b1203bf1b64ca2ed6a2050af918d09c05852dc42b/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:679abe5d3858b33c2cf74faec299fda60ea9de62916e8b67e625d65bf069a3b7", size = 1292718 }, + { url = "https://files.pythonhosted.org/packages/7d/78/a925655018747e9790350180330032e27d6e0d7ed30bde545fae42f8c49c/aiohttp-3.10.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79019094f87c9fb44f8d769e41dbb664d6e8fcfd62f665ccce36762deaa0e911", size = 1251776 }, + { url = "https://files.pythonhosted.org/packages/47/9d/85c6b69f702351d1236594745a4fdc042fc43f494c247a98dac17e004026/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe2fb38c2ed905a2582948e2de560675e9dfbee94c6d5ccdb1301c6d0a5bf092", size = 1271716 }, + { url = "https://files.pythonhosted.org/packages/7f/a7/55fc805ff9b14af818903882ece08e2235b12b73b867b521b92994c52b14/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a3f00003de6eba42d6e94fabb4125600d6e484846dbf90ea8e48a800430cc142", size = 1266263 }, + { url = "https://files.pythonhosted.org/packages/1f/ec/d2be2ca7b063e4f91519d550dbc9c1cb43040174a322470deed90b3d3333/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1bbb122c557a16fafc10354b9d99ebf2f2808a660d78202f10ba9d50786384b9", size = 1321617 }, + { url = "https://files.pythonhosted.org/packages/c9/a3/b29f7920e1cd0a9a68a45dd3eb16140074d2efb1518d2e1f3e140357dc37/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:30ca7c3b94708a9d7ae76ff281b2f47d8eaf2579cd05971b5dc681db8caac6e1", size = 1339227 }, + { url = "https://files.pythonhosted.org/packages/8a/81/34b67235c47e232d807b4bbc42ba9b927c7ce9476872372fddcfd1e41b3d/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:df9270660711670e68803107d55c2b5949c2e0f2e4896da176e1ecfc068b974a", size = 1299068 }, + { url = "https://files.pythonhosted.org/packages/04/1f/26a7fe11b6ad3184f214733428353c89ae9fe3e4f605a657f5245c5e720c/aiohttp-3.10.10-cp311-cp311-win32.whl", hash = "sha256:aafc8ee9b742ce75044ae9a4d3e60e3d918d15a4c2e08a6c3c3e38fa59b92d94", size = 362223 }, + { url = "https://files.pythonhosted.org/packages/10/91/85dcd93f64011434359ce2666bece981f08d31bc49df33261e625b28595d/aiohttp-3.10.10-cp311-cp311-win_amd64.whl", hash = "sha256:362f641f9071e5f3ee6f8e7d37d5ed0d95aae656adf4ef578313ee585b585959", size = 381576 }, + { url = "https://files.pythonhosted.org/packages/ae/99/4c5aefe5ad06a1baf206aed6598c7cdcbc7c044c46801cd0d1ecb758cae3/aiohttp-3.10.10-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9294bbb581f92770e6ed5c19559e1e99255e4ca604a22c5c6397b2f9dd3ee42c", size = 583536 }, + { url = "https://files.pythonhosted.org/packages/a9/36/8b3bc49b49cb6d2da40ee61ff15dbcc44fd345a3e6ab5bb20844df929821/aiohttp-3.10.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a8fa23fe62c436ccf23ff930149c047f060c7126eae3ccea005f0483f27b2e28", size = 395693 }, + { url = "https://files.pythonhosted.org/packages/e1/77/0aa8660dcf11fa65d61712dbb458c4989de220a844bd69778dff25f2d50b/aiohttp-3.10.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c6a5b8c7926ba5d8545c7dd22961a107526562da31a7a32fa2456baf040939f", size = 390898 }, + { url = "https://files.pythonhosted.org/packages/38/d2/b833d95deb48c75db85bf6646de0a697e7fb5d87bd27cbade4f9746b48b1/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:007ec22fbc573e5eb2fb7dec4198ef8f6bf2fe4ce20020798b2eb5d0abda6138", size = 1312060 }, + { url = "https://files.pythonhosted.org/packages/aa/5f/29fd5113165a0893de8efedf9b4737e0ba92dfcd791415a528f947d10299/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9627cc1a10c8c409b5822a92d57a77f383b554463d1884008e051c32ab1b3742", size = 1350553 }, + { url = "https://files.pythonhosted.org/packages/ad/cc/f835f74b7d344428469200105236d44606cfa448be1e7c95ca52880d9bac/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:50edbcad60d8f0e3eccc68da67f37268b5144ecc34d59f27a02f9611c1d4eec7", size = 1392646 }, + { url = "https://files.pythonhosted.org/packages/bf/fe/1332409d845ca601893bbf2d76935e0b93d41686e5f333841c7d7a4a770d/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a45d85cf20b5e0d0aa5a8dca27cce8eddef3292bc29d72dcad1641f4ed50aa16", size = 1306310 }, + { url = "https://files.pythonhosted.org/packages/e4/a1/25a7633a5a513278a9892e333501e2e69c83e50be4b57a62285fb7a008c3/aiohttp-3.10.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b00807e2605f16e1e198f33a53ce3c4523114059b0c09c337209ae55e3823a8", size = 1260255 }, + { url = "https://files.pythonhosted.org/packages/f2/39/30eafe89e0e2a06c25e4762844c8214c0c0cd0fd9ffc3471694a7986f421/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f2d4324a98062be0525d16f768a03e0bbb3b9fe301ceee99611dc9a7953124e6", size = 1271141 }, + { url = "https://files.pythonhosted.org/packages/5b/fc/33125df728b48391ef1fcb512dfb02072158cc10d041414fb79803463020/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:438cd072f75bb6612f2aca29f8bd7cdf6e35e8f160bc312e49fbecab77c99e3a", size = 1280244 }, + { url = "https://files.pythonhosted.org/packages/3b/61/e42bf2c2934b5caa4e2ec0b5e5fd86989adb022b5ee60c2572a9d77cf6fe/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:baa42524a82f75303f714108fea528ccacf0386af429b69fff141ffef1c534f9", size = 1316805 }, + { url = "https://files.pythonhosted.org/packages/18/32/f52a5e2ae9ad3bba10e026a63a7a23abfa37c7d97aeeb9004eaa98df3ce3/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a7d8d14fe962153fc681f6366bdec33d4356f98a3e3567782aac1b6e0e40109a", size = 1343930 }, + { url = "https://files.pythonhosted.org/packages/05/be/6a403b464dcab3631fe8e27b0f1d906d9e45c5e92aca97ee007e5a895560/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205", size = 1306186 }, + { url = "https://files.pythonhosted.org/packages/8e/fd/bb50fe781068a736a02bf5c7ad5f3ab53e39f1d1e63110da6d30f7605edc/aiohttp-3.10.10-cp312-cp312-win32.whl", hash = "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628", size = 359289 }, + { url = "https://files.pythonhosted.org/packages/70/9e/5add7e240f77ef67c275c82cc1d08afbca57b77593118c1f6e920ae8ad3f/aiohttp-3.10.10-cp312-cp312-win_amd64.whl", hash = "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf", size = 379313 }, + { url = "https://files.pythonhosted.org/packages/b1/eb/618b1b76c7fe8082a71c9d62e3fe84c5b9af6703078caa9ec57850a12080/aiohttp-3.10.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28", size = 576114 }, + { url = "https://files.pythonhosted.org/packages/aa/37/3126995d7869f8b30d05381b81a2d4fb4ec6ad313db788e009bc6d39c211/aiohttp-3.10.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d", size = 391901 }, + { url = "https://files.pythonhosted.org/packages/3e/f2/8fdfc845be1f811c31ceb797968523813f8e1263ee3e9120d61253f6848f/aiohttp-3.10.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79", size = 387418 }, + { url = "https://files.pythonhosted.org/packages/60/d5/33d2061d36bf07e80286e04b7e0a4de37ce04b5ebfed72dba67659a05250/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e", size = 1287073 }, + { url = "https://files.pythonhosted.org/packages/00/52/affb55be16a4747740bd630b4c002dac6c5eac42f9bb64202fc3cf3f1930/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6", size = 1323612 }, + { url = "https://files.pythonhosted.org/packages/94/f2/cddb69b975387daa2182a8442566971d6410b8a0179bb4540d81c97b1611/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42", size = 1368406 }, + { url = "https://files.pythonhosted.org/packages/c1/e4/afba7327da4d932da8c6e29aecaf855f9d52dace53ac15bfc8030a246f1b/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e", size = 1282761 }, + { url = "https://files.pythonhosted.org/packages/9f/6b/364856faa0c9031ea76e24ef0f7fef79cddd9fa8e7dba9a1771c6acc56b5/aiohttp-3.10.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc", size = 1236518 }, + { url = "https://files.pythonhosted.org/packages/46/af/c382846f8356fe64a7b5908bb9b477457aa23b71be7ed551013b7b7d4d87/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a", size = 1250344 }, + { url = "https://files.pythonhosted.org/packages/87/53/294f87fc086fd0772d0ab82497beb9df67f0f27a8b3dd5742a2656db2bc6/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414", size = 1248956 }, + { url = "https://files.pythonhosted.org/packages/86/30/7d746717fe11bdfefb88bb6c09c5fc985d85c4632da8bb6018e273899254/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3", size = 1293379 }, + { url = "https://files.pythonhosted.org/packages/48/b9/45d670a834458db67a24258e9139ba61fa3bd7d69b98ecf3650c22806f8f/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67", size = 1320108 }, + { url = "https://files.pythonhosted.org/packages/72/8c/804bb2e837a175635d2000a0659eafc15b2e9d92d3d81c8f69e141ecd0b0/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b", size = 1281546 }, + { url = "https://files.pythonhosted.org/packages/89/c0/862e6a9de3d6eeb126cd9d9ea388243b70df9b871ce1a42b193b7a4a77fc/aiohttp-3.10.10-cp313-cp313-win32.whl", hash = "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8", size = 357516 }, + { url = "https://files.pythonhosted.org/packages/ae/63/3e1aee3e554263f3f1011cca50d78a4894ae16ce99bf78101ac3a2f0ef74/aiohttp-3.10.10-cp313-cp313-win_amd64.whl", hash = "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151", size = 376785 }, +] + +[[package]] +name = "aiosignal" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/67/0952ed97a9793b4958e5736f6d2b346b414a2cd63e82d05940032f45b32f/aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", size = 19422 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17", size = 7617 }, +] + [[package]] name = "annotated-types" version = "0.7.0" @@ -27,11 +118,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9e/ef/7a4f225581a0d7886ea28359179cb861d7fbcdefad29663fc1167b86f69f/anyio-4.6.0-py3-none-any.whl", hash = "sha256:c7d2e9d63e31599eeb636c8c5c03a7e108d73b345f064f1c19fdc87b79036a9a", size = 89631 }, ] +[[package]] +name = "asgi-correlation-id" +version = "4.3.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "starlette" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f4/ff/a6538245ac1eaa7733ec6740774e9d5add019e2c63caa29e758c16c0afdd/asgi_correlation_id-4.3.4.tar.gz", hash = "sha256:ea6bc310380373cb9f731dc2e8b2b6fb978a76afe33f7a2384f697b8d6cd811d", size = 20075 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/ab/6936e2663c47a926e0659437b9333ad87d1ff49b1375d239026e0a268eba/asgi_correlation_id-4.3.4-py3-none-any.whl", hash = "sha256:36ce69b06c7d96b4acb89c7556a4c4f01a972463d3d49c675026cbbd08e9a0a2", size = 15262 }, +] + [[package]] name = "assistant-drive" version = "0.1.0" source = { editable = "../../../assistant-drive" } dependencies = [ + { name = "aiofiles" }, { name = "context" }, { name = "pydantic" }, { name = "pydantic-settings" }, @@ -39,6 +144,7 @@ dependencies = [ [package.metadata] requires-dist = [ + { name = "aiofiles", specifier = ">=24.1.0" }, { name = "context", editable = "../../../context" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.5.2" }, @@ -52,6 +158,28 @@ dev = [ { name = "pytest-repeat", specifier = ">=0.9.3" }, ] +[[package]] +name = "attrs" +version = "24.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/0f/aafca9af9315aee06a89ffde799a10a582fe8de76c563ee80bbcdc08b3fb/attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", size = 792678 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2", size = 63001 }, +] + +[[package]] +name = "azure-ai-contentsafety" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "azure-core" }, + { name = "isodate" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/08/e9/c069efade0e4976d96208306f1cf0803838cdb0b60e00a2a96bd20806bff/azure-ai-contentsafety-1.0.0.tar.gz", hash = "sha256:052731bd1419a720fa00910f46bf3428c4e5bd05280da7393d0c8106d46cc6d7", size = 63806 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/39/cbb3ff28ad09434a1be7803b2846077bc3b23a8232beb489962fc818fe21/azure_ai_contentsafety-1.0.0-py3-none-any.whl", hash = "sha256:e1c5574a541f9290fdd071d23535e14b1f463af231a6f0ac0f917e125f0463cf", size = 61328 }, +] + [[package]] name = "azure-core" version = "1.31.0" @@ -66,6 +194,11 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/01/8e/fcb6a77d3029d2a7356f38dbc77cf7daa113b81ddab76b5593d23321e44c/azure_core-1.31.0-py3-none-any.whl", hash = "sha256:22954de3777e0250029360ef31d80448ef1be13b80a459bff80ba7073379e2cd", size = 197399 }, ] +[package.optional-dependencies] +aio = [ + { name = "aiohttp" }, +] + [[package]] name = "azure-identity" version = "1.18.0" @@ -82,6 +215,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b0/71/1d1bb387b6acaa5daa3e703c70dde3d54823ccd229bd6730de6e724f296e/azure_identity-1.18.0-py3-none-any.whl", hash = "sha256:bccf6106245b49ff41d0c4cd7b72851c5a2ba3a32cef7589da246f5727f26f02", size = 187179 }, ] +[[package]] +name = "backoff" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/47/d7/5bbeb12c44d7c4f2fb5b56abce497eb5ed9f34d85701de869acedd602619/backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba", size = 17001 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8", size = 15148 }, +] + [[package]] name = "certifi" version = "2024.8.30" @@ -208,6 +350,18 @@ requires-dist = [ { name = "tiktoken", specifier = ">=0.7.0" }, ] +[[package]] +name = "click" +version = "8.1.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "platform_system == 'Windows'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", size = 97941 }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -264,6 +418,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b3/c6/c09cee6968add5ff868525c3815e5dccc0e3c6e89eec58dc9135d3c40e88/cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb", size = 3070445 }, ] +[[package]] +name = "deepmerge" +version = "2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a8/3a/b0ba594708f1ad0bc735884b3ad854d3ca3bdc1d741e56e40bbda6263499/deepmerge-2.0.tar.gz", hash = "sha256:5c3d86081fbebd04dd5de03626a0607b809a98fb6ccba5770b62466fe940ff20", size = 19890 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/82/e5d2c1c67d19841e9edc74954c827444ae826978499bde3dfc1d007c8c11/deepmerge-2.0-py3-none-any.whl", hash = "sha256:6de9ce507115cff0bed95ff0ce9ecc31088ef50cbdf09bc90a09349a318b3d00", size = 13475 }, +] + [[package]] name = "distro" version = "1.9.0" @@ -273,6 +436,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277 }, ] +[[package]] +name = "dnspython" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632 }, +] + +[[package]] +name = "email-validator" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dnspython" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521 }, +] + [[package]] name = "events" version = "0.1.0" @@ -284,6 +469,48 @@ dependencies = [ [package.metadata] requires-dist = [{ name = "pydantic", specifier = ">=2.6.1" }] +[[package]] +name = "fastapi" +version = "0.115.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "starlette" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a9/db/5781f19bd30745885e0737ff3fdd4e63e7bc691710f9da691128bb0dc73b/fastapi-0.115.4.tar.gz", hash = "sha256:db653475586b091cb8b2fec2ac54a680ac6a158e07406e1abae31679e8826349", size = 300737 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/f6/af0d1f58f86002be0cf1e2665cdd6f7a4a71cdc8a7a9438cdc9e3b5375fe/fastapi-0.115.4-py3-none-any.whl", hash = "sha256:0b504a063ffb3cf96a5e27dc1bc32c80ca743a2528574f9cdc77daa2d31b4742", size = 94732 }, +] + +[package.optional-dependencies] +standard = [ + { name = "email-validator" }, + { name = "fastapi-cli", extra = ["standard"] }, + { name = "httpx" }, + { name = "jinja2" }, + { name = "python-multipart" }, + { name = "uvicorn", extra = ["standard"] }, +] + +[[package]] +name = "fastapi-cli" +version = "0.0.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typer" }, + { name = "uvicorn", extra = ["standard"] }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c5/f8/1ad5ce32d029aeb9117e9a5a9b3e314a8477525d60c12a9b7730a3c186ec/fastapi_cli-0.0.5.tar.gz", hash = "sha256:d30e1239c6f46fcb95e606f02cdda59a1e2fa778a54b64686b3ff27f6211ff9f", size = 15571 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/24/ea/4b5011012ac925fe2f83b19d0e09cee9d324141ec7bf5e78bb2817f96513/fastapi_cli-0.0.5-py3-none-any.whl", hash = "sha256:e94d847524648c748a5350673546bbf9bcaeb086b33c24f2e82e021436866a46", size = 9489 }, +] + +[package.optional-dependencies] +standard = [ + { name = "uvicorn", extra = ["standard"] }, +] + [[package]] name = "form-filler-skill" version = "0.1.0" @@ -292,6 +519,7 @@ dependencies = [ { name = "chat-driver" }, { name = "context" }, { name = "events" }, + { name = "openai-client" }, { name = "skill-library" }, ] @@ -300,9 +528,64 @@ requires-dist = [ { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, + { name = "openai-client", editable = "../../../openai-client" }, { name = "skill-library", editable = "../../skill-library" }, ] +[[package]] +name = "frozenlist" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8f/ed/0f4cec13a93c02c47ec32d81d11c0c1efbadf4a471e3f3ce7cad366cbbd3/frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817", size = 39930 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/43/0bed28bf5eb1c9e4301003b74453b8e7aa85fb293b31dde352aac528dafc/frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30", size = 94987 }, + { url = "https://files.pythonhosted.org/packages/bb/bf/b74e38f09a246e8abbe1e90eb65787ed745ccab6eaa58b9c9308e052323d/frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5", size = 54584 }, + { url = "https://files.pythonhosted.org/packages/2c/31/ab01375682f14f7613a1ade30149f684c84f9b8823a4391ed950c8285656/frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778", size = 52499 }, + { url = "https://files.pythonhosted.org/packages/98/a8/d0ac0b9276e1404f58fec3ab6e90a4f76b778a49373ccaf6a563f100dfbc/frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a", size = 276357 }, + { url = "https://files.pythonhosted.org/packages/ad/c9/c7761084fa822f07dac38ac29f841d4587570dd211e2262544aa0b791d21/frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869", size = 287516 }, + { url = "https://files.pythonhosted.org/packages/a1/ff/cd7479e703c39df7bdab431798cef89dc75010d8aa0ca2514c5b9321db27/frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d", size = 283131 }, + { url = "https://files.pythonhosted.org/packages/59/a0/370941beb47d237eca4fbf27e4e91389fd68699e6f4b0ebcc95da463835b/frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45", size = 261320 }, + { url = "https://files.pythonhosted.org/packages/b8/5f/c10123e8d64867bc9b4f2f510a32042a306ff5fcd7e2e09e5ae5100ee333/frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d", size = 274877 }, + { url = "https://files.pythonhosted.org/packages/fa/79/38c505601ae29d4348f21706c5d89755ceded02a745016ba2f58bd5f1ea6/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3", size = 269592 }, + { url = "https://files.pythonhosted.org/packages/19/e2/39f3a53191b8204ba9f0bb574b926b73dd2efba2a2b9d2d730517e8f7622/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a", size = 265934 }, + { url = "https://files.pythonhosted.org/packages/d5/c9/3075eb7f7f3a91f1a6b00284af4de0a65a9ae47084930916f5528144c9dd/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9", size = 283859 }, + { url = "https://files.pythonhosted.org/packages/05/f5/549f44d314c29408b962fa2b0e69a1a67c59379fb143b92a0a065ffd1f0f/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2", size = 287560 }, + { url = "https://files.pythonhosted.org/packages/9d/f8/cb09b3c24a3eac02c4c07a9558e11e9e244fb02bf62c85ac2106d1eb0c0b/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf", size = 277150 }, + { url = "https://files.pythonhosted.org/packages/37/48/38c2db3f54d1501e692d6fe058f45b6ad1b358d82cd19436efab80cfc965/frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942", size = 45244 }, + { url = "https://files.pythonhosted.org/packages/ca/8c/2ddffeb8b60a4bce3b196c32fcc30d8830d4615e7b492ec2071da801b8ad/frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d", size = 51634 }, + { url = "https://files.pythonhosted.org/packages/79/73/fa6d1a96ab7fd6e6d1c3500700963eab46813847f01ef0ccbaa726181dd5/frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21", size = 94026 }, + { url = "https://files.pythonhosted.org/packages/ab/04/ea8bf62c8868b8eada363f20ff1b647cf2e93377a7b284d36062d21d81d1/frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d", size = 54150 }, + { url = "https://files.pythonhosted.org/packages/d0/9a/8e479b482a6f2070b26bda572c5e6889bb3ba48977e81beea35b5ae13ece/frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e", size = 51927 }, + { url = "https://files.pythonhosted.org/packages/e3/12/2aad87deb08a4e7ccfb33600871bbe8f0e08cb6d8224371387f3303654d7/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a", size = 282647 }, + { url = "https://files.pythonhosted.org/packages/77/f2/07f06b05d8a427ea0060a9cef6e63405ea9e0d761846b95ef3fb3be57111/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a", size = 289052 }, + { url = "https://files.pythonhosted.org/packages/bd/9f/8bf45a2f1cd4aa401acd271b077989c9267ae8463e7c8b1eb0d3f561b65e/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee", size = 291719 }, + { url = "https://files.pythonhosted.org/packages/41/d1/1f20fd05a6c42d3868709b7604c9f15538a29e4f734c694c6bcfc3d3b935/frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6", size = 267433 }, + { url = "https://files.pythonhosted.org/packages/af/f2/64b73a9bb86f5a89fb55450e97cd5c1f84a862d4ff90d9fd1a73ab0f64a5/frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e", size = 283591 }, + { url = "https://files.pythonhosted.org/packages/29/e2/ffbb1fae55a791fd6c2938dd9ea779509c977435ba3940b9f2e8dc9d5316/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9", size = 273249 }, + { url = "https://files.pythonhosted.org/packages/2e/6e/008136a30798bb63618a114b9321b5971172a5abddff44a100c7edc5ad4f/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039", size = 271075 }, + { url = "https://files.pythonhosted.org/packages/ae/f0/4e71e54a026b06724cec9b6c54f0b13a4e9e298cc8db0f82ec70e151f5ce/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784", size = 285398 }, + { url = "https://files.pythonhosted.org/packages/4d/36/70ec246851478b1c0b59f11ef8ade9c482ff447c1363c2bd5fad45098b12/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631", size = 294445 }, + { url = "https://files.pythonhosted.org/packages/37/e0/47f87544055b3349b633a03c4d94b405956cf2437f4ab46d0928b74b7526/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f", size = 280569 }, + { url = "https://files.pythonhosted.org/packages/f9/7c/490133c160fb6b84ed374c266f42800e33b50c3bbab1652764e6e1fc498a/frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8", size = 44721 }, + { url = "https://files.pythonhosted.org/packages/b1/56/4e45136ffc6bdbfa68c29ca56ef53783ef4c2fd395f7cbf99a2624aa9aaa/frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f", size = 51329 }, + { url = "https://files.pythonhosted.org/packages/da/3b/915f0bca8a7ea04483622e84a9bd90033bab54bdf485479556c74fd5eaf5/frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953", size = 91538 }, + { url = "https://files.pythonhosted.org/packages/c7/d1/a7c98aad7e44afe5306a2b068434a5830f1470675f0e715abb86eb15f15b/frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0", size = 52849 }, + { url = "https://files.pythonhosted.org/packages/3a/c8/76f23bf9ab15d5f760eb48701909645f686f9c64fbb8982674c241fbef14/frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2", size = 50583 }, + { url = "https://files.pythonhosted.org/packages/1f/22/462a3dd093d11df623179d7754a3b3269de3b42de2808cddef50ee0f4f48/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f", size = 265636 }, + { url = "https://files.pythonhosted.org/packages/80/cf/e075e407fc2ae7328155a1cd7e22f932773c8073c1fc78016607d19cc3e5/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608", size = 270214 }, + { url = "https://files.pythonhosted.org/packages/a1/58/0642d061d5de779f39c50cbb00df49682832923f3d2ebfb0fedf02d05f7f/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b", size = 273905 }, + { url = "https://files.pythonhosted.org/packages/ab/66/3fe0f5f8f2add5b4ab7aa4e199f767fd3b55da26e3ca4ce2cc36698e50c4/frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840", size = 250542 }, + { url = "https://files.pythonhosted.org/packages/f6/b8/260791bde9198c87a465224e0e2bb62c4e716f5d198fc3a1dacc4895dbd1/frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439", size = 267026 }, + { url = "https://files.pythonhosted.org/packages/2e/a4/3d24f88c527f08f8d44ade24eaee83b2627793fa62fa07cbb7ff7a2f7d42/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de", size = 257690 }, + { url = "https://files.pythonhosted.org/packages/de/9a/d311d660420b2beeff3459b6626f2ab4fb236d07afbdac034a4371fe696e/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641", size = 253893 }, + { url = "https://files.pythonhosted.org/packages/c6/23/e491aadc25b56eabd0f18c53bb19f3cdc6de30b2129ee0bc39cd387cd560/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e", size = 267006 }, + { url = "https://files.pythonhosted.org/packages/08/c4/ab918ce636a35fb974d13d666dcbe03969592aeca6c3ab3835acff01f79c/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9", size = 276157 }, + { url = "https://files.pythonhosted.org/packages/c0/29/3b7a0bbbbe5a34833ba26f686aabfe982924adbdcafdc294a7a129c31688/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03", size = 264642 }, + { url = "https://files.pythonhosted.org/packages/ab/42/0595b3dbffc2e82d7fe658c12d5a5bafcd7516c6bf2d1d1feb5387caa9c1/frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c", size = 44914 }, + { url = "https://files.pythonhosted.org/packages/17/c4/b7db1206a3fea44bf3b838ca61deb6f74424a8a5db1dd53ecb21da669be6/frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28", size = 51167 }, + { url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 }, +] + [[package]] name = "function-registry" version = "0.1.0" @@ -359,6 +642,35 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/06/89/b161908e2f51be56568184aeb4a880fd287178d176fd1c860d2217f41106/httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f", size = 78011 }, ] +[[package]] +name = "httptools" +version = "0.6.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/26/bb526d4d14c2774fe07113ca1db7255737ffbb119315839af2065abfdac3/httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069", size = 199029 }, + { url = "https://files.pythonhosted.org/packages/a6/17/3e0d3e9b901c732987a45f4f94d4e2c62b89a041d93db89eafb262afd8d5/httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a", size = 103492 }, + { url = "https://files.pythonhosted.org/packages/b7/24/0fe235d7b69c42423c7698d086d4db96475f9b50b6ad26a718ef27a0bce6/httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975", size = 462891 }, + { url = "https://files.pythonhosted.org/packages/b1/2f/205d1f2a190b72da6ffb5f41a3736c26d6fa7871101212b15e9b5cd8f61d/httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636", size = 459788 }, + { url = "https://files.pythonhosted.org/packages/6e/4c/d09ce0eff09057a206a74575ae8f1e1e2f0364d20e2442224f9e6612c8b9/httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721", size = 433214 }, + { url = "https://files.pythonhosted.org/packages/3e/d2/84c9e23edbccc4a4c6f96a1b8d99dfd2350289e94f00e9ccc7aadde26fb5/httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988", size = 434120 }, + { url = "https://files.pythonhosted.org/packages/d0/46/4d8e7ba9581416de1c425b8264e2cadd201eb709ec1584c381f3e98f51c1/httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17", size = 88565 }, + { url = "https://files.pythonhosted.org/packages/bb/0e/d0b71465c66b9185f90a091ab36389a7352985fe857e352801c39d6127c8/httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2", size = 200683 }, + { url = "https://files.pythonhosted.org/packages/e2/b8/412a9bb28d0a8988de3296e01efa0bd62068b33856cdda47fe1b5e890954/httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44", size = 104337 }, + { url = "https://files.pythonhosted.org/packages/9b/01/6fb20be3196ffdc8eeec4e653bc2a275eca7f36634c86302242c4fbb2760/httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1", size = 508796 }, + { url = "https://files.pythonhosted.org/packages/f7/d8/b644c44acc1368938317d76ac991c9bba1166311880bcc0ac297cb9d6bd7/httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2", size = 510837 }, + { url = "https://files.pythonhosted.org/packages/52/d8/254d16a31d543073a0e57f1c329ca7378d8924e7e292eda72d0064987486/httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81", size = 485289 }, + { url = "https://files.pythonhosted.org/packages/5f/3c/4aee161b4b7a971660b8be71a92c24d6c64372c1ab3ae7f366b3680df20f/httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", size = 489779 }, + { url = "https://files.pythonhosted.org/packages/12/b7/5cae71a8868e555f3f67a50ee7f673ce36eac970f029c0c5e9d584352961/httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970", size = 88634 }, + { url = "https://files.pythonhosted.org/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214 }, + { url = "https://files.pythonhosted.org/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431 }, + { url = "https://files.pythonhosted.org/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121 }, + { url = "https://files.pythonhosted.org/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071", size = 473805 }, + { url = "https://files.pythonhosted.org/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858 }, + { url = "https://files.pythonhosted.org/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042 }, + { url = "https://files.pythonhosted.org/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682 }, +] + [[package]] name = "httpx" version = "0.27.2" @@ -393,6 +705,27 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl", hash = "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717", size = 36115 }, ] +[[package]] +name = "isodate" +version = "0.7.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/4d/e940025e2ce31a8ce1202635910747e5a87cc3a6a6bb2d00973375014749/isodate-0.7.2.tar.gz", hash = "sha256:4cd1aa0f43ca76f4a6c6c0292a85f40b35ec2e43e315b59f06e6d32171a953e6", size = 29705 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/15/aa/0aca39a37d3c7eb941ba736ede56d689e7be91cab5d9ca846bde3999eba6/isodate-0.7.2-py3-none-any.whl", hash = "sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15", size = 22320 }, +] + +[[package]] +name = "jinja2" +version = "3.1.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ed/55/39036716d19cab0747a5020fc7e907f362fbf48c984b14e62127f7e68e5d/jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", size = 240245 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d", size = 133271 }, +] + [[package]] name = "jiter" version = "0.5.0" @@ -425,6 +758,75 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/15/81/296b1e25c43db67848728cdab34ac3eb5c5cbb4955ceb3f51ae60d4a5e3d/jiter-0.5.0-cp312-none-win_amd64.whl", hash = "sha256:a586832f70c3f1481732919215f36d41c59ca080fa27a65cf23d9490e75b2ef5", size = 189720 }, ] +[[package]] +name = "markdown-it-py" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353 }, + { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392 }, + { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984 }, + { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120 }, + { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032 }, + { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057 }, + { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359 }, + { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306 }, + { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094 }, + { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521 }, + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, +] + [[package]] name = "msal" version = "1.31.0" @@ -452,6 +854,60 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2c/69/314d887a01599669fb330da14e5c6ff5f138609e322812a942a74ef9b765/msal_extensions-1.2.0-py3-none-any.whl", hash = "sha256:cf5ba83a2113fa6dc011a254a72f1c223c88d7dfad74cc30617c4679a417704d", size = 19254 }, ] +[[package]] +name = "multidict" +version = "6.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/be/504b89a5e9ca731cd47487e91c469064f8ae5af93b7259758dcfc2b9c848/multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a", size = 64002 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/13/df3505a46d0cd08428e4c8169a196131d1b0c4b515c3649829258843dde6/multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6", size = 48570 }, + { url = "https://files.pythonhosted.org/packages/f0/e1/a215908bfae1343cdb72f805366592bdd60487b4232d039c437fe8f5013d/multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156", size = 29316 }, + { url = "https://files.pythonhosted.org/packages/70/0f/6dc70ddf5d442702ed74f298d69977f904960b82368532c88e854b79f72b/multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb", size = 29640 }, + { url = "https://files.pythonhosted.org/packages/d8/6d/9c87b73a13d1cdea30b321ef4b3824449866bd7f7127eceed066ccb9b9ff/multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b", size = 131067 }, + { url = "https://files.pythonhosted.org/packages/cc/1e/1b34154fef373371fd6c65125b3d42ff5f56c7ccc6bfff91b9b3c60ae9e0/multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72", size = 138507 }, + { url = "https://files.pythonhosted.org/packages/fb/e0/0bc6b2bac6e461822b5f575eae85da6aae76d0e2a79b6665d6206b8e2e48/multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304", size = 133905 }, + { url = "https://files.pythonhosted.org/packages/ba/af/73d13b918071ff9b2205fcf773d316e0f8fefb4ec65354bbcf0b10908cc6/multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351", size = 129004 }, + { url = "https://files.pythonhosted.org/packages/74/21/23960627b00ed39643302d81bcda44c9444ebcdc04ee5bedd0757513f259/multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb", size = 121308 }, + { url = "https://files.pythonhosted.org/packages/8b/5c/cf282263ffce4a596ed0bb2aa1a1dddfe1996d6a62d08842a8d4b33dca13/multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3", size = 132608 }, + { url = "https://files.pythonhosted.org/packages/d7/3e/97e778c041c72063f42b290888daff008d3ab1427f5b09b714f5a8eff294/multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399", size = 127029 }, + { url = "https://files.pythonhosted.org/packages/47/ac/3efb7bfe2f3aefcf8d103e9a7162572f01936155ab2f7ebcc7c255a23212/multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423", size = 137594 }, + { url = "https://files.pythonhosted.org/packages/42/9b/6c6e9e8dc4f915fc90a9b7798c44a30773dea2995fdcb619870e705afe2b/multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3", size = 134556 }, + { url = "https://files.pythonhosted.org/packages/1d/10/8e881743b26aaf718379a14ac58572a240e8293a1c9d68e1418fb11c0f90/multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753", size = 130993 }, + { url = "https://files.pythonhosted.org/packages/45/84/3eb91b4b557442802d058a7579e864b329968c8d0ea57d907e7023c677f2/multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80", size = 26405 }, + { url = "https://files.pythonhosted.org/packages/9f/0b/ad879847ecbf6d27e90a6eabb7eff6b62c129eefe617ea45eae7c1f0aead/multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926", size = 28795 }, + { url = "https://files.pythonhosted.org/packages/fd/16/92057c74ba3b96d5e211b553895cd6dc7cc4d1e43d9ab8fafc727681ef71/multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa", size = 48713 }, + { url = "https://files.pythonhosted.org/packages/94/3d/37d1b8893ae79716179540b89fc6a0ee56b4a65fcc0d63535c6f5d96f217/multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436", size = 29516 }, + { url = "https://files.pythonhosted.org/packages/a2/12/adb6b3200c363062f805275b4c1e656be2b3681aada66c80129932ff0bae/multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761", size = 29557 }, + { url = "https://files.pythonhosted.org/packages/47/e9/604bb05e6e5bce1e6a5cf80a474e0f072e80d8ac105f1b994a53e0b28c42/multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e", size = 130170 }, + { url = "https://files.pythonhosted.org/packages/7e/13/9efa50801785eccbf7086b3c83b71a4fb501a4d43549c2f2f80b8787d69f/multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef", size = 134836 }, + { url = "https://files.pythonhosted.org/packages/bf/0f/93808b765192780d117814a6dfcc2e75de6dcc610009ad408b8814dca3ba/multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95", size = 133475 }, + { url = "https://files.pythonhosted.org/packages/d3/c8/529101d7176fe7dfe1d99604e48d69c5dfdcadb4f06561f465c8ef12b4df/multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925", size = 131049 }, + { url = "https://files.pythonhosted.org/packages/ca/0c/fc85b439014d5a58063e19c3a158a889deec399d47b5269a0f3b6a2e28bc/multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966", size = 120370 }, + { url = "https://files.pythonhosted.org/packages/db/46/d4416eb20176492d2258fbd47b4abe729ff3b6e9c829ea4236f93c865089/multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305", size = 125178 }, + { url = "https://files.pythonhosted.org/packages/5b/46/73697ad7ec521df7de5531a32780bbfd908ded0643cbe457f981a701457c/multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2", size = 119567 }, + { url = "https://files.pythonhosted.org/packages/cd/ed/51f060e2cb0e7635329fa6ff930aa5cffa17f4c7f5c6c3ddc3500708e2f2/multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2", size = 129822 }, + { url = "https://files.pythonhosted.org/packages/df/9e/ee7d1954b1331da3eddea0c4e08d9142da5f14b1321c7301f5014f49d492/multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6", size = 128656 }, + { url = "https://files.pythonhosted.org/packages/77/00/8538f11e3356b5d95fa4b024aa566cde7a38aa7a5f08f4912b32a037c5dc/multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", size = 125360 }, + { url = "https://files.pythonhosted.org/packages/be/05/5d334c1f2462d43fec2363cd00b1c44c93a78c3925d952e9a71caf662e96/multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", size = 26382 }, + { url = "https://files.pythonhosted.org/packages/a3/bf/f332a13486b1ed0496d624bcc7e8357bb8053823e8cd4b9a18edc1d97e73/multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", size = 28529 }, + { url = "https://files.pythonhosted.org/packages/22/67/1c7c0f39fe069aa4e5d794f323be24bf4d33d62d2a348acdb7991f8f30db/multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008", size = 48771 }, + { url = "https://files.pythonhosted.org/packages/3c/25/c186ee7b212bdf0df2519eacfb1981a017bda34392c67542c274651daf23/multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f", size = 29533 }, + { url = "https://files.pythonhosted.org/packages/67/5e/04575fd837e0958e324ca035b339cea174554f6f641d3fb2b4f2e7ff44a2/multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28", size = 29595 }, + { url = "https://files.pythonhosted.org/packages/d3/b2/e56388f86663810c07cfe4a3c3d87227f3811eeb2d08450b9e5d19d78876/multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b", size = 130094 }, + { url = "https://files.pythonhosted.org/packages/6c/ee/30ae9b4186a644d284543d55d491fbd4239b015d36b23fea43b4c94f7052/multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c", size = 134876 }, + { url = "https://files.pythonhosted.org/packages/84/c7/70461c13ba8ce3c779503c70ec9d0345ae84de04521c1f45a04d5f48943d/multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3", size = 133500 }, + { url = "https://files.pythonhosted.org/packages/4a/9f/002af221253f10f99959561123fae676148dd730e2daa2cd053846a58507/multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44", size = 131099 }, + { url = "https://files.pythonhosted.org/packages/82/42/d1c7a7301d52af79d88548a97e297f9d99c961ad76bbe6f67442bb77f097/multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2", size = 120403 }, + { url = "https://files.pythonhosted.org/packages/68/f3/471985c2c7ac707547553e8f37cff5158030d36bdec4414cb825fbaa5327/multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3", size = 125348 }, + { url = "https://files.pythonhosted.org/packages/67/2c/e6df05c77e0e433c214ec1d21ddd203d9a4770a1f2866a8ca40a545869a0/multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa", size = 119673 }, + { url = "https://files.pythonhosted.org/packages/c5/cd/bc8608fff06239c9fb333f9db7743a1b2eafe98c2666c9a196e867a3a0a4/multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa", size = 129927 }, + { url = "https://files.pythonhosted.org/packages/44/8e/281b69b7bc84fc963a44dc6e0bbcc7150e517b91df368a27834299a526ac/multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4", size = 128711 }, + { url = "https://files.pythonhosted.org/packages/12/a4/63e7cd38ed29dd9f1881d5119f272c898ca92536cdb53ffe0843197f6c85/multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6", size = 125519 }, + { url = "https://files.pythonhosted.org/packages/38/e0/4f5855037a72cd8a7a2f60a3952d9aa45feedb37ae7831642102604e8a37/multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81", size = 26426 }, + { url = "https://files.pythonhosted.org/packages/7e/a5/17ee3a4db1e310b7405f5d25834460073a8ccd86198ce044dfaf69eac073/multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774", size = 28531 }, + { url = "https://files.pythonhosted.org/packages/99/b7/b9e70fde2c0f0c9af4cc5277782a89b66d35948ea3369ec9f598358c3ac5/multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", size = 10051 }, +] + [[package]] name = "openai" version = "1.51.0" @@ -471,6 +927,92 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/08/9f22356d4fbd273f734db1e6663b7ca6987943080567f5580471022e57ca/openai-1.51.0-py3-none-any.whl", hash = "sha256:d9affafb7e51e5a27dce78589d4964ce4d6f6d560307265933a94b2e3f3c5d2c", size = 383533 }, ] +[[package]] +name = "openai-client" +version = "0.1.0" +source = { editable = "../../../openai-client" } +dependencies = [ + { name = "azure-ai-contentsafety" }, + { name = "azure-core", extra = ["aio"] }, + { name = "azure-identity" }, + { name = "openai" }, + { name = "pillow" }, + { name = "semantic-workbench-assistant" }, + { name = "tiktoken" }, +] + +[package.metadata] +requires-dist = [ + { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, + { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, + { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "openai", specifier = ">=1.3.9" }, + { name = "pillow", specifier = ">=11.0.0" }, + { name = "semantic-workbench-assistant", editable = "../../../semantic-workbench-assistant" }, + { name = "tiktoken", specifier = ">=0.7.0" }, +] + +[package.metadata.requires-dev] +dev = [{ name = "pytest", specifier = ">=8.3.3" }] + +[[package]] +name = "packaging" +version = "24.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/51/65/50db4dda066951078f0a96cf12f4b9ada6e4b811516bf0262c0f4f7064d4/packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", size = 148788 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124", size = 53985 }, +] + +[[package]] +name = "pillow" +version = "11.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/26/0d95c04c868f6bdb0c447e3ee2de5564411845e36a858cfd63766bc7b563/pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739", size = 46737780 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f0/eb/f7e21b113dd48a9c97d364e0915b3988c6a0b6207652f5a92372871b7aa4/pillow-11.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1c1d72714f429a521d8d2d018badc42414c3077eb187a59579f28e4270b4b0fc", size = 3154705 }, + { url = "https://files.pythonhosted.org/packages/25/b3/2b54a1d541accebe6bd8b1358b34ceb2c509f51cb7dcda8687362490da5b/pillow-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:499c3a1b0d6fc8213519e193796eb1a86a1be4b1877d678b30f83fd979811d1a", size = 2979222 }, + { url = "https://files.pythonhosted.org/packages/20/12/1a41eddad8265c5c19dda8fb6c269ce15ee25e0b9f8f26286e6202df6693/pillow-11.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8b2351c85d855293a299038e1f89db92a2f35e8d2f783489c6f0b2b5f3fe8a3", size = 4190220 }, + { url = "https://files.pythonhosted.org/packages/a9/9b/8a8c4d07d77447b7457164b861d18f5a31ae6418ef5c07f6f878fa09039a/pillow-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4dba50cfa56f910241eb7f883c20f1e7b1d8f7d91c750cd0b318bad443f4d5", size = 4291399 }, + { url = "https://files.pythonhosted.org/packages/fc/e4/130c5fab4a54d3991129800dd2801feeb4b118d7630148cd67f0e6269d4c/pillow-11.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5ddbfd761ee00c12ee1be86c9c0683ecf5bb14c9772ddbd782085779a63dd55b", size = 4202709 }, + { url = "https://files.pythonhosted.org/packages/39/63/b3fc299528d7df1f678b0666002b37affe6b8751225c3d9c12cf530e73ed/pillow-11.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa", size = 4372556 }, + { url = "https://files.pythonhosted.org/packages/c6/a6/694122c55b855b586c26c694937d36bb8d3b09c735ff41b2f315c6e66a10/pillow-11.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b4fd7bd29610a83a8c9b564d457cf5bd92b4e11e79a4ee4716a63c959699b306", size = 4287187 }, + { url = "https://files.pythonhosted.org/packages/ba/a9/f9d763e2671a8acd53d29b1e284ca298bc10a595527f6be30233cdb9659d/pillow-11.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cb929ca942d0ec4fac404cbf520ee6cac37bf35be479b970c4ffadf2b6a1cad9", size = 4418468 }, + { url = "https://files.pythonhosted.org/packages/6e/0e/b5cbad2621377f11313a94aeb44ca55a9639adabcaaa073597a1925f8c26/pillow-11.0.0-cp311-cp311-win32.whl", hash = "sha256:006bcdd307cc47ba43e924099a038cbf9591062e6c50e570819743f5607404f5", size = 2249249 }, + { url = "https://files.pythonhosted.org/packages/dc/83/1470c220a4ff06cd75fc609068f6605e567ea51df70557555c2ab6516b2c/pillow-11.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:52a2d8323a465f84faaba5236567d212c3668f2ab53e1c74c15583cf507a0291", size = 2566769 }, + { url = "https://files.pythonhosted.org/packages/52/98/def78c3a23acee2bcdb2e52005fb2810ed54305602ec1bfcfab2bda6f49f/pillow-11.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:16095692a253047fe3ec028e951fa4221a1f3ed3d80c397e83541a3037ff67c9", size = 2254611 }, + { url = "https://files.pythonhosted.org/packages/1c/a3/26e606ff0b2daaf120543e537311fa3ae2eb6bf061490e4fea51771540be/pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923", size = 3147642 }, + { url = "https://files.pythonhosted.org/packages/4f/d5/1caabedd8863526a6cfa44ee7a833bd97f945dc1d56824d6d76e11731939/pillow-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903", size = 2978999 }, + { url = "https://files.pythonhosted.org/packages/d9/ff/5a45000826a1aa1ac6874b3ec5a856474821a1b59d838c4f6ce2ee518fe9/pillow-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4", size = 4196794 }, + { url = "https://files.pythonhosted.org/packages/9d/21/84c9f287d17180f26263b5f5c8fb201de0f88b1afddf8a2597a5c9fe787f/pillow-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f", size = 4300762 }, + { url = "https://files.pythonhosted.org/packages/84/39/63fb87cd07cc541438b448b1fed467c4d687ad18aa786a7f8e67b255d1aa/pillow-11.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9", size = 4210468 }, + { url = "https://files.pythonhosted.org/packages/7f/42/6e0f2c2d5c60f499aa29be14f860dd4539de322cd8fb84ee01553493fb4d/pillow-11.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7", size = 4381824 }, + { url = "https://files.pythonhosted.org/packages/31/69/1ef0fb9d2f8d2d114db982b78ca4eeb9db9a29f7477821e160b8c1253f67/pillow-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6", size = 4296436 }, + { url = "https://files.pythonhosted.org/packages/44/ea/dad2818c675c44f6012289a7c4f46068c548768bc6c7f4e8c4ae5bbbc811/pillow-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc", size = 4429714 }, + { url = "https://files.pythonhosted.org/packages/af/3a/da80224a6eb15bba7a0dcb2346e2b686bb9bf98378c0b4353cd88e62b171/pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6", size = 2249631 }, + { url = "https://files.pythonhosted.org/packages/57/97/73f756c338c1d86bb802ee88c3cab015ad7ce4b838f8a24f16b676b1ac7c/pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47", size = 2567533 }, + { url = "https://files.pythonhosted.org/packages/0b/30/2b61876e2722374558b871dfbfcbe4e406626d63f4f6ed92e9c8e24cac37/pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25", size = 2254890 }, + { url = "https://files.pythonhosted.org/packages/63/24/e2e15e392d00fcf4215907465d8ec2a2f23bcec1481a8ebe4ae760459995/pillow-11.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699", size = 3147300 }, + { url = "https://files.pythonhosted.org/packages/43/72/92ad4afaa2afc233dc44184adff289c2e77e8cd916b3ddb72ac69495bda3/pillow-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38", size = 2978742 }, + { url = "https://files.pythonhosted.org/packages/9e/da/c8d69c5bc85d72a8523fe862f05ababdc52c0a755cfe3d362656bb86552b/pillow-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2", size = 4194349 }, + { url = "https://files.pythonhosted.org/packages/cd/e8/686d0caeed6b998351d57796496a70185376ed9c8ec7d99e1d19ad591fc6/pillow-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2", size = 4298714 }, + { url = "https://files.pythonhosted.org/packages/ec/da/430015cec620d622f06854be67fd2f6721f52fc17fca8ac34b32e2d60739/pillow-11.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527", size = 4208514 }, + { url = "https://files.pythonhosted.org/packages/44/ae/7e4f6662a9b1cb5f92b9cc9cab8321c381ffbee309210940e57432a4063a/pillow-11.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa", size = 4380055 }, + { url = "https://files.pythonhosted.org/packages/74/d5/1a807779ac8a0eeed57f2b92a3c32ea1b696e6140c15bd42eaf908a261cd/pillow-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f", size = 4296751 }, + { url = "https://files.pythonhosted.org/packages/38/8c/5fa3385163ee7080bc13026d59656267daaaaf3c728c233d530e2c2757c8/pillow-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb", size = 4430378 }, + { url = "https://files.pythonhosted.org/packages/ca/1d/ad9c14811133977ff87035bf426875b93097fb50af747793f013979facdb/pillow-11.0.0-cp313-cp313-win32.whl", hash = "sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798", size = 2249588 }, + { url = "https://files.pythonhosted.org/packages/fb/01/3755ba287dac715e6afdb333cb1f6d69740a7475220b4637b5ce3d78cec2/pillow-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de", size = 2567509 }, + { url = "https://files.pythonhosted.org/packages/c0/98/2c7d727079b6be1aba82d195767d35fcc2d32204c7a5820f822df5330152/pillow-11.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84", size = 2254791 }, + { url = "https://files.pythonhosted.org/packages/eb/38/998b04cc6f474e78b563716b20eecf42a2fa16a84589d23c8898e64b0ffd/pillow-11.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b", size = 3150854 }, + { url = "https://files.pythonhosted.org/packages/13/8e/be23a96292113c6cb26b2aa3c8b3681ec62b44ed5c2bd0b258bd59503d3c/pillow-11.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003", size = 2982369 }, + { url = "https://files.pythonhosted.org/packages/97/8a/3db4eaabb7a2ae8203cd3a332a005e4aba00067fc514aaaf3e9721be31f1/pillow-11.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2", size = 4333703 }, + { url = "https://files.pythonhosted.org/packages/28/ac/629ffc84ff67b9228fe87a97272ab125bbd4dc462745f35f192d37b822f1/pillow-11.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a", size = 4412550 }, + { url = "https://files.pythonhosted.org/packages/d6/07/a505921d36bb2df6868806eaf56ef58699c16c388e378b0dcdb6e5b2fb36/pillow-11.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8", size = 4461038 }, + { url = "https://files.pythonhosted.org/packages/d6/b9/fb620dd47fc7cc9678af8f8bd8c772034ca4977237049287e99dda360b66/pillow-11.0.0-cp313-cp313t-win32.whl", hash = "sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8", size = 2253197 }, + { url = "https://files.pythonhosted.org/packages/df/86/25dde85c06c89d7fc5db17940f07aae0a56ac69aa9ccb5eb0f09798862a8/pillow-11.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904", size = 2572169 }, + { url = "https://files.pythonhosted.org/packages/51/85/9c33f2517add612e17f3381aee7c4072779130c634921a756c97bc29fb49/pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3", size = 2256828 }, +] + [[package]] name = "portalocker" version = "2.10.1" @@ -483,6 +1025,63 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9b/fb/a70a4214956182e0d7a9099ab17d50bfcba1056188e9b14f35b9e2b62a0d/portalocker-2.10.1-py3-none-any.whl", hash = "sha256:53a5984ebc86a025552264b459b46a2086e269b21823cb572f8f28ee759e45bf", size = 18423 }, ] +[[package]] +name = "propcache" +version = "0.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/4d/5e5a60b78dbc1d464f8a7bbaeb30957257afdc8512cbb9dfd5659304f5cd/propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70", size = 40951 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/1c/71eec730e12aec6511e702ad0cd73c2872eccb7cad39de8ba3ba9de693ef/propcache-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354", size = 80811 }, + { url = "https://files.pythonhosted.org/packages/89/c3/7e94009f9a4934c48a371632197406a8860b9f08e3f7f7d922ab69e57a41/propcache-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de", size = 46365 }, + { url = "https://files.pythonhosted.org/packages/c0/1d/c700d16d1d6903aeab28372fe9999762f074b80b96a0ccc953175b858743/propcache-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87", size = 45602 }, + { url = "https://files.pythonhosted.org/packages/2e/5e/4a3e96380805bf742712e39a4534689f4cddf5fa2d3a93f22e9fd8001b23/propcache-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016", size = 236161 }, + { url = "https://files.pythonhosted.org/packages/a5/85/90132481183d1436dff6e29f4fa81b891afb6cb89a7306f32ac500a25932/propcache-0.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb", size = 244938 }, + { url = "https://files.pythonhosted.org/packages/4a/89/c893533cb45c79c970834274e2d0f6d64383ec740be631b6a0a1d2b4ddc0/propcache-0.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2", size = 243576 }, + { url = "https://files.pythonhosted.org/packages/8c/56/98c2054c8526331a05f205bf45cbb2cda4e58e56df70e76d6a509e5d6ec6/propcache-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4", size = 236011 }, + { url = "https://files.pythonhosted.org/packages/2d/0c/8b8b9f8a6e1abd869c0fa79b907228e7abb966919047d294ef5df0d136cf/propcache-0.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504", size = 224834 }, + { url = "https://files.pythonhosted.org/packages/18/bb/397d05a7298b7711b90e13108db697732325cafdcd8484c894885c1bf109/propcache-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178", size = 224946 }, + { url = "https://files.pythonhosted.org/packages/25/19/4fc08dac19297ac58135c03770b42377be211622fd0147f015f78d47cd31/propcache-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d", size = 217280 }, + { url = "https://files.pythonhosted.org/packages/7e/76/c79276a43df2096ce2aba07ce47576832b1174c0c480fe6b04bd70120e59/propcache-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2", size = 220088 }, + { url = "https://files.pythonhosted.org/packages/c3/9a/8a8cf428a91b1336b883f09c8b884e1734c87f724d74b917129a24fe2093/propcache-0.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db", size = 233008 }, + { url = "https://files.pythonhosted.org/packages/25/7b/768a8969abd447d5f0f3333df85c6a5d94982a1bc9a89c53c154bf7a8b11/propcache-0.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b", size = 237719 }, + { url = "https://files.pythonhosted.org/packages/ed/0d/e5d68ccc7976ef8b57d80613ac07bbaf0614d43f4750cf953f0168ef114f/propcache-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b", size = 227729 }, + { url = "https://files.pythonhosted.org/packages/05/64/17eb2796e2d1c3d0c431dc5f40078d7282f4645af0bb4da9097fbb628c6c/propcache-0.2.0-cp311-cp311-win32.whl", hash = "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1", size = 40473 }, + { url = "https://files.pythonhosted.org/packages/83/c5/e89fc428ccdc897ade08cd7605f174c69390147526627a7650fb883e0cd0/propcache-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71", size = 44921 }, + { url = "https://files.pythonhosted.org/packages/7c/46/a41ca1097769fc548fc9216ec4c1471b772cc39720eb47ed7e38ef0006a9/propcache-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2", size = 80800 }, + { url = "https://files.pythonhosted.org/packages/75/4f/93df46aab9cc473498ff56be39b5f6ee1e33529223d7a4d8c0a6101a9ba2/propcache-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7", size = 46443 }, + { url = "https://files.pythonhosted.org/packages/0b/17/308acc6aee65d0f9a8375e36c4807ac6605d1f38074b1581bd4042b9fb37/propcache-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8", size = 45676 }, + { url = "https://files.pythonhosted.org/packages/65/44/626599d2854d6c1d4530b9a05e7ff2ee22b790358334b475ed7c89f7d625/propcache-0.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793", size = 246191 }, + { url = "https://files.pythonhosted.org/packages/f2/df/5d996d7cb18df076debae7d76ac3da085c0575a9f2be6b1f707fe227b54c/propcache-0.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09", size = 251791 }, + { url = "https://files.pythonhosted.org/packages/2e/6d/9f91e5dde8b1f662f6dd4dff36098ed22a1ef4e08e1316f05f4758f1576c/propcache-0.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89", size = 253434 }, + { url = "https://files.pythonhosted.org/packages/3c/e9/1b54b7e26f50b3e0497cd13d3483d781d284452c2c50dd2a615a92a087a3/propcache-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e", size = 248150 }, + { url = "https://files.pythonhosted.org/packages/a7/ef/a35bf191c8038fe3ce9a414b907371c81d102384eda5dbafe6f4dce0cf9b/propcache-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9", size = 233568 }, + { url = "https://files.pythonhosted.org/packages/97/d9/d00bb9277a9165a5e6d60f2142cd1a38a750045c9c12e47ae087f686d781/propcache-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4", size = 229874 }, + { url = "https://files.pythonhosted.org/packages/8e/78/c123cf22469bdc4b18efb78893e69c70a8b16de88e6160b69ca6bdd88b5d/propcache-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c", size = 225857 }, + { url = "https://files.pythonhosted.org/packages/31/1b/fd6b2f1f36d028820d35475be78859d8c89c8f091ad30e377ac49fd66359/propcache-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887", size = 227604 }, + { url = "https://files.pythonhosted.org/packages/99/36/b07be976edf77a07233ba712e53262937625af02154353171716894a86a6/propcache-0.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57", size = 238430 }, + { url = "https://files.pythonhosted.org/packages/0d/64/5822f496c9010e3966e934a011ac08cac8734561842bc7c1f65586e0683c/propcache-0.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23", size = 244814 }, + { url = "https://files.pythonhosted.org/packages/fd/bd/8657918a35d50b18a9e4d78a5df7b6c82a637a311ab20851eef4326305c1/propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348", size = 235922 }, + { url = "https://files.pythonhosted.org/packages/a8/6f/ec0095e1647b4727db945213a9f395b1103c442ef65e54c62e92a72a3f75/propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5", size = 40177 }, + { url = "https://files.pythonhosted.org/packages/20/a2/bd0896fdc4f4c1db46d9bc361c8c79a9bf08ccc08ba054a98e38e7ba1557/propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3", size = 44446 }, + { url = "https://files.pythonhosted.org/packages/a8/a7/5f37b69197d4f558bfef5b4bceaff7c43cc9b51adf5bd75e9081d7ea80e4/propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7", size = 78120 }, + { url = "https://files.pythonhosted.org/packages/c8/cd/48ab2b30a6b353ecb95a244915f85756d74f815862eb2ecc7a518d565b48/propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763", size = 45127 }, + { url = "https://files.pythonhosted.org/packages/a5/ba/0a1ef94a3412aab057bd996ed5f0ac7458be5bf469e85c70fa9ceb43290b/propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d", size = 44419 }, + { url = "https://files.pythonhosted.org/packages/b4/6c/ca70bee4f22fa99eacd04f4d2f1699be9d13538ccf22b3169a61c60a27fa/propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a", size = 229611 }, + { url = "https://files.pythonhosted.org/packages/19/70/47b872a263e8511ca33718d96a10c17d3c853aefadeb86dc26e8421184b9/propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b", size = 234005 }, + { url = "https://files.pythonhosted.org/packages/4f/be/3b0ab8c84a22e4a3224719099c1229ddfdd8a6a1558cf75cb55ee1e35c25/propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb", size = 237270 }, + { url = "https://files.pythonhosted.org/packages/04/d8/f071bb000d4b8f851d312c3c75701e586b3f643fe14a2e3409b1b9ab3936/propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf", size = 231877 }, + { url = "https://files.pythonhosted.org/packages/93/e7/57a035a1359e542bbb0a7df95aad6b9871ebee6dce2840cb157a415bd1f3/propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2", size = 217848 }, + { url = "https://files.pythonhosted.org/packages/f0/93/d1dea40f112ec183398fb6c42fde340edd7bab202411c4aa1a8289f461b6/propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f", size = 216987 }, + { url = "https://files.pythonhosted.org/packages/62/4c/877340871251145d3522c2b5d25c16a1690ad655fbab7bb9ece6b117e39f/propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136", size = 212451 }, + { url = "https://files.pythonhosted.org/packages/7c/bb/a91b72efeeb42906ef58ccf0cdb87947b54d7475fee3c93425d732f16a61/propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325", size = 212879 }, + { url = "https://files.pythonhosted.org/packages/9b/7f/ee7fea8faac57b3ec5d91ff47470c6c5d40d7f15d0b1fccac806348fa59e/propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44", size = 222288 }, + { url = "https://files.pythonhosted.org/packages/ff/d7/acd67901c43d2e6b20a7a973d9d5fd543c6e277af29b1eb0e1f7bd7ca7d2/propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83", size = 228257 }, + { url = "https://files.pythonhosted.org/packages/8d/6f/6272ecc7a8daad1d0754cfc6c8846076a8cb13f810005c79b15ce0ef0cf2/propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544", size = 221075 }, + { url = "https://files.pythonhosted.org/packages/7c/bd/c7a6a719a6b3dd8b3aeadb3675b5783983529e4a3185946aa444d3e078f6/propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032", size = 39654 }, + { url = "https://files.pythonhosted.org/packages/88/e7/0eef39eff84fa3e001b44de0bd41c7c0e3432e7648ffd3d64955910f002d/propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e", size = 43705 }, + { url = "https://files.pythonhosted.org/packages/3d/b6/e6d98278f2d49b22b4d033c9f792eda783b9ab2094b041f013fc69bcde87/propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036", size = 11603 }, +] + [[package]] name = "pycparser" version = "2.22" @@ -566,6 +1165,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/29/8d/29e82e333f32d9e2051c10764b906c2a6cd140992910b5f49762790911ba/pydantic_settings-2.5.2-py3-none-any.whl", hash = "sha256:2c912e55fd5794a59bf8c832b9de832dcfdf4778d79ff79b708744eed499a907", size = 26864 }, ] +[[package]] +name = "pygments" +version = "2.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", size = 4891905 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", size = 1205513 }, +] + [[package]] name = "pyjwt" version = "2.9.0" @@ -601,6 +1209,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 }, ] +[[package]] +name = "python-json-logger" +version = "2.0.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/da/95963cebfc578dabd323d7263958dfb68898617912bb09327dd30e9c8d13/python-json-logger-2.0.7.tar.gz", hash = "sha256:23e7ec02d34237c5aa1e29a070193a4ea87583bb4e7f8fd06d3de8264c4b2e1c", size = 10508 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/a6/145655273568ee78a581e734cf35beb9e33a370b29c5d3c8fee3744de29f/python_json_logger-2.0.7-py3-none-any.whl", hash = "sha256:f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd", size = 8067 }, +] + [[package]] name = "python-liquid" version = "1.12.1" @@ -615,6 +1232,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2c/6e/bfd01926e28f6cf355a7a8460271ba135013870f5857b06f35dbf65ab237/python_liquid-1.12.1-py3-none-any.whl", hash = "sha256:2224312944be16c1a44406398eb8a07c7e57398d5c0ef15ff950946dbefe7c33", size = 206592 }, ] +[[package]] +name = "python-multipart" +version = "0.0.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b9/59/cbb0dc4eb07c2676d964d7ef986314abd0b90ef2b683864a04c13590487d/python_multipart-0.0.16.tar.gz", hash = "sha256:8dee37b88dab9b59922ca173c35acb627cc12ec74019f5cd4578369c6df36554", size = 36404 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/ec/e85b99fda29a3e7643ee39419fdd478782dbcd61c11d846a9a8fc748fff2/python_multipart-0.0.16-py3-none-any.whl", hash = "sha256:c2759b7b976ef3937214dfb592446b59dfaa5f04682a076f78b117c94776d87a", size = 24426 }, +] + [[package]] name = "pywin32" version = "306" @@ -628,6 +1254,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1c/43/e3444dc9a12f8365d9603c2145d16bf0a2f8180f343cf87be47f5579e547/pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040", size = 10388145 }, ] +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612 }, + { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040 }, + { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829 }, + { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167 }, + { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952 }, + { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301 }, + { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638 }, + { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850 }, + { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980 }, + { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 }, + { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 }, + { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 }, + { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 }, + { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 }, + { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, + { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 }, + { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 }, + { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 }, + { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 }, + { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 }, + { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 }, + { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, +] + [[package]] name = "regex" version = "2024.9.11" @@ -696,6 +1357,78 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, ] +[[package]] +name = "rich" +version = "13.9.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/e9/cf9ef5245d835065e6673781dbd4b8911d352fb770d56cf0879cf11b7ee1/rich-13.9.3.tar.gz", hash = "sha256:bc1e01b899537598cf02579d2b9f4a415104d3fc439313a7a2c165d76557a08e", size = 222889 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/e2/10e9819cf4a20bd8ea2f5dabafc2e6bf4a78d6a0965daeb60a4b34d1c11f/rich-13.9.3-py3-none-any.whl", hash = "sha256:9836f5096eb2172c9e77df411c1b009bace4193d6a481d534fea75ebba758283", size = 242157 }, +] + +[[package]] +name = "semantic-workbench-api-model" +version = "0.1.0" +source = { editable = "../../../semantic-workbench-api-model" } +dependencies = [ + { name = "asgi-correlation-id" }, + { name = "fastapi", extra = ["standard"] }, +] + +[package.metadata] +requires-dist = [ + { name = "asgi-correlation-id", specifier = ">=4.3.1" }, + { name = "fastapi", extras = ["standard"], specifier = "~=0.115.0" }, +] + +[[package]] +name = "semantic-workbench-assistant" +version = "0.1.0" +source = { editable = "../../../semantic-workbench-assistant" } +dependencies = [ + { name = "asgi-correlation-id" }, + { name = "backoff" }, + { name = "deepmerge" }, + { name = "fastapi", extra = ["standard"] }, + { name = "pydantic-settings" }, + { name = "python-json-logger" }, + { name = "rich" }, + { name = "semantic-workbench-api-model" }, +] + +[package.metadata] +requires-dist = [ + { name = "asgi-correlation-id", specifier = ">=4.3.1" }, + { name = "backoff", specifier = ">=2.2.1" }, + { name = "deepmerge", specifier = ">=2.0" }, + { name = "fastapi", extras = ["standard"], specifier = "~=0.115.0" }, + { name = "pydantic-settings", specifier = ">=2.2.0" }, + { name = "python-json-logger", specifier = ">=2.0.7" }, + { name = "rich", specifier = ">=13.7.0" }, + { name = "semantic-workbench-api-model", editable = "../../../semantic-workbench-api-model" }, +] + +[package.metadata.requires-dev] +dev = [ + { name = "asgi-lifespan", specifier = ">=2.1.0" }, + { name = "pytest", specifier = ">=7.4.3" }, + { name = "pytest-asyncio", specifier = ">=0.23.5.post1" }, + { name = "pytest-httpx", specifier = ">=0.30.0" }, +] + +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 }, +] + [[package]] name = "six" version = "1.16.0" @@ -738,6 +1471,13 @@ requires-dist = [ { name = "tiktoken", specifier = ">=0.7.0" }, ] +[package.metadata.requires-dev] +dev = [ + { name = "pytest", specifier = ">=8.3.1" }, + { name = "pytest-asyncio", specifier = ">=0.23.8" }, + { name = "pytest-repeat", specifier = ">=0.9.3" }, +] + [[package]] name = "sniffio" version = "1.3.1" @@ -747,6 +1487,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, ] +[[package]] +name = "starlette" +version = "0.41.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3e/da/1fb4bdb72ae12b834becd7e1e7e47001d32f91ec0ce8d7bc1b618d9f0bd9/starlette-0.41.2.tar.gz", hash = "sha256:9834fd799d1a87fd346deb76158668cfa0b0d56f85caefe8268e2d97c3468b62", size = 2573867 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/43/f185bfd0ca1d213beb4293bed51d92254df23d8ceaf6c0e17146d508a776/starlette-0.41.2-py3-none-any.whl", hash = "sha256:fbc189474b4731cf30fcef52f18a8d070e3f3b46c6a04c97579e85e6ffca942d", size = 73259 }, +] + [[package]] name = "tiktoken" version = "0.7.0" @@ -785,6 +1537,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/48/5d/acf5905c36149bbaec41ccf7f2b68814647347b72075ac0b1fe3022fdc73/tqdm-4.66.5-py3-none-any.whl", hash = "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd", size = 78351 }, ] +[[package]] +name = "typer" +version = "0.12.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "rich" }, + { name = "shellingham" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c5/58/a79003b91ac2c6890fc5d90145c662fd5771c6f11447f116b63300436bc9/typer-0.12.5.tar.gz", hash = "sha256:f592f089bedcc8ec1b974125d64851029c3b1af145f04aca64d69410f0c9b722", size = 98953 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/2b/886d13e742e514f704c33c4caa7df0f3b89e5a25ef8db02aa9ca3d9535d5/typer-0.12.5-py3-none-any.whl", hash = "sha256:62fe4e471711b147e3365034133904df3e235698399bc4de2b36c8579298d52b", size = 47288 }, +] + [[package]] name = "typing-extensions" version = "4.12.2" @@ -802,3 +1569,206 @@ sdist = { url = "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b763 wheels = [ { url = "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338 }, ] + +[[package]] +name = "uvicorn" +version = "0.32.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e0/fc/1d785078eefd6945f3e5bab5c076e4230698046231eb0f3747bc5c8fa992/uvicorn-0.32.0.tar.gz", hash = "sha256:f78b36b143c16f54ccdb8190d0a26b5f1901fe5a3c777e1ab29f26391af8551e", size = 77564 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/14/78bd0e95dd2444b6caacbca2b730671d4295ccb628ef58b81bee903629df/uvicorn-0.32.0-py3-none-any.whl", hash = "sha256:60b8f3a5ac027dcd31448f411ced12b5ef452c646f76f02f8cc3f25d8d26fd82", size = 63723 }, +] + +[package.optional-dependencies] +standard = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "httptools" }, + { name = "python-dotenv" }, + { name = "pyyaml" }, + { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, + { name = "watchfiles" }, + { name = "websockets" }, +] + +[[package]] +name = "uvloop" +version = "0.21.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/57/a7/4cf0334105c1160dd6819f3297f8700fda7fc30ab4f61fbf3e725acbc7cc/uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8", size = 1447410 }, + { url = "https://files.pythonhosted.org/packages/8c/7c/1517b0bbc2dbe784b563d6ab54f2ef88c890fdad77232c98ed490aa07132/uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0", size = 805476 }, + { url = "https://files.pythonhosted.org/packages/ee/ea/0bfae1aceb82a503f358d8d2fa126ca9dbdb2ba9c7866974faec1cb5875c/uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e", size = 3960855 }, + { url = "https://files.pythonhosted.org/packages/8a/ca/0864176a649838b838f36d44bf31c451597ab363b60dc9e09c9630619d41/uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb", size = 3973185 }, + { url = "https://files.pythonhosted.org/packages/30/bf/08ad29979a936d63787ba47a540de2132169f140d54aa25bc8c3df3e67f4/uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6", size = 3820256 }, + { url = "https://files.pythonhosted.org/packages/da/e2/5cf6ef37e3daf2f06e651aae5ea108ad30df3cb269102678b61ebf1fdf42/uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d", size = 3937323 }, + { url = "https://files.pythonhosted.org/packages/8c/4c/03f93178830dc7ce8b4cdee1d36770d2f5ebb6f3d37d354e061eefc73545/uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c", size = 1471284 }, + { url = "https://files.pythonhosted.org/packages/43/3e/92c03f4d05e50f09251bd8b2b2b584a2a7f8fe600008bcc4523337abe676/uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2", size = 821349 }, + { url = "https://files.pythonhosted.org/packages/a6/ef/a02ec5da49909dbbfb1fd205a9a1ac4e88ea92dcae885e7c961847cd51e2/uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d", size = 4580089 }, + { url = "https://files.pythonhosted.org/packages/06/a7/b4e6a19925c900be9f98bec0a75e6e8f79bb53bdeb891916609ab3958967/uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc", size = 4693770 }, + { url = "https://files.pythonhosted.org/packages/ce/0c/f07435a18a4b94ce6bd0677d8319cd3de61f3a9eeb1e5f8ab4e8b5edfcb3/uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb", size = 4451321 }, + { url = "https://files.pythonhosted.org/packages/8f/eb/f7032be105877bcf924709c97b1bf3b90255b4ec251f9340cef912559f28/uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f", size = 4659022 }, + { url = "https://files.pythonhosted.org/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123 }, + { url = "https://files.pythonhosted.org/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325 }, + { url = "https://files.pythonhosted.org/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806 }, + { url = "https://files.pythonhosted.org/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068 }, + { url = "https://files.pythonhosted.org/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428 }, + { url = "https://files.pythonhosted.org/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018 }, +] + +[[package]] +name = "watchfiles" +version = "0.24.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c8/27/2ba23c8cc85796e2d41976439b08d52f691655fdb9401362099502d1f0cf/watchfiles-0.24.0.tar.gz", hash = "sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1", size = 37870 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/02/366ae902cd81ca5befcd1854b5c7477b378f68861597cef854bd6dc69fbe/watchfiles-0.24.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:bdcd5538e27f188dd3c804b4a8d5f52a7fc7f87e7fd6b374b8e36a4ca03db428", size = 375579 }, + { url = "https://files.pythonhosted.org/packages/bc/67/d8c9d256791fe312fea118a8a051411337c948101a24586e2df237507976/watchfiles-0.24.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2dadf8a8014fde6addfd3c379e6ed1a981c8f0a48292d662e27cabfe4239c83c", size = 367726 }, + { url = "https://files.pythonhosted.org/packages/b1/dc/a8427b21ef46386adf824a9fec4be9d16a475b850616cfd98cf09a97a2ef/watchfiles-0.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6509ed3f467b79d95fc62a98229f79b1a60d1b93f101e1c61d10c95a46a84f43", size = 437735 }, + { url = "https://files.pythonhosted.org/packages/3a/21/0b20bef581a9fbfef290a822c8be645432ceb05fb0741bf3c032e0d90d9a/watchfiles-0.24.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8360f7314a070c30e4c976b183d1d8d1585a4a50c5cb603f431cebcbb4f66327", size = 433644 }, + { url = "https://files.pythonhosted.org/packages/1c/e8/d5e5f71cc443c85a72e70b24269a30e529227986096abe091040d6358ea9/watchfiles-0.24.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:316449aefacf40147a9efaf3bd7c9bdd35aaba9ac5d708bd1eb5763c9a02bef5", size = 450928 }, + { url = "https://files.pythonhosted.org/packages/61/ee/bf17f5a370c2fcff49e1fec987a6a43fd798d8427ea754ce45b38f9e117a/watchfiles-0.24.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73bde715f940bea845a95247ea3e5eb17769ba1010efdc938ffcb967c634fa61", size = 469072 }, + { url = "https://files.pythonhosted.org/packages/a3/34/03b66d425986de3fc6077e74a74c78da298f8cb598887f664a4485e55543/watchfiles-0.24.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3770e260b18e7f4e576edca4c0a639f704088602e0bc921c5c2e721e3acb8d15", size = 475517 }, + { url = "https://files.pythonhosted.org/packages/70/eb/82f089c4f44b3171ad87a1b433abb4696f18eb67292909630d886e073abe/watchfiles-0.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa0fd7248cf533c259e59dc593a60973a73e881162b1a2f73360547132742823", size = 425480 }, + { url = "https://files.pythonhosted.org/packages/53/20/20509c8f5291e14e8a13104b1808cd7cf5c44acd5feaecb427a49d387774/watchfiles-0.24.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d7a2e3b7f5703ffbd500dabdefcbc9eafeff4b9444bbdd5d83d79eedf8428fab", size = 612322 }, + { url = "https://files.pythonhosted.org/packages/df/2b/5f65014a8cecc0a120f5587722068a975a692cadbe9fe4ea56b3d8e43f14/watchfiles-0.24.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d831ee0a50946d24a53821819b2327d5751b0c938b12c0653ea5be7dea9c82ec", size = 595094 }, + { url = "https://files.pythonhosted.org/packages/18/98/006d8043a82c0a09d282d669c88e587b3a05cabdd7f4900e402250a249ac/watchfiles-0.24.0-cp311-none-win32.whl", hash = "sha256:49d617df841a63b4445790a254013aea2120357ccacbed00253f9c2b5dc24e2d", size = 264191 }, + { url = "https://files.pythonhosted.org/packages/8a/8b/badd9247d6ec25f5f634a9b3d0d92e39c045824ec7e8afcedca8ee52c1e2/watchfiles-0.24.0-cp311-none-win_amd64.whl", hash = "sha256:d3dcb774e3568477275cc76554b5a565024b8ba3a0322f77c246bc7111c5bb9c", size = 277527 }, + { url = "https://files.pythonhosted.org/packages/af/19/35c957c84ee69d904299a38bae3614f7cede45f07f174f6d5a2f4dbd6033/watchfiles-0.24.0-cp311-none-win_arm64.whl", hash = "sha256:9301c689051a4857d5b10777da23fafb8e8e921bcf3abe6448a058d27fb67633", size = 266253 }, + { url = "https://files.pythonhosted.org/packages/35/82/92a7bb6dc82d183e304a5f84ae5437b59ee72d48cee805a9adda2488b237/watchfiles-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7211b463695d1e995ca3feb38b69227e46dbd03947172585ecb0588f19b0d87a", size = 374137 }, + { url = "https://files.pythonhosted.org/packages/87/91/49e9a497ddaf4da5e3802d51ed67ff33024597c28f652b8ab1e7c0f5718b/watchfiles-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4b8693502d1967b00f2fb82fc1e744df128ba22f530e15b763c8d82baee15370", size = 367733 }, + { url = "https://files.pythonhosted.org/packages/0d/d8/90eb950ab4998effea2df4cf3a705dc594f6bc501c5a353073aa990be965/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdab9555053399318b953a1fe1f586e945bc8d635ce9d05e617fd9fe3a4687d6", size = 437322 }, + { url = "https://files.pythonhosted.org/packages/6c/a2/300b22e7bc2a222dd91fce121cefa7b49aa0d26a627b2777e7bdfcf1110b/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:34e19e56d68b0dad5cff62273107cf5d9fbaf9d75c46277aa5d803b3ef8a9e9b", size = 433409 }, + { url = "https://files.pythonhosted.org/packages/99/44/27d7708a43538ed6c26708bcccdde757da8b7efb93f4871d4cc39cffa1cc/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41face41f036fee09eba33a5b53a73e9a43d5cb2c53dad8e61fa6c9f91b5a51e", size = 452142 }, + { url = "https://files.pythonhosted.org/packages/b0/ec/c4e04f755be003129a2c5f3520d2c47026f00da5ecb9ef1e4f9449637571/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5148c2f1ea043db13ce9b0c28456e18ecc8f14f41325aa624314095b6aa2e9ea", size = 469414 }, + { url = "https://files.pythonhosted.org/packages/c5/4e/cdd7de3e7ac6432b0abf282ec4c1a1a2ec62dfe423cf269b86861667752d/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e4bd963a935aaf40b625c2499f3f4f6bbd0c3776f6d3bc7c853d04824ff1c9f", size = 472962 }, + { url = "https://files.pythonhosted.org/packages/27/69/e1da9d34da7fc59db358424f5d89a56aaafe09f6961b64e36457a80a7194/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c79d7719d027b7a42817c5d96461a99b6a49979c143839fc37aa5748c322f234", size = 425705 }, + { url = "https://files.pythonhosted.org/packages/e8/c1/24d0f7357be89be4a43e0a656259676ea3d7a074901f47022f32e2957798/watchfiles-0.24.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:32aa53a9a63b7f01ed32e316e354e81e9da0e6267435c7243bf8ae0f10b428ef", size = 612851 }, + { url = "https://files.pythonhosted.org/packages/c7/af/175ba9b268dec56f821639c9893b506c69fd999fe6a2e2c51de420eb2f01/watchfiles-0.24.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ce72dba6a20e39a0c628258b5c308779b8697f7676c254a845715e2a1039b968", size = 594868 }, + { url = "https://files.pythonhosted.org/packages/44/81/1f701323a9f70805bc81c74c990137123344a80ea23ab9504a99492907f8/watchfiles-0.24.0-cp312-none-win32.whl", hash = "sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444", size = 264109 }, + { url = "https://files.pythonhosted.org/packages/b4/0b/32cde5bc2ebd9f351be326837c61bdeb05ad652b793f25c91cac0b48a60b/watchfiles-0.24.0-cp312-none-win_amd64.whl", hash = "sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896", size = 277055 }, + { url = "https://files.pythonhosted.org/packages/4b/81/daade76ce33d21dbec7a15afd7479de8db786e5f7b7d249263b4ea174e08/watchfiles-0.24.0-cp312-none-win_arm64.whl", hash = "sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418", size = 266169 }, + { url = "https://files.pythonhosted.org/packages/30/dc/6e9f5447ae14f645532468a84323a942996d74d5e817837a5c8ce9d16c69/watchfiles-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48", size = 373764 }, + { url = "https://files.pythonhosted.org/packages/79/c0/c3a9929c372816c7fc87d8149bd722608ea58dc0986d3ef7564c79ad7112/watchfiles-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90", size = 367873 }, + { url = "https://files.pythonhosted.org/packages/2e/11/ff9a4445a7cfc1c98caf99042df38964af12eed47d496dd5d0d90417349f/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94", size = 438381 }, + { url = "https://files.pythonhosted.org/packages/48/a3/763ba18c98211d7bb6c0f417b2d7946d346cdc359d585cc28a17b48e964b/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e", size = 432809 }, + { url = "https://files.pythonhosted.org/packages/30/4c/616c111b9d40eea2547489abaf4ffc84511e86888a166d3a4522c2ba44b5/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827", size = 451801 }, + { url = "https://files.pythonhosted.org/packages/b6/be/d7da83307863a422abbfeb12903a76e43200c90ebe5d6afd6a59d158edea/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df", size = 468886 }, + { url = "https://files.pythonhosted.org/packages/1d/d3/3dfe131ee59d5e90b932cf56aba5c996309d94dafe3d02d204364c23461c/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab", size = 472973 }, + { url = "https://files.pythonhosted.org/packages/42/6c/279288cc5653a289290d183b60a6d80e05f439d5bfdfaf2d113738d0f932/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f", size = 425282 }, + { url = "https://files.pythonhosted.org/packages/d6/d7/58afe5e85217e845edf26d8780c2d2d2ae77675eeb8d1b8b8121d799ce52/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b", size = 612540 }, + { url = "https://files.pythonhosted.org/packages/6d/d5/b96eeb9fe3fda137200dd2f31553670cbc731b1e13164fd69b49870b76ec/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18", size = 593625 }, + { url = "https://files.pythonhosted.org/packages/c1/e5/c326fe52ee0054107267608d8cea275e80be4455b6079491dfd9da29f46f/watchfiles-0.24.0-cp313-none-win32.whl", hash = "sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07", size = 263899 }, + { url = "https://files.pythonhosted.org/packages/a6/8b/8a7755c5e7221bb35fe4af2dc44db9174f90ebf0344fd5e9b1e8b42d381e/watchfiles-0.24.0-cp313-none-win_amd64.whl", hash = "sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366", size = 276622 }, +] + +[[package]] +name = "websockets" +version = "13.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e2/73/9223dbc7be3dcaf2a7bbf756c351ec8da04b1fa573edaf545b95f6b0c7fd/websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878", size = 158549 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b2/f0/cf0b8a30d86b49e267ac84addbebbc7a48a6e7bb7c19db80f62411452311/websockets-13.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:61fc0dfcda609cda0fc9fe7977694c0c59cf9d749fbb17f4e9483929e3c48a19", size = 157813 }, + { url = "https://files.pythonhosted.org/packages/bf/e7/22285852502e33071a8cf0ac814f8988480ec6db4754e067b8b9d0e92498/websockets-13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ceec59f59d092c5007e815def4ebb80c2de330e9588e101cf8bd94c143ec78a5", size = 155469 }, + { url = "https://files.pythonhosted.org/packages/68/d4/c8c7c1e5b40ee03c5cc235955b0fb1ec90e7e37685a5f69229ad4708dcde/websockets-13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1dca61c6db1166c48b95198c0b7d9c990b30c756fc2923cc66f68d17dc558fd", size = 155717 }, + { url = "https://files.pythonhosted.org/packages/c9/e4/c50999b9b848b1332b07c7fd8886179ac395cb766fda62725d1539e7bc6c/websockets-13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308e20f22c2c77f3f39caca508e765f8725020b84aa963474e18c59accbf4c02", size = 165379 }, + { url = "https://files.pythonhosted.org/packages/bc/49/4a4ad8c072f18fd79ab127650e47b160571aacfc30b110ee305ba25fffc9/websockets-13.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d516c325e6540e8a57b94abefc3459d7dab8ce52ac75c96cad5549e187e3a7", size = 164376 }, + { url = "https://files.pythonhosted.org/packages/af/9b/8c06d425a1d5a74fd764dd793edd02be18cf6fc3b1ccd1f29244ba132dc0/websockets-13.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c6e35319b46b99e168eb98472d6c7d8634ee37750d7693656dc766395df096", size = 164753 }, + { url = "https://files.pythonhosted.org/packages/d5/5b/0acb5815095ff800b579ffc38b13ab1b915b317915023748812d24e0c1ac/websockets-13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5f9fee94ebafbc3117c30be1844ed01a3b177bb6e39088bc6b2fa1dc15572084", size = 165051 }, + { url = "https://files.pythonhosted.org/packages/30/93/c3891c20114eacb1af09dedfcc620c65c397f4fd80a7009cd12d9457f7f5/websockets-13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7c1e90228c2f5cdde263253fa5db63e6653f1c00e7ec64108065a0b9713fa1b3", size = 164489 }, + { url = "https://files.pythonhosted.org/packages/28/09/af9e19885539759efa2e2cd29b8b3f9eecef7ecefea40d46612f12138b36/websockets-13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6548f29b0e401eea2b967b2fdc1c7c7b5ebb3eeb470ed23a54cd45ef078a0db9", size = 164438 }, + { url = "https://files.pythonhosted.org/packages/b6/08/6f38b8e625b3d93de731f1d248cc1493327f16cb45b9645b3e791782cff0/websockets-13.1-cp311-cp311-win32.whl", hash = "sha256:c11d4d16e133f6df8916cc5b7e3e96ee4c44c936717d684a94f48f82edb7c92f", size = 158710 }, + { url = "https://files.pythonhosted.org/packages/fb/39/ec8832ecb9bb04a8d318149005ed8cee0ba4e0205835da99e0aa497a091f/websockets-13.1-cp311-cp311-win_amd64.whl", hash = "sha256:d04f13a1d75cb2b8382bdc16ae6fa58c97337253826dfe136195b7f89f661557", size = 159137 }, + { url = "https://files.pythonhosted.org/packages/df/46/c426282f543b3c0296cf964aa5a7bb17e984f58dde23460c3d39b3148fcf/websockets-13.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc", size = 157821 }, + { url = "https://files.pythonhosted.org/packages/aa/85/22529867010baac258da7c45848f9415e6cf37fef00a43856627806ffd04/websockets-13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49", size = 155480 }, + { url = "https://files.pythonhosted.org/packages/29/2c/bdb339bfbde0119a6e84af43ebf6275278698a2241c2719afc0d8b0bdbf2/websockets-13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd", size = 155715 }, + { url = "https://files.pythonhosted.org/packages/9f/d0/8612029ea04c5c22bf7af2fd3d63876c4eaeef9b97e86c11972a43aa0e6c/websockets-13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0", size = 165647 }, + { url = "https://files.pythonhosted.org/packages/56/04/1681ed516fa19ca9083f26d3f3a302257e0911ba75009533ed60fbb7b8d1/websockets-13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6", size = 164592 }, + { url = "https://files.pythonhosted.org/packages/38/6f/a96417a49c0ed132bb6087e8e39a37db851c70974f5c724a4b2a70066996/websockets-13.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9", size = 165012 }, + { url = "https://files.pythonhosted.org/packages/40/8b/fccf294919a1b37d190e86042e1a907b8f66cff2b61e9befdbce03783e25/websockets-13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68", size = 165311 }, + { url = "https://files.pythonhosted.org/packages/c1/61/f8615cf7ce5fe538476ab6b4defff52beb7262ff8a73d5ef386322d9761d/websockets-13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14", size = 164692 }, + { url = "https://files.pythonhosted.org/packages/5c/f1/a29dd6046d3a722d26f182b783a7997d25298873a14028c4760347974ea3/websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf", size = 164686 }, + { url = "https://files.pythonhosted.org/packages/0f/99/ab1cdb282f7e595391226f03f9b498f52109d25a2ba03832e21614967dfa/websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c", size = 158712 }, + { url = "https://files.pythonhosted.org/packages/46/93/e19160db48b5581feac8468330aa11b7292880a94a37d7030478596cc14e/websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3", size = 159145 }, + { url = "https://files.pythonhosted.org/packages/51/20/2b99ca918e1cbd33c53db2cace5f0c0cd8296fc77558e1908799c712e1cd/websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6", size = 157828 }, + { url = "https://files.pythonhosted.org/packages/b8/47/0932a71d3d9c0e9483174f60713c84cee58d62839a143f21a2bcdbd2d205/websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708", size = 155487 }, + { url = "https://files.pythonhosted.org/packages/a9/60/f1711eb59ac7a6c5e98e5637fef5302f45b6f76a2c9d64fd83bbb341377a/websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418", size = 155721 }, + { url = "https://files.pythonhosted.org/packages/6a/e6/ba9a8db7f9d9b0e5f829cf626ff32677f39824968317223605a6b419d445/websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a", size = 165609 }, + { url = "https://files.pythonhosted.org/packages/c1/22/4ec80f1b9c27a0aebd84ccd857252eda8418ab9681eb571b37ca4c5e1305/websockets-13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f", size = 164556 }, + { url = "https://files.pythonhosted.org/packages/27/ac/35f423cb6bb15600438db80755609d27eda36d4c0b3c9d745ea12766c45e/websockets-13.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5", size = 164993 }, + { url = "https://files.pythonhosted.org/packages/31/4e/98db4fd267f8be9e52e86b6ee4e9aa7c42b83452ea0ea0672f176224b977/websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135", size = 165360 }, + { url = "https://files.pythonhosted.org/packages/3f/15/3f0de7cda70ffc94b7e7024544072bc5b26e2c1eb36545291abb755d8cdb/websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2", size = 164745 }, + { url = "https://files.pythonhosted.org/packages/a1/6e/66b6b756aebbd680b934c8bdbb6dcb9ce45aad72cde5f8a7208dbb00dd36/websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6", size = 164732 }, + { url = "https://files.pythonhosted.org/packages/35/c6/12e3aab52c11aeb289e3dbbc05929e7a9d90d7a9173958477d3ef4f8ce2d/websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d", size = 158709 }, + { url = "https://files.pythonhosted.org/packages/41/d8/63d6194aae711d7263df4498200c690a9c39fb437ede10f3e157a6343e0d/websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2", size = 159144 }, + { url = "https://files.pythonhosted.org/packages/56/27/96a5cd2626d11c8280656c6c71d8ab50fe006490ef9971ccd154e0c42cd2/websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f", size = 152134 }, +] + +[[package]] +name = "yarl" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/8f/d2d546f8b674335fa7ef83cc5c1892294f3f516c570893e65a7ea8ed49c9/yarl-1.17.0.tar.gz", hash = "sha256:d3f13583f378930377e02002b4085a3d025b00402d5a80911726d43a67911cd9", size = 177249 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/72/a455fd01d4d33c10d683c209f87af5962bae54b13f435a69747354b169b1/yarl-1.17.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:19a4fe0279626c6295c5b0c8c2bb7228319d2e985883621a6e87b344062d8135", size = 140427 }, + { url = "https://files.pythonhosted.org/packages/ca/f6/8f2af9ad1ceab385660f90930433d41191b8647ad3946a67ea573333317f/yarl-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cadd0113f4db3c6b56868d6a19ca6286f5ccfa7bc08c27982cf92e5ed31b489a", size = 93259 }, + { url = "https://files.pythonhosted.org/packages/5d/c5/61036a97e6686de3a3b47ffd51f2db10f4eff895dfdc287f27f9acdc4097/yarl-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:60d6693eef43215b1ccfb1df3f6eae8db30a9ff1e7989fb6b2a6f0b468930ee8", size = 91194 }, + { url = "https://files.pythonhosted.org/packages/0c/a0/fe9db41a1807da0f6f9cbc78243da3267258734c383ff911696f506cae49/yarl-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb8bf3843e1fa8cf3fe77813c512818e57368afab7ebe9ef02446fe1a10b492", size = 339165 }, + { url = "https://files.pythonhosted.org/packages/27/d5/d99e6e25e77ea26ac1d73630ad26ba29ec01ec7594c530cf045b150f7e1f/yarl-1.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d2a5b35fd1d8d90443e061d0c8669ac7600eec5c14c4a51f619e9e105b136715", size = 354290 }, + { url = "https://files.pythonhosted.org/packages/5f/98/0c475389a172e096467ef44cb59d649fc4f44ac186689a70299cd2e03dea/yarl-1.17.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c5bf17b32f392df20ab5c3a69d37b26d10efaa018b4f4e5643c7520d8eee7ac7", size = 351486 }, + { url = "https://files.pythonhosted.org/packages/b2/0d/8ecf4604cf62abd8d4aa30dd927466b095f263ee708aed2e576f9f6c6ac8/yarl-1.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48f51b529b958cd06e78158ff297a8bf57b4021243c179ee03695b5dbf9cb6e1", size = 343091 }, + { url = "https://files.pythonhosted.org/packages/c8/11/e0978e6e2f312c4ac5d441634df8374d25afa17164a6a5caed65f2071ce1/yarl-1.17.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fcaa06bf788e19f913d315d9c99a69e196a40277dc2c23741a1d08c93f4d430", size = 336785 }, + { url = "https://files.pythonhosted.org/packages/35/26/ecfebb253652b2446082e5072bf347dc2663a176f1a7f96830fb3f2ddb37/yarl-1.17.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:32f3ee19ff0f18a7a522d44e869e1ebc8218ad3ae4ebb7020445f59b4bbe5897", size = 346317 }, + { url = "https://files.pythonhosted.org/packages/4f/d7/bec0e8ab6788824a21b4d2a467ebd491c034bf5a61aae9f91bac3225cd0f/yarl-1.17.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:a4fb69a81ae2ec2b609574ae35420cf5647d227e4d0475c16aa861dd24e840b0", size = 344050 }, + { url = "https://files.pythonhosted.org/packages/5d/cd/a3d7496963fa6fda90987efc6c6d63e17035a15607a7ba432b3658ee7c4a/yarl-1.17.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7bacc8b77670322132a1b2522c50a1f62991e2f95591977455fd9a398b4e678d", size = 350009 }, + { url = "https://files.pythonhosted.org/packages/4c/11/e32119eba4f1b2a888d653348571ec835fda93da45255d0d4e0fd557ae75/yarl-1.17.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:437bf6eb47a2d20baaf7f6739895cb049e56896a5ffdea61a4b25da781966e8b", size = 361038 }, + { url = "https://files.pythonhosted.org/packages/b2/3f/868044fff54c060cade272a54baaf57a155537ac79424312c6c0a3c0ff17/yarl-1.17.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:30534a03c87484092080e3b6e789140bd277e40f453358900ad1f0f2e61fc8ec", size = 365043 }, + { url = "https://files.pythonhosted.org/packages/6f/63/99b77939e7a6b8dbb638fb7b6c6ecea4a730ccd7bdda5b621df9ff5bbbc6/yarl-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b30df4ff98703649915144be6f0df3b16fd4870ac38a09c56d5d9e54ff2d5f96", size = 357382 }, + { url = "https://files.pythonhosted.org/packages/b8/cc/48b49f45e4fc5fbb7538a6b513f0a4ae7377c44568e375fca65f270f03d7/yarl-1.17.0-cp311-cp311-win32.whl", hash = "sha256:263b487246858e874ab53e148e2a9a0de8465341b607678106829a81d81418c6", size = 83336 }, + { url = "https://files.pythonhosted.org/packages/ae/60/2ac590d83bb8aa5b8cc3d7f9c47d532d89fb06c3ffa2c4d4fc8d6935aded/yarl-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:07055a9e8b647a362e7d4810fe99d8f98421575e7d2eede32e008c89a65a17bd", size = 89919 }, + { url = "https://files.pythonhosted.org/packages/58/30/3d1b3eea23b9d1764c3d6a6bc22a12336bc91c748475dd1ea79f63a72bf1/yarl-1.17.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:84095ab25ba69a8fa3fb4936e14df631b8a71193fe18bd38be7ecbe34d0f5512", size = 141535 }, + { url = "https://files.pythonhosted.org/packages/aa/0d/178955afc7b6b17f7a693878da366ad4dbf2adfee84cbb76640755115191/yarl-1.17.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:02608fb3f6df87039212fc746017455ccc2a5fc96555ee247c45d1e9f21f1d7b", size = 93821 }, + { url = "https://files.pythonhosted.org/packages/d1/b3/808461c3c3d4c32ff8783364a8673bd785ce887b7421e0ea8d758357d874/yarl-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13468d291fe8c12162b7cf2cdb406fe85881c53c9e03053ecb8c5d3523822cd9", size = 91750 }, + { url = "https://files.pythonhosted.org/packages/95/8b/572f96dd61de8f8b82caf18254573707d526715ad38fd83c47663f2b3c28/yarl-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8da3f8f368fb7e2f052fded06d5672260c50b5472c956a5f1bd7bf474ae504ab", size = 331165 }, + { url = "https://files.pythonhosted.org/packages/4d/f6/8870c4beb0a120d381e7a62f6c1e6a590d929e94de135802ecdb042caffa/yarl-1.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ec0507ab6523980bed050137007c76883d941b519aca0e26d4c1ec1f297dd646", size = 340972 }, + { url = "https://files.pythonhosted.org/packages/cb/08/97a6ccb59df29bbedb560491bc74f9f946dbf074bec1b61f942c29d2bc32/yarl-1.17.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08fc76df7fd8360e9ff30e6ccc3ee85b8dbd6ed5d3a295e6ec62bcae7601b932", size = 340557 }, + { url = "https://files.pythonhosted.org/packages/5a/f4/52be40fc0a8811a18a2b2ae99c6233e769fe391b52fae95a23a4db45e82c/yarl-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d522f390686acb6bab2b917dd9ca06740c5080cd2eaa5aef8827b97e967319d", size = 336362 }, + { url = "https://files.pythonhosted.org/packages/0a/25/b95d3c0130c65d2118b3b58d644261a3cd4571a317e5b46dcb2a44d096e2/yarl-1.17.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:147c527a80bb45b3dcd6e63401af8ac574125d8d120e6afe9901049286ff64ef", size = 324716 }, + { url = "https://files.pythonhosted.org/packages/ab/8a/b4d020a2b83bcab78d9cf094ed30cd08f966a7ce900abdbc3d57e34d1a4b/yarl-1.17.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:24cf43bcd17a0a1f72284e47774f9c60e0bf0d2484d5851f4ddf24ded49f33c6", size = 342539 }, + { url = "https://files.pythonhosted.org/packages/e9/e5/29959b19f9267dde6d80d9576bd95d9ed9463693a7c7e5408cd33bf66b18/yarl-1.17.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c28a44b9e0fba49c3857360e7ad1473fc18bc7f6659ca08ed4f4f2b9a52c75fa", size = 341129 }, + { url = "https://files.pythonhosted.org/packages/0a/b2/e5bb6f8909f96179b2982b6d4f44e3700b319eebbacf3f88adc75b2ae4e9/yarl-1.17.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:350cacb2d589bc07d230eb995d88fcc646caad50a71ed2d86df533a465a4e6e1", size = 344626 }, + { url = "https://files.pythonhosted.org/packages/86/6a/324d0b022032380ea8c378282d5e84e3d1535565489472518e80b8734f1f/yarl-1.17.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:fd1ab1373274dea1c6448aee420d7b38af163b5c4732057cd7ee9f5454efc8b1", size = 355409 }, + { url = "https://files.pythonhosted.org/packages/20/f7/e2440d94826723f8bfd194a62ee014974ec416c16f953aa27c23e3ed3128/yarl-1.17.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4934e0f96dadc567edc76d9c08181633c89c908ab5a3b8f698560124167d9488", size = 361845 }, + { url = "https://files.pythonhosted.org/packages/d7/69/757dc8bb7a9e543b319e200c8c6ed30fbf7e7155736c609e2c140d0bb719/yarl-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8d0a278170d75c88e435a1ce76557af6758bfebc338435b2eba959df2552163e", size = 356050 }, + { url = "https://files.pythonhosted.org/packages/2c/3a/c563287d638200be202d46c03698079d85993b7c68f1488451546e60999b/yarl-1.17.0-cp312-cp312-win32.whl", hash = "sha256:61584f33196575a08785bb56db6b453682c88f009cd9c6f338a10f6737ce419f", size = 82982 }, + { url = "https://files.pythonhosted.org/packages/9a/cb/07a4084b90e7761749c56a5338c34366765051e9838eb669e449f012fdb2/yarl-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:9987a439ad33a7712bd5bbd073f09ad10d38640425fa498ecc99d8aa064f8fc4", size = 89294 }, + { url = "https://files.pythonhosted.org/packages/6c/4d/9285cd4d13a1bb521350656f89a09b6d44e4e167d4329246a01dc76a2128/yarl-1.17.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8deda7b8eb15a52db94c2014acdc7bdd14cb59ec4b82ac65d2ad16dc234a109e", size = 139677 }, + { url = "https://files.pythonhosted.org/packages/25/c9/eec62c4b4bb1151be548c378c06d3c7282aa70b027f0b26d24c6dde55106/yarl-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56294218b348dcbd3d7fce0ffd79dd0b6c356cb2a813a1181af730b7c40de9e7", size = 93066 }, + { url = "https://files.pythonhosted.org/packages/03/b0/ae2fc93595bf076bf568ed795a3f91ecf596975d9286aab62635340de1d7/yarl-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1fab91292f51c884b290ebec0b309a64a5318860ccda0c4940e740425a67b6b7", size = 90877 }, + { url = "https://files.pythonhosted.org/packages/3e/c2/8dd9c26534eaac304088674582e94d06d874e0b9c43ecf17d93d735eaf8a/yarl-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cf93fa61ff4d9c7d40482ce1a2c9916ca435e34a1b8451e17f295781ccc034f", size = 332747 }, + { url = "https://files.pythonhosted.org/packages/43/95/130310a39e90d99cf5894a4ea6bee147f133db3423e4d88bf6f2baba4ee4/yarl-1.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:261be774a0d71908c8830c33bacc89eef15c198433a8cc73767c10eeeb35a7d0", size = 343341 }, + { url = "https://files.pythonhosted.org/packages/e1/59/995a99e510f74d39c849157407d8d3e683b5b3d3d830f28de6dfca2c7f60/yarl-1.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:deec9693b67f6af856a733b8a3e465553ef09e5e8ead792f52c25b699b8f9e6e", size = 344880 }, + { url = "https://files.pythonhosted.org/packages/78/41/520458d62a79b6115f035d63f6dec7c70ebfc19c50875cd0b9c3d63bd66f/yarl-1.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c804b07622ba50a765ca7fb8145512836ab65956de01307541def869e4a456c9", size = 338438 }, + { url = "https://files.pythonhosted.org/packages/b1/90/878e20cc8f54206407d035f17ccd567c75ed2bf77fb9c137c2977e58baf4/yarl-1.17.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d013a7c9574e98c14831a8f22d27277688ec3b2741d0188ac01a910b009987a", size = 326415 }, + { url = "https://files.pythonhosted.org/packages/0a/2e/709c8339cd5a0b8fb3e7474428165293feec85d77c642b95b0d7be7bda9c/yarl-1.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e2cfcba719bd494c7413dcf0caafb51772dec168c7c946e094f710d6aa70494e", size = 345526 }, + { url = "https://files.pythonhosted.org/packages/62/5e/90c60a9ac1b3f254b52e542674024160b90e0e547014f0d2a3025c789796/yarl-1.17.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:c068aba9fc5b94dfae8ea1cedcbf3041cd4c64644021362ffb750f79837e881f", size = 340048 }, + { url = "https://files.pythonhosted.org/packages/ae/1f/2d086911313e4db00b28f5d105d64823dbcd4a78efcbba70bd58ffc72e20/yarl-1.17.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3616df510ffac0df3c9fa851a40b76087c6c89cbcea2de33a835fc80f9faac24", size = 344999 }, + { url = "https://files.pythonhosted.org/packages/da/f7/8670ff0427f82db0ec25f4f7e62f5111cc76d79b05a2fe9631155cd0f742/yarl-1.17.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:755d6176b442fba9928a4df787591a6a3d62d4969f05c406cad83d296c5d4e05", size = 353920 }, + { url = "https://files.pythonhosted.org/packages/68/b8/1f5a2fdecee03c23b4b5c9d394342709ed04e15bead1d3c7bee53854a61b/yarl-1.17.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:c18f6e708d1cf9ff5b1af026e697ac73bea9cb70ee26a2b045b112548579bed2", size = 360209 }, + { url = "https://files.pythonhosted.org/packages/2b/95/d2e538a544c75131836b5e93975fa677932f0cbacbe4d7a4adb80caba967/yarl-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5b937c216b6dee8b858c6afea958de03c5ff28406257d22b55c24962a2baf6fd", size = 359149 }, + { url = "https://files.pythonhosted.org/packages/93/c7/c7f954200ebae213f0b76b072dcd3c37b39a42f4cf3d80a30d580bcedef7/yarl-1.17.0-cp313-cp313-win32.whl", hash = "sha256:d0131b14cb545c1a7bd98f4565a3e9bdf25a1bd65c83fc156ee5d8a8499ec4a3", size = 308608 }, + { url = "https://files.pythonhosted.org/packages/c7/cc/57117f63f27668e87e3ea9ce9fecab7331f0a30b72690211a2857b5db9f5/yarl-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:01c96efa4313c01329e88b7e9e9e1b2fc671580270ddefdd41129fa8d0db7696", size = 314345 }, + { url = "https://files.pythonhosted.org/packages/93/86/f1305e1ab1d6dc27d245ffc83d18d88f2bebf6c6488725ee82dffb3eda7a/yarl-1.17.0-py3-none-any.whl", hash = "sha256:62dd42bb0e49423f4dd58836a04fcf09c80237836796025211bbe913f1524993", size = 44053 }, +] diff --git a/libraries/python/skills/skills/posix-skill/posix_skill/posix_skill.py b/libraries/python/skills/skills/posix-skill/posix_skill/posix_skill.py index 0bb628e0..f2d82d1b 100644 --- a/libraries/python/skills/skills/posix-skill/posix_skill/posix_skill.py +++ b/libraries/python/skills/skills/posix-skill/posix_skill/posix_skill.py @@ -21,7 +21,7 @@ def __init__( chat_driver_config: ChatDriverConfig, mount_dir: str = "/mnt/data", ) -> None: - self.shell = SandboxShell(sandbox_dir / context.session_id, mount_dir) + self.shell = SandboxShell(sandbox_dir, mount_dir) # Put all functions in a group. We are going to use all these as (1) # skill actions, but also as (2) chat functions and (3) chat commands. @@ -45,9 +45,8 @@ def __init__( self.make_home_dir_routine(), ] - # Configure the skill's chat driver. + # Re-configure the skill's chat driver. chat_driver_config.instructions = INSTRUCTIONS - chat_driver_config.context = context chat_driver_config.commands = functions chat_driver_config.functions = functions @@ -55,7 +54,6 @@ def __init__( super().__init__( name=NAME, description=DESCRIPTION, - context=context, chat_driver_config=chat_driver_config, skill_actions=functions, routines=routines, diff --git a/libraries/python/skills/skills/posix-skill/uv.lock b/libraries/python/skills/skills/posix-skill/uv.lock index ae772499..3f0e051e 100644 --- a/libraries/python/skills/skills/posix-skill/uv.lock +++ b/libraries/python/skills/skills/posix-skill/uv.lock @@ -320,6 +320,7 @@ dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, + { name = "python-liquid" }, { name = "requests" }, { name = "tiktoken" }, ] @@ -335,6 +336,7 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, + { name = "python-liquid", specifier = ">=1.12.1" }, { name = "requests", specifier = ">=2.32.0" }, { name = "tiktoken", specifier = ">=0.7.0" }, ] diff --git a/libraries/python/skills/skills/prospector-skill/uv.lock b/libraries/python/skills/skills/prospector-skill/uv.lock index fb7c57c0..3741b1fb 100644 --- a/libraries/python/skills/skills/prospector-skill/uv.lock +++ b/libraries/python/skills/skills/prospector-skill/uv.lock @@ -320,6 +320,7 @@ dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, + { name = "python-liquid" }, { name = "requests" }, { name = "tiktoken" }, ] @@ -335,6 +336,7 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, + { name = "python-liquid", specifier = ">=1.12.1" }, { name = "requests", specifier = ">=2.32.0" }, { name = "tiktoken", specifier = ">=0.7.0" }, ] diff --git a/libraries/python/skills/skills/skill-template/uv.lock b/libraries/python/skills/skills/skill-template/uv.lock index bf6c6414..a5787da7 100644 --- a/libraries/python/skills/skills/skill-template/uv.lock +++ b/libraries/python/skills/skills/skill-template/uv.lock @@ -320,6 +320,7 @@ dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, + { name = "python-liquid" }, { name = "requests" }, { name = "tiktoken" }, ] @@ -335,6 +336,7 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, + { name = "python-liquid", specifier = ">=1.12.1" }, { name = "requests", specifier = ">=2.32.0" }, { name = "tiktoken", specifier = ">=0.7.0" }, ] diff --git a/semantic-workbench.code-workspace b/semantic-workbench.code-workspace index b01bfc92..a3839015 100644 --- a/semantic-workbench.code-workspace +++ b/semantic-workbench.code-workspace @@ -115,6 +115,10 @@ "name": "libraries:skills:document-skill", "path": "libraries/python/skills/skills/document-skill" }, + { + "name": "libraries:skills:form-filler-skill", + "path": "libraries/python/skills/skills/form-filler-skill" + }, { "name": "libraries:skills:notebooks", "path": "libraries/python/skills/notebooks" @@ -146,6 +150,10 @@ { "name": ".github", "path": ".github" + }, + { + "name": "root", + "path": "." } ], "settings": { From 2a3450096d1bcc1917de165dd6564207fb0df44b Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Tue, 5 Nov 2024 23:34:55 +0000 Subject: [PATCH 07/14] Make Context inherit ContextProtol. --- libraries/python/context/context/context.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/python/context/context/context.py b/libraries/python/context/context/context.py index 5f3dfb8e..3bde2d04 100644 --- a/libraries/python/context/context/context.py +++ b/libraries/python/context/context/context.py @@ -56,7 +56,11 @@ def __init__( self.emit = emit or LogEmitter().emit def to_dict(self) -> dict[str, Any]: - return {"session_id": self.session_id, "run_id": self.run_id, "emit": self.emit.__class__.__name__} + return { + "session_id": self.session_id, + "run_id": self.run_id, + "emit": self.emit.__class__.__name__, + } def __repr__(self) -> str: return f"Context({self.session_id})" From f194b66c8ad5c242051ac7ca7b12dad813215a5c Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Tue, 5 Nov 2024 23:56:42 +0000 Subject: [PATCH 08/14] uv sync --- assistants/prospector-assistant/uv.lock | 2 - assistants/skill-assistant/uv.lock | 4 +- libraries/python/chat-driver/uv.lock | 499 +++++------------- libraries/python/skills/skill-library/uv.lock | 98 ++-- .../skills/skills/document-skill/uv.lock | 2 - .../skills/skills/form-filler-skill/uv.lock | 19 +- .../python/skills/skills/posix-skill/uv.lock | 2 - .../skills/skills/prospector-skill/uv.lock | 2 - .../skills/skills/skill-template/uv.lock | 2 - 9 files changed, 186 insertions(+), 444 deletions(-) diff --git a/assistants/prospector-assistant/uv.lock b/assistants/prospector-assistant/uv.lock index f964fc01..7bf660ca 100644 --- a/assistants/prospector-assistant/uv.lock +++ b/assistants/prospector-assistant/uv.lock @@ -397,7 +397,6 @@ dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, - { name = "python-liquid" }, { name = "requests" }, { name = "tiktoken" }, ] @@ -413,7 +412,6 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "python-liquid", specifier = ">=1.12.1" }, { name = "requests", specifier = ">=2.32.0" }, { name = "tiktoken", specifier = ">=0.7.0" }, ] diff --git a/assistants/skill-assistant/uv.lock b/assistants/skill-assistant/uv.lock index 86b8595d..6049b682 100644 --- a/assistants/skill-assistant/uv.lock +++ b/assistants/skill-assistant/uv.lock @@ -366,7 +366,6 @@ dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, - { name = "python-liquid" }, { name = "requests" }, { name = "tiktoken" }, ] @@ -382,7 +381,6 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "python-liquid", specifier = ">=1.12.1" }, { name = "requests", specifier = ">=2.32.0" }, { name = "tiktoken", specifier = ">=0.7.0" }, ] @@ -596,6 +594,7 @@ dependencies = [ { name = "chat-driver" }, { name = "context" }, { name = "events" }, + { name = "openai-client" }, { name = "skill-library" }, ] @@ -604,6 +603,7 @@ requires-dist = [ { name = "chat-driver", editable = "../../libraries/python/chat-driver" }, { name = "context", editable = "../../libraries/python/context" }, { name = "events", editable = "../../libraries/python/events" }, + { name = "openai-client", editable = "../../libraries/python/openai-client" }, { name = "skill-library", editable = "../../libraries/python/skills/skill-library" }, ] diff --git a/libraries/python/chat-driver/uv.lock b/libraries/python/chat-driver/uv.lock index 6ce43bb0..267c97d7 100644 --- a/libraries/python/chat-driver/uv.lock +++ b/libraries/python/chat-driver/uv.lock @@ -106,42 +106,7 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/9f/09/45b9b7a6d4e45c6bcb5bf61d19e3ab87df68e0601fa8c5293de3542546cc/anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c", size = 173422 } wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/ef/7a4f225581a0d7886ea28359179cb861d7fbcdefad29663fc1167b86f69f/anyio-4.6.0-py3-none-any.whl", hash = "sha256:c7d2e9d63e31599eeb636c8c5c03a7e108d73b345f064f1c19fdc87b79036a9a", size = 89631 }, -] - -[[package]] -name = "asgi-correlation-id" -version = "4.3.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, - { name = "starlette" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/ff/a6538245ac1eaa7733ec6740774e9d5add019e2c63caa29e758c16c0afdd/asgi_correlation_id-4.3.4.tar.gz", hash = "sha256:ea6bc310380373cb9f731dc2e8b2b6fb978a76afe33f7a2384f697b8d6cd811d", size = 20075 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/ab/6936e2663c47a926e0659437b9333ad87d1ff49b1375d239026e0a268eba/asgi_correlation_id-4.3.4-py3-none-any.whl", hash = "sha256:36ce69b06c7d96b4acb89c7556a4c4f01a972463d3d49c675026cbbd08e9a0a2", size = 15262 }, -] - -[[package]] -name = "attrs" -version = "24.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fc/0f/aafca9af9315aee06a89ffde799a10a582fe8de76c563ee80bbcdc08b3fb/attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", size = 792678 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2", size = 63001 }, -] - -[[package]] -name = "azure-ai-contentsafety" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "azure-core" }, - { name = "isodate" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/08/e9/c069efade0e4976d96208306f1cf0803838cdb0b60e00a2a96bd20806bff/azure-ai-contentsafety-1.0.0.tar.gz", hash = "sha256:052731bd1419a720fa00910f46bf3428c4e5bd05280da7393d0c8106d46cc6d7", size = 63806 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/36/39/cbb3ff28ad09434a1be7803b2846077bc3b23a8232beb489962fc818fe21/azure_ai_contentsafety-1.0.0-py3-none-any.whl", hash = "sha256:e1c5574a541f9290fdd071d23535e14b1f463af231a6f0ac0f917e125f0463cf", size = 61328 }, + { url = "https://files.pythonhosted.org/packages/e4/f5/f2b75d2fc6f1a260f340f0e7c6a060f4dd2961cc16884ed851b0d18da06a/anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d", size = 90377 }, ] [[package]] @@ -181,16 +146,16 @@ wheels = [ [[package]] name = "azure-core" -version = "1.31.0" +version = "1.32.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, { name = "six" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/03/7a/f79ad135a276a37e61168495697c14ba1721a52c3eab4dae2941929c79f8/azure_core-1.31.0.tar.gz", hash = "sha256:656a0dd61e1869b1506b7c6a3b31d62f15984b1a573d6326f6aa2f3e4123284b", size = 277147 } +sdist = { url = "https://files.pythonhosted.org/packages/cc/ee/668328306a9e963a5ad9f152cd98c7adad86c822729fd1d2a01613ad1e67/azure_core-1.32.0.tar.gz", hash = "sha256:22b3c35d6b2dae14990f6c1be2912bf23ffe50b220e708a28ab1bb92b1c730e5", size = 279128 } wheels = [ - { url = "https://files.pythonhosted.org/packages/01/8e/fcb6a77d3029d2a7356f38dbc77cf7daa113b81ddab76b5593d23321e44c/azure_core-1.31.0-py3-none-any.whl", hash = "sha256:22954de3777e0250029360ef31d80448ef1be13b80a459bff80ba7073379e2cd", size = 197399 }, + { url = "https://files.pythonhosted.org/packages/39/83/325bf5e02504dbd8b4faa98197a44cdf8a325ef259b48326a2b6f17f8383/azure_core-1.32.0-py3-none-any.whl", hash = "sha256:eac191a0efb23bfa83fddf321b27b122b4ec847befa3091fa736a5c32c50d7b4", size = 198855 }, ] [package.optional-dependencies] @@ -211,16 +176,7 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/aa/91/cbaeff9eb0b838f0d35b4607ac1c6195c735c8eb17db235f8f60e622934c/azure_identity-1.19.0.tar.gz", hash = "sha256:500144dc18197d7019b81501165d4fa92225f03778f17d7ca8a2a180129a9c83", size = 263058 } wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/71/1d1bb387b6acaa5daa3e703c70dde3d54823ccd229bd6730de6e724f296e/azure_identity-1.18.0-py3-none-any.whl", hash = "sha256:bccf6106245b49ff41d0c4cd7b72851c5a2ba3a32cef7589da246f5727f26f02", size = 187179 }, -] - -[[package]] -name = "backoff" -version = "2.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/47/d7/5bbeb12c44d7c4f2fb5b56abce497eb5ed9f34d85701de869acedd602619/backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba", size = 17001 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8", size = 15148 }, + { url = "https://files.pythonhosted.org/packages/f0/d5/3995ed12f941f4a41a273d9b1709282e825ef87ed8eab3833038fee54d59/azure_identity-1.19.0-py3-none-any.whl", hash = "sha256:e3f6558c181692d7509f09de10cca527c7dce426776454fb97df512a46527e81", size = 187587 }, ] [[package]] @@ -354,7 +310,6 @@ dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, - { name = "python-liquid" }, { name = "requests" }, { name = "tiktoken" }, ] @@ -370,7 +325,6 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "python-liquid", specifier = ">=1.12.1" }, { name = "requests", specifier = ">=2.32.0" }, { name = "tiktoken", specifier = ">=0.7.0" }, ] @@ -423,33 +377,24 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/0d/05/07b55d1fa21ac18c3a8c79f764e2514e6f6a9698f1be44994f5adf0d29db/cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805", size = 686989 } wheels = [ - { url = "https://files.pythonhosted.org/packages/58/28/b92c98a04ba762f8cdeb54eba5c4c84e63cac037a7c5e70117d337b15ad6/cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d", size = 6223222 }, - { url = "https://files.pythonhosted.org/packages/33/13/1193774705783ba364121aa2a60132fa31a668b8ababd5edfa1662354ccd/cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062", size = 3794751 }, - { url = "https://files.pythonhosted.org/packages/5e/4b/39bb3c4c8cfb3e94e736b8d8859ce5c81536e91a1033b1d26770c4249000/cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962", size = 3981827 }, - { url = "https://files.pythonhosted.org/packages/ce/dc/1471d4d56608e1013237af334b8a4c35d53895694fbb73882d1c4fd3f55e/cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277", size = 3780034 }, - { url = "https://files.pythonhosted.org/packages/ad/43/7a9920135b0d5437cc2f8f529fa757431eb6a7736ddfadfdee1cc5890800/cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a", size = 3993407 }, - { url = "https://files.pythonhosted.org/packages/cc/42/9ab8467af6c0b76f3d9b8f01d1cf25b9c9f3f2151f4acfab888d21c55a72/cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042", size = 3886457 }, - { url = "https://files.pythonhosted.org/packages/a4/65/430509e31700286ec02868a2457d2111d03ccefc20349d24e58d171ae0a7/cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494", size = 4081499 }, - { url = "https://files.pythonhosted.org/packages/bb/18/a04b6467e6e09df8c73b91dcee8878f4a438a43a3603dc3cd6f8003b92d8/cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2", size = 2616504 }, - { url = "https://files.pythonhosted.org/packages/cc/73/0eacbdc437202edcbdc07f3576ed8fb8b0ab79d27bf2c5d822d758a72faa/cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d", size = 3067456 }, - { url = "https://files.pythonhosted.org/packages/8a/b6/bc54b371f02cffd35ff8dc6baba88304d7cf8e83632566b4b42e00383e03/cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d", size = 6225263 }, - { url = "https://files.pythonhosted.org/packages/00/0e/8217e348a1fa417ec4c78cd3cdf24154f5e76fd7597343a35bd403650dfd/cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806", size = 3794368 }, - { url = "https://files.pythonhosted.org/packages/3d/ed/38b6be7254d8f7251fde8054af597ee8afa14f911da67a9410a45f602fc3/cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85", size = 3981750 }, - { url = "https://files.pythonhosted.org/packages/64/f3/b7946c3887cf7436f002f4cbb1e6aec77b8d299b86be48eeadfefb937c4b/cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c", size = 3778925 }, - { url = "https://files.pythonhosted.org/packages/ac/7e/ebda4dd4ae098a0990753efbb4b50954f1d03003846b943ea85070782da7/cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1", size = 3993152 }, - { url = "https://files.pythonhosted.org/packages/43/f6/feebbd78a3e341e3913846a3bb2c29d0b09b1b3af1573c6baabc2533e147/cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa", size = 3886392 }, - { url = "https://files.pythonhosted.org/packages/bd/4c/ab0b9407d5247576290b4fd8abd06b7f51bd414f04eef0f2800675512d61/cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4", size = 4082606 }, - { url = "https://files.pythonhosted.org/packages/05/36/e532a671998d6fcfdb9122da16434347a58a6bae9465e527e450e0bc60a5/cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47", size = 2617948 }, - { url = "https://files.pythonhosted.org/packages/b3/c6/c09cee6968add5ff868525c3815e5dccc0e3c6e89eec58dc9135d3c40e88/cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb", size = 3070445 }, -] - -[[package]] -name = "deepmerge" -version = "2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a8/3a/b0ba594708f1ad0bc735884b3ad854d3ca3bdc1d741e56e40bbda6263499/deepmerge-2.0.tar.gz", hash = "sha256:5c3d86081fbebd04dd5de03626a0607b809a98fb6ccba5770b62466fe940ff20", size = 19890 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/82/e5d2c1c67d19841e9edc74954c827444ae826978499bde3dfc1d007c8c11/deepmerge-2.0-py3-none-any.whl", hash = "sha256:6de9ce507115cff0bed95ff0ce9ecc31088ef50cbdf09bc90a09349a318b3d00", size = 13475 }, + { url = "https://files.pythonhosted.org/packages/1f/f3/01fdf26701a26f4b4dbc337a26883ad5bccaa6f1bbbdd29cd89e22f18a1c/cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e", size = 6225303 }, + { url = "https://files.pythonhosted.org/packages/a3/01/4896f3d1b392025d4fcbecf40fdea92d3df8662123f6835d0af828d148fd/cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e", size = 3760905 }, + { url = "https://files.pythonhosted.org/packages/0a/be/f9a1f673f0ed4b7f6c643164e513dbad28dd4f2dcdf5715004f172ef24b6/cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f", size = 3977271 }, + { url = "https://files.pythonhosted.org/packages/4e/49/80c3a7b5514d1b416d7350830e8c422a4d667b6d9b16a9392ebfd4a5388a/cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6", size = 3746606 }, + { url = "https://files.pythonhosted.org/packages/0e/16/a28ddf78ac6e7e3f25ebcef69ab15c2c6be5ff9743dd0709a69a4f968472/cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18", size = 3986484 }, + { url = "https://files.pythonhosted.org/packages/01/f5/69ae8da70c19864a32b0315049866c4d411cce423ec169993d0434218762/cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd", size = 3852131 }, + { url = "https://files.pythonhosted.org/packages/fd/db/e74911d95c040f9afd3612b1f732e52b3e517cb80de8bf183be0b7d413c6/cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73", size = 4075647 }, + { url = "https://files.pythonhosted.org/packages/56/48/7b6b190f1462818b324e674fa20d1d5ef3e24f2328675b9b16189cbf0b3c/cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2", size = 2623873 }, + { url = "https://files.pythonhosted.org/packages/eb/b1/0ebff61a004f7f89e7b65ca95f2f2375679d43d0290672f7713ee3162aff/cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd", size = 3068039 }, + { url = "https://files.pythonhosted.org/packages/30/d5/c8b32c047e2e81dd172138f772e81d852c51f0f2ad2ae8a24f1122e9e9a7/cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984", size = 6222984 }, + { url = "https://files.pythonhosted.org/packages/2f/78/55356eb9075d0be6e81b59f45c7b48df87f76a20e73893872170471f3ee8/cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5", size = 3762968 }, + { url = "https://files.pythonhosted.org/packages/2a/2c/488776a3dc843f95f86d2f957ca0fc3407d0242b50bede7fad1e339be03f/cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4", size = 3977754 }, + { url = "https://files.pythonhosted.org/packages/7c/04/2345ca92f7a22f601a9c62961741ef7dd0127c39f7310dffa0041c80f16f/cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7", size = 3749458 }, + { url = "https://files.pythonhosted.org/packages/ac/25/e715fa0bc24ac2114ed69da33adf451a38abb6f3f24ec207908112e9ba53/cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405", size = 3988220 }, + { url = "https://files.pythonhosted.org/packages/21/ce/b9c9ff56c7164d8e2edfb6c9305045fbc0df4508ccfdb13ee66eb8c95b0e/cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16", size = 3853898 }, + { url = "https://files.pythonhosted.org/packages/2a/33/b3682992ab2e9476b9c81fff22f02c8b0a1e6e1d49ee1750a67d85fd7ed2/cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73", size = 4076592 }, + { url = "https://files.pythonhosted.org/packages/81/1e/ffcc41b3cebd64ca90b28fd58141c5f68c83d48563c88333ab660e002cd3/cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995", size = 2623145 }, + { url = "https://files.pythonhosted.org/packages/87/5c/3dab83cc4aba1f4b0e733e3f0c3e7d4386440d660ba5b1e3ff995feb734d/cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362", size = 3068026 }, ] [[package]] @@ -741,103 +686,46 @@ wheels = [ [[package]] name = "jiter" -version = "0.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/ef/64458dfad180debd70d9dd1ca4f607e52bb6de748e5284d748556a0d5173/jiter-0.6.1.tar.gz", hash = "sha256:e19cd21221fc139fb032e4112986656cb2739e9fe6d84c13956ab30ccc7d4449", size = 161306 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/5f/3ac960ed598726aae46edea916e6df4df7ff6fe084bc60774b95cf3154e6/jiter-0.5.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d4c8e1ed0ef31ad29cae5ea16b9e41529eb50a7fba70600008e9f8de6376d553", size = 284131 }, - { url = "https://files.pythonhosted.org/packages/03/eb/2308fa5f5c14c97c4c7720fef9465f1fa0771826cddb4eec9866bdd88846/jiter-0.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6f16e21276074a12d8421692515b3fd6d2ea9c94fd0734c39a12960a20e85f3", size = 299310 }, - { url = "https://files.pythonhosted.org/packages/3c/f6/dba34ca10b44715fa5302b8e8d2113f72eb00a9297ddf3fa0ae4fd22d1d1/jiter-0.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5280e68e7740c8c128d3ae5ab63335ce6d1fb6603d3b809637b11713487af9e6", size = 332282 }, - { url = "https://files.pythonhosted.org/packages/69/f7/64e0a7439790ec47f7681adb3871c9d9c45fff771102490bbee5e92c00b7/jiter-0.5.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:583c57fc30cc1fec360e66323aadd7fc3edeec01289bfafc35d3b9dcb29495e4", size = 342370 }, - { url = "https://files.pythonhosted.org/packages/55/31/1efbfff2ae8e4d919144c53db19b828049ad0622a670be3bbea94a86282c/jiter-0.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26351cc14507bdf466b5f99aba3df3143a59da75799bf64a53a3ad3155ecded9", size = 363591 }, - { url = "https://files.pythonhosted.org/packages/30/c3/7ab2ca2276426a7398c6dfb651e38dbc81954c79a3bfbc36c514d8599499/jiter-0.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4829df14d656b3fb87e50ae8b48253a8851c707da9f30d45aacab2aa2ba2d614", size = 378551 }, - { url = "https://files.pythonhosted.org/packages/47/e7/5d88031cd743c62199b125181a591b1671df3ff2f6e102df85c58d8f7d31/jiter-0.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a42a4bdcf7307b86cb863b2fb9bb55029b422d8f86276a50487982d99eed7c6e", size = 319152 }, - { url = "https://files.pythonhosted.org/packages/4c/2d/09ea58e1adca9f0359f3d41ef44a1a18e59518d7c43a21f4ece9e72e28c0/jiter-0.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04d461ad0aebf696f8da13c99bc1b3e06f66ecf6cfd56254cc402f6385231c06", size = 357377 }, - { url = "https://files.pythonhosted.org/packages/7d/2f/83ff1058cb56fc3ff73e0d3c6440703ddc9cdb7f759b00cfbde8228fc435/jiter-0.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e6375923c5f19888c9226582a124b77b622f8fd0018b843c45eeb19d9701c403", size = 511091 }, - { url = "https://files.pythonhosted.org/packages/ae/c9/4f85f97c9894382ab457382337aea0012711baaa17f2ed55c0ff25f3668a/jiter-0.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2cec323a853c24fd0472517113768c92ae0be8f8c384ef4441d3632da8baa646", size = 492948 }, - { url = "https://files.pythonhosted.org/packages/4d/f2/2e987e0eb465e064c5f52c2f29c8d955452e3b316746e326269263bfb1b7/jiter-0.5.0-cp311-none-win32.whl", hash = "sha256:aa1db0967130b5cab63dfe4d6ff547c88b2a394c3410db64744d491df7f069bb", size = 195183 }, - { url = "https://files.pythonhosted.org/packages/ab/59/05d1c3203c349b37c4dd28b02b9b4e5915a7bcbd9319173b4548a67d2e93/jiter-0.5.0-cp311-none-win_amd64.whl", hash = "sha256:aa9d2b85b2ed7dc7697597dcfaac66e63c1b3028652f751c81c65a9f220899ae", size = 191032 }, - { url = "https://files.pythonhosted.org/packages/aa/bd/c3950e2c478161e131bed8cb67c36aed418190e2a961a1c981e69954e54b/jiter-0.5.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9f664e7351604f91dcdd557603c57fc0d551bc65cc0a732fdacbf73ad335049a", size = 283511 }, - { url = "https://files.pythonhosted.org/packages/80/1c/8ce58d8c37a589eeaaa5d07d131fd31043886f5e77ab50c00a66d869a361/jiter-0.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:044f2f1148b5248ad2c8c3afb43430dccf676c5a5834d2f5089a4e6c5bbd64df", size = 296974 }, - { url = "https://files.pythonhosted.org/packages/4d/b8/6faeff9eed8952bed93a77ea1cffae7b946795b88eafd1a60e87a67b09e0/jiter-0.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:702e3520384c88b6e270c55c772d4bd6d7b150608dcc94dea87ceba1b6391248", size = 331897 }, - { url = "https://files.pythonhosted.org/packages/4f/54/1d9a2209b46d39ce6f0cef3ad87c462f9c50312ab84585e6bd5541292b35/jiter-0.5.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:528d742dcde73fad9d63e8242c036ab4a84389a56e04efd854062b660f559544", size = 342962 }, - { url = "https://files.pythonhosted.org/packages/2a/de/90360be7fc54b2b4c2dfe79eb4ed1f659fce9c96682e6a0be4bbe71371f7/jiter-0.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8cf80e5fe6ab582c82f0c3331df27a7e1565e2dcf06265afd5173d809cdbf9ba", size = 363844 }, - { url = "https://files.pythonhosted.org/packages/ba/ad/ef32b173191b7a53ea8a6757b80723cba321f8469834825e8c71c96bde17/jiter-0.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:44dfc9ddfb9b51a5626568ef4e55ada462b7328996294fe4d36de02fce42721f", size = 378709 }, - { url = "https://files.pythonhosted.org/packages/07/de/353ce53743c0defbbbd652e89c106a97dbbac4eb42c95920b74b5056b93a/jiter-0.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c451f7922992751a936b96c5f5b9bb9312243d9b754c34b33d0cb72c84669f4e", size = 319038 }, - { url = "https://files.pythonhosted.org/packages/3f/92/42d47310bf9530b9dece9e2d7c6d51cf419af5586ededaf5e66622d160e2/jiter-0.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:308fce789a2f093dca1ff91ac391f11a9f99c35369117ad5a5c6c4903e1b3e3a", size = 357763 }, - { url = "https://files.pythonhosted.org/packages/bd/8c/2bb76a9a84474d48fdd133d3445db8a4413da4e87c23879d917e000a9d87/jiter-0.5.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7f5ad4a7c6b0d90776fdefa294f662e8a86871e601309643de30bf94bb93a64e", size = 511031 }, - { url = "https://files.pythonhosted.org/packages/33/4f/9f23d79c0795e0a8e56e7988e8785c2dcda27e0ed37977256d50c77c6a19/jiter-0.5.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ea189db75f8eca08807d02ae27929e890c7d47599ce3d0a6a5d41f2419ecf338", size = 493042 }, - { url = "https://files.pythonhosted.org/packages/df/67/8a4f975aa834b8aecdb6b131422390173928fd47f42f269dcc32034ab432/jiter-0.5.0-cp312-none-win32.whl", hash = "sha256:e3bbe3910c724b877846186c25fe3c802e105a2c1fc2b57d6688b9f8772026e4", size = 195405 }, - { url = "https://files.pythonhosted.org/packages/15/81/296b1e25c43db67848728cdab34ac3eb5c5cbb4955ceb3f51ae60d4a5e3d/jiter-0.5.0-cp312-none-win_amd64.whl", hash = "sha256:a586832f70c3f1481732919215f36d41c59ca080fa27a65cf23d9490e75b2ef5", size = 189720 }, -] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, -] - -[[package]] -name = "markupsafe" -version = "3.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353 }, - { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392 }, - { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984 }, - { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120 }, - { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032 }, - { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057 }, - { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359 }, - { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306 }, - { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094 }, - { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521 }, - { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, - { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, - { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, - { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 }, - { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 }, - { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 }, - { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 }, - { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, - { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, - { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, - { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 }, - { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 }, - { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 }, - { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 }, - { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 }, - { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 }, - { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 }, - { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 }, - { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 }, - { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 }, - { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 }, - { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 }, - { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 }, - { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 }, - { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 }, - { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 }, - { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 }, - { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 }, - { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, - { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" +version = "0.7.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, +sdist = { url = "https://files.pythonhosted.org/packages/ac/3d/4ca1c6b8d1d15ea747da474891f9879c0f0777e2e44e87c0be81657ed016/jiter-0.7.0.tar.gz", hash = "sha256:c061d9738535497b5509f8970584f20de1e900806b239a39a9994fc191dad630", size = 162154 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f3/01/ac41fe6d402da0ff454e2abaee6b8cc29ad2c97cf985f503e46ca7724aca/jiter-0.7.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:91cec0ad755bd786c9f769ce8d843af955df6a8e56b17658771b2d5cb34a3ff8", size = 292667 }, + { url = "https://files.pythonhosted.org/packages/9d/cb/d2e612729676cbe022ad732aaed9c842ac459a70808a927f7f845cfc6dc1/jiter-0.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:feba70a28a27d962e353e978dbb6afd798e711c04cb0b4c5e77e9d3779033a1a", size = 306403 }, + { url = "https://files.pythonhosted.org/packages/e9/db/d88002c550f6405dbf98962cc3dc1c8e66de9c4f3246abebe1582b2f919f/jiter-0.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9d866ec066c3616cacb8535dbda38bb1d470b17b25f0317c4540182bc886ce2", size = 329020 }, + { url = "https://files.pythonhosted.org/packages/18/42/54d6527bcdea2909396849491b96a6fe595bd97ec43bdc522399c534ed33/jiter-0.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8e7a7a00b6f9f18289dd563596f97ecaba6c777501a8ba04bf98e03087bcbc60", size = 347638 }, + { url = "https://files.pythonhosted.org/packages/ec/12/a3c43061d5e189def91c07472e64a569196687f60c2f86150e29a5692ce7/jiter-0.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9aaf564094c7db8687f2660605e099f3d3e6ea5e7135498486674fcb78e29165", size = 373916 }, + { url = "https://files.pythonhosted.org/packages/32/08/2c7432ed26d194927ec07c1dfc08cdae5b6d302369df7fdda320d6393736/jiter-0.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a4d27e09825c1b3c7a667adb500ce8b840e8fc9f630da8454b44cdd4fb0081bb", size = 390942 }, + { url = "https://files.pythonhosted.org/packages/65/9b/70f3ecbd3f18ef19e50fbe5a51bdb1c520282720896c16ae1a68b90675b8/jiter-0.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ca7c287da9c1d56dda88da1d08855a787dbb09a7e2bd13c66a2e288700bd7c7", size = 327315 }, + { url = "https://files.pythonhosted.org/packages/2c/30/ba97e50e5fe1f58a1012257e0cfac0cc09e548b63f81982546c6dac8f1e7/jiter-0.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db19a6d160f093cbc8cd5ea2abad420b686f6c0e5fb4f7b41941ebc6a4f83cda", size = 367159 }, + { url = "https://files.pythonhosted.org/packages/a1/6d/73bb48ca87951c6c01b902258d0b792ed9404980bafceb1aa87ac43eb925/jiter-0.7.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6e46a63c7f877cf7441ffc821c28287cfb9f533ae6ed707bde15e7d4dfafa7ae", size = 514891 }, + { url = "https://files.pythonhosted.org/packages/6f/03/50c665a3d9067c5e384604310d67a184ae3176f27f677ca0c2670bb061ac/jiter-0.7.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7ba426fa7ff21cb119fa544b75dd3fbee6a70e55a5829709c0338d07ccd30e6d", size = 498039 }, + { url = "https://files.pythonhosted.org/packages/85/35/9fb7c7fea9b9c159d2089ea9b5ff4e3e56e2d42069456e3568dadf904e99/jiter-0.7.0-cp311-none-win32.whl", hash = "sha256:c07f55a64912b0c7982377831210836d2ea92b7bd343fca67a32212dd72e38e0", size = 198533 }, + { url = "https://files.pythonhosted.org/packages/96/19/e9b32c69c6dea404d983847e92cf86c3287b0f2f3e7621180a544c0ff153/jiter-0.7.0-cp311-none-win_amd64.whl", hash = "sha256:ed27b2c43e1b5f6c7fedc5c11d4d8bfa627de42d1143d87e39e2e83ddefd861a", size = 205728 }, + { url = "https://files.pythonhosted.org/packages/d9/7b/ed881a65e8f0989913408643b68a3a0913365c5c3884e85bae01a9679dd5/jiter-0.7.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ac7930bcaaeb1e229e35c91c04ed2e9f39025b86ee9fc3141706bbf6fff4aeeb", size = 292762 }, + { url = "https://files.pythonhosted.org/packages/d8/44/d0409912bc28508abffd99b9d55baba869592c1d27f9ee1cc035ef62371e/jiter-0.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:571feae3e7c901a8eedde9fd2865b0dfc1432fb15cab8c675a8444f7d11b7c5d", size = 302790 }, + { url = "https://files.pythonhosted.org/packages/8d/4f/38d0e87c8863c1b1f2dbac48acca8da85f6931a7b735e7163781843170a5/jiter-0.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8af4df8a262fa2778b68c2a03b6e9d1cb4d43d02bea6976d46be77a3a331af1", size = 329246 }, + { url = "https://files.pythonhosted.org/packages/88/3c/1af75094cbeba25df672b3f772dc717203be843e08248a0e03ef0ca382bc/jiter-0.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd028d4165097a611eb0c7494d8c1f2aebd46f73ca3200f02a175a9c9a6f22f5", size = 347808 }, + { url = "https://files.pythonhosted.org/packages/0b/74/55f00ca01223665e1418bec76cdeebb17a5f9ffae94e886da5c9bef5abd2/jiter-0.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6b487247c7836810091e9455efe56a52ec51bfa3a222237e1587d04d3e04527", size = 374011 }, + { url = "https://files.pythonhosted.org/packages/f7/ae/c1c892861796aa0adb720da75c59de5dbcf74ad51243c2aeea46681dcb16/jiter-0.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6d28a92f28814e1a9f2824dc11f4e17e1df1f44dc4fdeb94c5450d34bcb2602", size = 388863 }, + { url = "https://files.pythonhosted.org/packages/9d/a2/914587a68cba16920b1f979267a4e5c19f6977cac8fb8a6fbbd00035d0ed/jiter-0.7.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90443994bbafe134f0b34201dad3ebe1c769f0599004084e046fb249ad912425", size = 326765 }, + { url = "https://files.pythonhosted.org/packages/c8/ea/79abc48a6c9ba9ee3ccb0c194ec4cc1dd62e523c7c7003189380d00e5f16/jiter-0.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f9abf464f9faac652542ce8360cea8e68fba2b78350e8a170248f9bcc228702a", size = 367756 }, + { url = "https://files.pythonhosted.org/packages/4b/eb/ddc874819382081f9ad71cf681ee76450b17ac981f78a8db6408e7e28f34/jiter-0.7.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db7a8d99fc5f842f7d2852f06ccaed066532292c41723e5dff670c339b649f88", size = 515349 }, + { url = "https://files.pythonhosted.org/packages/af/9d/816d2d7f19070b72cf0133437cbacf99a9202f6fbbc2cfa2111fb686b0e0/jiter-0.7.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:15cf691ebd8693b70c94627d6b748f01e6d697d9a6e9f2bc310934fcfb7cf25e", size = 498050 }, + { url = "https://files.pythonhosted.org/packages/3e/a5/d0afb758c02d2d3c8ac3214a5be26579594d790944eaee7a47af06915e0e/jiter-0.7.0-cp312-none-win32.whl", hash = "sha256:9dcd54fa422fb66ca398bec296fed5f58e756aa0589496011cfea2abb5be38a5", size = 198912 }, + { url = "https://files.pythonhosted.org/packages/d0/8e/80b2afd0391a3530966d8fc2f9c104955ba41093b3c319ae40b25e68e323/jiter-0.7.0-cp312-none-win_amd64.whl", hash = "sha256:cc989951f73f9375b8eacd571baaa057f3d7d11b7ce6f67b9d54642e7475bfad", size = 199942 }, + { url = "https://files.pythonhosted.org/packages/50/bb/82c7180dc126687ddcc25386727b3a1688ab8eff496afe7838b69886fcc7/jiter-0.7.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:24cecd18df540963cd27c08ca5ce1d0179f229ff78066d9eecbe5add29361340", size = 292624 }, + { url = "https://files.pythonhosted.org/packages/11/c2/3b6d4596eab2ff81ebfe5bab779f457433cc2ffb8a2d1d6ab5ac187f26f6/jiter-0.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d41b46236b90b043cca73785674c23d2a67d16f226394079d0953f94e765ed76", size = 304723 }, + { url = "https://files.pythonhosted.org/packages/49/65/56f78dfccfb22e43815cad4a468b4360f8cfebecc024edb5e2a625b83a04/jiter-0.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b160db0987171365c153e406a45dcab0ee613ae3508a77bfff42515cb4ce4d6e", size = 328319 }, + { url = "https://files.pythonhosted.org/packages/fd/f2/9e3ed9ac0b122dd65250fc83cd0f0979da82f055ef6041411191f6301284/jiter-0.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1c8d91e0f0bd78602eaa081332e8ee4f512c000716f5bc54e9a037306d693a7", size = 347323 }, + { url = "https://files.pythonhosted.org/packages/42/18/24517f9f8575daf36fdac9dd53fcecde3d4c5bdd9f7b97a55e26ed2555b5/jiter-0.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997706c683195eeff192d2e5285ce64d2a610414f37da3a3f2625dcf8517cf90", size = 374073 }, + { url = "https://files.pythonhosted.org/packages/a1/b1/b368ccdeff3eabb4b293a21a94317a6f717ecc5bfbfca4eecd12ff39da3f/jiter-0.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ea52a8a0ff0229ab2920284079becd2bae0688d432fca94857ece83bb49c541", size = 388224 }, + { url = "https://files.pythonhosted.org/packages/92/1e/cc3d0655bcbc026e4b7746cb1ccab10d6eb2c29ffa64e574072db4d55f73/jiter-0.7.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d77449d2738cf74752bb35d75ee431af457e741124d1db5e112890023572c7c", size = 326145 }, + { url = "https://files.pythonhosted.org/packages/bb/24/d410c732326738d4f392689621ff14e10d3717efe7de9ecb97c44d8765a3/jiter-0.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8203519907a1d81d6cb00902c98e27c2d0bf25ce0323c50ca594d30f5f1fbcf", size = 366857 }, + { url = "https://files.pythonhosted.org/packages/14/a1/53df95b8248968936e7ba9eb5839918e3cfd183e56356d2961b9b29a49fc/jiter-0.7.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41d15ccc53931c822dd7f1aebf09faa3cda2d7b48a76ef304c7dbc19d1302e51", size = 514972 }, + { url = "https://files.pythonhosted.org/packages/97/c8/1876add533606ff1204450dd2564638cac7f164ff90844cb921cdf25cf68/jiter-0.7.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:febf3179b2fabf71fbd2fd52acb8594163bb173348b388649567a548f356dbf6", size = 497728 }, + { url = "https://files.pythonhosted.org/packages/94/31/1e59f246e264414b004864b63783e54aa3397be88f53dda3b01db3ae4251/jiter-0.7.0-cp313-none-win32.whl", hash = "sha256:4a8e2d866e7eda19f012444e01b55079d8e1c4c30346aaac4b97e80c54e2d6d3", size = 198660 }, + { url = "https://files.pythonhosted.org/packages/ca/96/58b3d260e212add0087563672931b1176e70bef1225839a4470ec66157a5/jiter-0.7.0-cp313-none-win_amd64.whl", hash = "sha256:7417c2b928062c496f381fb0cb50412eee5ad1d8b53dbc0e011ce45bb2de522c", size = 199305 }, ] [[package]] @@ -992,7 +880,7 @@ wheels = [ [[package]] name = "openai" -version = "1.52.1" +version = "1.54.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -1004,97 +892,9 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/80/ac/54c76352d493866637756b7c0ecec44f0b5bafb8fe753d98472cf6cfe4ce/openai-1.52.1.tar.gz", hash = "sha256:383b96c7e937cbec23cad5bf5718085381e4313ca33c5c5896b54f8e1b19d144", size = 310069 } +sdist = { url = "https://files.pythonhosted.org/packages/da/26/f1a79d8332ac5ed38fdc347701aa4a7ad8f8f66ec3f9880122c455d7ffb1/openai-1.54.2.tar.gz", hash = "sha256:0dbb8f2bb36f7ff1d200d103b9f95c35773ed3248e3a697b02f5a39015627e5e", size = 312551 } wheels = [ - { url = "https://files.pythonhosted.org/packages/ad/31/28a83e124e9f9dd04c83b5aeb6f8b1770f45addde4dd3d34d9a9091590ad/openai-1.52.1-py3-none-any.whl", hash = "sha256:f23e83df5ba04ee0e82c8562571e8cb596cd88f9a84ab783e6c6259e5ffbfb4a", size = 386945 }, -] - -[[package]] -name = "openai-client" -version = "0.1.0" -source = { editable = "../openai-client" } -dependencies = [ - { name = "azure-ai-contentsafety" }, - { name = "azure-core", extra = ["aio"] }, - { name = "azure-identity" }, - { name = "function-registry" }, - { name = "openai" }, - { name = "pillow" }, - { name = "semantic-workbench-assistant" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, - { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "function-registry", editable = "../function-registry" }, - { name = "openai", specifier = ">=1.3.9" }, - { name = "pillow", specifier = ">=11.0.0" }, - { name = "semantic-workbench-assistant", editable = "../semantic-workbench-assistant" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[package.metadata.requires-dev] -dev = [{ name = "pytest", specifier = ">=8.3.3" }] - -[[package]] -name = "packaging" -version = "24.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/51/65/50db4dda066951078f0a96cf12f4b9ada6e4b811516bf0262c0f4f7064d4/packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", size = 148788 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124", size = 53985 }, -] - -[[package]] -name = "pillow" -version = "11.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/26/0d95c04c868f6bdb0c447e3ee2de5564411845e36a858cfd63766bc7b563/pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739", size = 46737780 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f0/eb/f7e21b113dd48a9c97d364e0915b3988c6a0b6207652f5a92372871b7aa4/pillow-11.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1c1d72714f429a521d8d2d018badc42414c3077eb187a59579f28e4270b4b0fc", size = 3154705 }, - { url = "https://files.pythonhosted.org/packages/25/b3/2b54a1d541accebe6bd8b1358b34ceb2c509f51cb7dcda8687362490da5b/pillow-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:499c3a1b0d6fc8213519e193796eb1a86a1be4b1877d678b30f83fd979811d1a", size = 2979222 }, - { url = "https://files.pythonhosted.org/packages/20/12/1a41eddad8265c5c19dda8fb6c269ce15ee25e0b9f8f26286e6202df6693/pillow-11.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8b2351c85d855293a299038e1f89db92a2f35e8d2f783489c6f0b2b5f3fe8a3", size = 4190220 }, - { url = "https://files.pythonhosted.org/packages/a9/9b/8a8c4d07d77447b7457164b861d18f5a31ae6418ef5c07f6f878fa09039a/pillow-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4dba50cfa56f910241eb7f883c20f1e7b1d8f7d91c750cd0b318bad443f4d5", size = 4291399 }, - { url = "https://files.pythonhosted.org/packages/fc/e4/130c5fab4a54d3991129800dd2801feeb4b118d7630148cd67f0e6269d4c/pillow-11.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5ddbfd761ee00c12ee1be86c9c0683ecf5bb14c9772ddbd782085779a63dd55b", size = 4202709 }, - { url = "https://files.pythonhosted.org/packages/39/63/b3fc299528d7df1f678b0666002b37affe6b8751225c3d9c12cf530e73ed/pillow-11.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa", size = 4372556 }, - { url = "https://files.pythonhosted.org/packages/c6/a6/694122c55b855b586c26c694937d36bb8d3b09c735ff41b2f315c6e66a10/pillow-11.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b4fd7bd29610a83a8c9b564d457cf5bd92b4e11e79a4ee4716a63c959699b306", size = 4287187 }, - { url = "https://files.pythonhosted.org/packages/ba/a9/f9d763e2671a8acd53d29b1e284ca298bc10a595527f6be30233cdb9659d/pillow-11.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cb929ca942d0ec4fac404cbf520ee6cac37bf35be479b970c4ffadf2b6a1cad9", size = 4418468 }, - { url = "https://files.pythonhosted.org/packages/6e/0e/b5cbad2621377f11313a94aeb44ca55a9639adabcaaa073597a1925f8c26/pillow-11.0.0-cp311-cp311-win32.whl", hash = "sha256:006bcdd307cc47ba43e924099a038cbf9591062e6c50e570819743f5607404f5", size = 2249249 }, - { url = "https://files.pythonhosted.org/packages/dc/83/1470c220a4ff06cd75fc609068f6605e567ea51df70557555c2ab6516b2c/pillow-11.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:52a2d8323a465f84faaba5236567d212c3668f2ab53e1c74c15583cf507a0291", size = 2566769 }, - { url = "https://files.pythonhosted.org/packages/52/98/def78c3a23acee2bcdb2e52005fb2810ed54305602ec1bfcfab2bda6f49f/pillow-11.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:16095692a253047fe3ec028e951fa4221a1f3ed3d80c397e83541a3037ff67c9", size = 2254611 }, - { url = "https://files.pythonhosted.org/packages/1c/a3/26e606ff0b2daaf120543e537311fa3ae2eb6bf061490e4fea51771540be/pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923", size = 3147642 }, - { url = "https://files.pythonhosted.org/packages/4f/d5/1caabedd8863526a6cfa44ee7a833bd97f945dc1d56824d6d76e11731939/pillow-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903", size = 2978999 }, - { url = "https://files.pythonhosted.org/packages/d9/ff/5a45000826a1aa1ac6874b3ec5a856474821a1b59d838c4f6ce2ee518fe9/pillow-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4", size = 4196794 }, - { url = "https://files.pythonhosted.org/packages/9d/21/84c9f287d17180f26263b5f5c8fb201de0f88b1afddf8a2597a5c9fe787f/pillow-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f", size = 4300762 }, - { url = "https://files.pythonhosted.org/packages/84/39/63fb87cd07cc541438b448b1fed467c4d687ad18aa786a7f8e67b255d1aa/pillow-11.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9", size = 4210468 }, - { url = "https://files.pythonhosted.org/packages/7f/42/6e0f2c2d5c60f499aa29be14f860dd4539de322cd8fb84ee01553493fb4d/pillow-11.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7", size = 4381824 }, - { url = "https://files.pythonhosted.org/packages/31/69/1ef0fb9d2f8d2d114db982b78ca4eeb9db9a29f7477821e160b8c1253f67/pillow-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6", size = 4296436 }, - { url = "https://files.pythonhosted.org/packages/44/ea/dad2818c675c44f6012289a7c4f46068c548768bc6c7f4e8c4ae5bbbc811/pillow-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc", size = 4429714 }, - { url = "https://files.pythonhosted.org/packages/af/3a/da80224a6eb15bba7a0dcb2346e2b686bb9bf98378c0b4353cd88e62b171/pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6", size = 2249631 }, - { url = "https://files.pythonhosted.org/packages/57/97/73f756c338c1d86bb802ee88c3cab015ad7ce4b838f8a24f16b676b1ac7c/pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47", size = 2567533 }, - { url = "https://files.pythonhosted.org/packages/0b/30/2b61876e2722374558b871dfbfcbe4e406626d63f4f6ed92e9c8e24cac37/pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25", size = 2254890 }, - { url = "https://files.pythonhosted.org/packages/63/24/e2e15e392d00fcf4215907465d8ec2a2f23bcec1481a8ebe4ae760459995/pillow-11.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699", size = 3147300 }, - { url = "https://files.pythonhosted.org/packages/43/72/92ad4afaa2afc233dc44184adff289c2e77e8cd916b3ddb72ac69495bda3/pillow-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38", size = 2978742 }, - { url = "https://files.pythonhosted.org/packages/9e/da/c8d69c5bc85d72a8523fe862f05ababdc52c0a755cfe3d362656bb86552b/pillow-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2", size = 4194349 }, - { url = "https://files.pythonhosted.org/packages/cd/e8/686d0caeed6b998351d57796496a70185376ed9c8ec7d99e1d19ad591fc6/pillow-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2", size = 4298714 }, - { url = "https://files.pythonhosted.org/packages/ec/da/430015cec620d622f06854be67fd2f6721f52fc17fca8ac34b32e2d60739/pillow-11.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527", size = 4208514 }, - { url = "https://files.pythonhosted.org/packages/44/ae/7e4f6662a9b1cb5f92b9cc9cab8321c381ffbee309210940e57432a4063a/pillow-11.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa", size = 4380055 }, - { url = "https://files.pythonhosted.org/packages/74/d5/1a807779ac8a0eeed57f2b92a3c32ea1b696e6140c15bd42eaf908a261cd/pillow-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f", size = 4296751 }, - { url = "https://files.pythonhosted.org/packages/38/8c/5fa3385163ee7080bc13026d59656267daaaaf3c728c233d530e2c2757c8/pillow-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb", size = 4430378 }, - { url = "https://files.pythonhosted.org/packages/ca/1d/ad9c14811133977ff87035bf426875b93097fb50af747793f013979facdb/pillow-11.0.0-cp313-cp313-win32.whl", hash = "sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798", size = 2249588 }, - { url = "https://files.pythonhosted.org/packages/fb/01/3755ba287dac715e6afdb333cb1f6d69740a7475220b4637b5ce3d78cec2/pillow-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de", size = 2567509 }, - { url = "https://files.pythonhosted.org/packages/c0/98/2c7d727079b6be1aba82d195767d35fcc2d32204c7a5820f822df5330152/pillow-11.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84", size = 2254791 }, - { url = "https://files.pythonhosted.org/packages/eb/38/998b04cc6f474e78b563716b20eecf42a2fa16a84589d23c8898e64b0ffd/pillow-11.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b", size = 3150854 }, - { url = "https://files.pythonhosted.org/packages/13/8e/be23a96292113c6cb26b2aa3c8b3681ec62b44ed5c2bd0b258bd59503d3c/pillow-11.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003", size = 2982369 }, - { url = "https://files.pythonhosted.org/packages/97/8a/3db4eaabb7a2ae8203cd3a332a005e4aba00067fc514aaaf3e9721be31f1/pillow-11.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2", size = 4333703 }, - { url = "https://files.pythonhosted.org/packages/28/ac/629ffc84ff67b9228fe87a97272ab125bbd4dc462745f35f192d37b822f1/pillow-11.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a", size = 4412550 }, - { url = "https://files.pythonhosted.org/packages/d6/07/a505921d36bb2df6868806eaf56ef58699c16c388e378b0dcdb6e5b2fb36/pillow-11.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8", size = 4461038 }, - { url = "https://files.pythonhosted.org/packages/d6/b9/fb620dd47fc7cc9678af8f8bd8c772034ca4977237049287e99dda360b66/pillow-11.0.0-cp313-cp313t-win32.whl", hash = "sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8", size = 2253197 }, - { url = "https://files.pythonhosted.org/packages/df/86/25dde85c06c89d7fc5db17940f07aae0a56ac69aa9ccb5eb0f09798862a8/pillow-11.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904", size = 2572169 }, - { url = "https://files.pythonhosted.org/packages/51/85/9c33f2517add612e17f3381aee7c4072779130c634921a756c97bc29fb49/pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3", size = 2256828 }, + { url = "https://files.pythonhosted.org/packages/f6/0f/ea8717dedbef16fa61a0bdeb0b7ae96ff574933ed5932102d3f5a4ce01a1/openai-1.54.2-py3-none-any.whl", hash = "sha256:77010b439e69d37f67cc2f44eaa62b2b6d5a60add2d8636e4603c0e762982708", size = 389315 }, ] [[package]] @@ -1328,24 +1128,15 @@ wheels = [ [[package]] name = "pydantic-settings" -version = "2.6.0" +version = "2.6.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6c/66/5f1a9da10675bfb3b9da52f5b689c77e0a5612263fcce510cfac3e99a168/pydantic_settings-2.6.0.tar.gz", hash = "sha256:44a1804abffac9e6a30372bb45f6cafab945ef5af25e66b1c634c01dd39e0188", size = 75232 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/29/8d/29e82e333f32d9e2051c10764b906c2a6cd140992910b5f49762790911ba/pydantic_settings-2.5.2-py3-none-any.whl", hash = "sha256:2c912e55fd5794a59bf8c832b9de832dcfdf4778d79ff79b708744eed499a907", size = 26864 }, -] - -[[package]] -name = "pygments" -version = "2.18.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", size = 4891905 } +sdist = { url = "https://files.pythonhosted.org/packages/b5/d4/9dfbe238f45ad8b168f5c96ee49a3df0598ce18a0795a983b419949ce65b/pydantic_settings-2.6.1.tar.gz", hash = "sha256:e0f92546d8a9923cb8941689abf85d6601a8c19a23e97a34b2964a2e3f813ca0", size = 75646 } wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", size = 1205513 }, + { url = "https://files.pythonhosted.org/packages/5e/f9/ff95fd7d760af42f647ea87f9b8a383d891cdb5e5dbd4613edaeb094252a/pydantic_settings-2.6.1-py3-none-any.whl", hash = "sha256:7fb0637c786a558d3103436278a7c4f1cfd29ba8973238a50c5bb9a55387da87", size = 28595 }, ] [[package]] @@ -1429,47 +1220,15 @@ name = "pywin32" version = "308" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/1e/fc18ad83ca553e01b97aa8393ff10e33c1fb57801db05488b83282ee9913/pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407", size = 8507689 }, - { url = "https://files.pythonhosted.org/packages/7e/9e/ad6b1ae2a5ad1066dc509350e0fbf74d8d50251a51e420a2a8feaa0cecbd/pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e", size = 9227547 }, - { url = "https://files.pythonhosted.org/packages/91/20/f744bff1da8f43388498503634378dbbefbe493e65675f2cc52f7185c2c2/pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a", size = 10388324 }, - { url = "https://files.pythonhosted.org/packages/14/91/17e016d5923e178346aabda3dfec6629d1a26efe587d19667542105cf0a6/pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b", size = 8507705 }, - { url = "https://files.pythonhosted.org/packages/83/1c/25b79fc3ec99b19b0a0730cc47356f7e2959863bf9f3cd314332bddb4f68/pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e", size = 9227429 }, - { url = "https://files.pythonhosted.org/packages/1c/43/e3444dc9a12f8365d9603c2145d16bf0a2f8180f343cf87be47f5579e547/pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040", size = 10388145 }, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612 }, - { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040 }, - { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829 }, - { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167 }, - { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952 }, - { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301 }, - { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638 }, - { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850 }, - { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980 }, - { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 }, - { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 }, - { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 }, - { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 }, - { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 }, - { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 }, - { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, - { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, - { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, - { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 }, - { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 }, - { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 }, - { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 }, - { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 }, - { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 }, - { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 }, - { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, - { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, + { url = "https://files.pythonhosted.org/packages/eb/e2/02652007469263fe1466e98439831d65d4ca80ea1a2df29abecedf7e47b7/pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a", size = 5928156 }, + { url = "https://files.pythonhosted.org/packages/48/ef/f4fb45e2196bc7ffe09cad0542d9aff66b0e33f6c0954b43e49c33cad7bd/pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b", size = 6559559 }, + { url = "https://files.pythonhosted.org/packages/79/ef/68bb6aa865c5c9b11a35771329e95917b5559845bd75b65549407f9fc6b4/pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6", size = 7972495 }, + { url = "https://files.pythonhosted.org/packages/00/7c/d00d6bdd96de4344e06c4afbf218bc86b54436a94c01c71a8701f613aa56/pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897", size = 5939729 }, + { url = "https://files.pythonhosted.org/packages/21/27/0c8811fbc3ca188f93b5354e7c286eb91f80a53afa4e11007ef661afa746/pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47", size = 6543015 }, + { url = "https://files.pythonhosted.org/packages/9d/0f/d40f8373608caed2255781a3ad9a51d03a594a1248cd632d6a298daca693/pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091", size = 7976033 }, + { url = "https://files.pythonhosted.org/packages/a9/a4/aa562d8935e3df5e49c161b427a3a2efad2ed4e9cf81c3de636f1fdddfd0/pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed", size = 5938579 }, + { url = "https://files.pythonhosted.org/packages/c7/50/b0efb8bb66210da67a53ab95fd7a98826a97ee21f1d22949863e6d588b22/pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4", size = 6542056 }, + { url = "https://files.pythonhosted.org/packages/26/df/2b63e3e4f2df0224f8aaf6d131f54fe4e8c96400eb9df563e2aae2e1a1f9/pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd", size = 7974986 }, ] [[package]] @@ -1509,55 +1268,55 @@ wheels = [ [[package]] name = "regex" -version = "2024.9.11" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f9/38/148df33b4dbca3bd069b963acab5e0fa1a9dbd6820f8c322d0dd6faeff96/regex-2024.9.11.tar.gz", hash = "sha256:6c188c307e8433bcb63dc1915022deb553b4203a70722fc542c363bf120a01fd", size = 399403 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/a1/d526b7b6095a0019aa360948c143aacfeb029919c898701ce7763bbe4c15/regex-2024.9.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2cce2449e5927a0bf084d346da6cd5eb016b2beca10d0013ab50e3c226ffc0df", size = 482483 }, - { url = "https://files.pythonhosted.org/packages/32/d9/bfdd153179867c275719e381e1e8e84a97bd186740456a0dcb3e7125c205/regex-2024.9.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b37fa423beefa44919e009745ccbf353d8c981516e807995b2bd11c2c77d268", size = 287442 }, - { url = "https://files.pythonhosted.org/packages/33/c4/60f3370735135e3a8d673ddcdb2507a8560d0e759e1398d366e43d000253/regex-2024.9.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:64ce2799bd75039b480cc0360907c4fb2f50022f030bf9e7a8705b636e408fad", size = 284561 }, - { url = "https://files.pythonhosted.org/packages/b1/51/91a5ebdff17f9ec4973cb0aa9d37635efec1c6868654bbc25d1543aca4ec/regex-2024.9.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4cc92bb6db56ab0c1cbd17294e14f5e9224f0cc6521167ef388332604e92679", size = 791779 }, - { url = "https://files.pythonhosted.org/packages/07/4a/022c5e6f0891a90cd7eb3d664d6c58ce2aba48bff107b00013f3d6167069/regex-2024.9.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d05ac6fa06959c4172eccd99a222e1fbf17b5670c4d596cb1e5cde99600674c4", size = 832605 }, - { url = "https://files.pythonhosted.org/packages/ac/1c/3793990c8c83ca04e018151ddda83b83ecc41d89964f0f17749f027fc44d/regex-2024.9.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040562757795eeea356394a7fb13076ad4f99d3c62ab0f8bdfb21f99a1f85664", size = 818556 }, - { url = "https://files.pythonhosted.org/packages/e9/5c/8b385afbfacb853730682c57be56225f9fe275c5bf02ac1fc88edbff316d/regex-2024.9.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6113c008a7780792efc80f9dfe10ba0cd043cbf8dc9a76ef757850f51b4edc50", size = 792808 }, - { url = "https://files.pythonhosted.org/packages/9b/8b/a4723a838b53c771e9240951adde6af58c829fb6a6a28f554e8131f53839/regex-2024.9.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e5fb5f77c8745a60105403a774fe2c1759b71d3e7b4ca237a5e67ad066c7199", size = 781115 }, - { url = "https://files.pythonhosted.org/packages/83/5f/031a04b6017033d65b261259c09043c06f4ef2d4eac841d0649d76d69541/regex-2024.9.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:54d9ff35d4515debf14bc27f1e3b38bfc453eff3220f5bce159642fa762fe5d4", size = 778155 }, - { url = "https://files.pythonhosted.org/packages/fd/cd/4660756070b03ce4a66663a43f6c6e7ebc2266cc6b4c586c167917185eb4/regex-2024.9.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:df5cbb1fbc74a8305b6065d4ade43b993be03dbe0f8b30032cced0d7740994bd", size = 784614 }, - { url = "https://files.pythonhosted.org/packages/93/8d/65b9bea7df120a7be8337c415b6d256ba786cbc9107cebba3bf8ff09da99/regex-2024.9.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7fb89ee5d106e4a7a51bce305ac4efb981536301895f7bdcf93ec92ae0d91c7f", size = 853744 }, - { url = "https://files.pythonhosted.org/packages/96/a7/fba1eae75eb53a704475baf11bd44b3e6ccb95b316955027eb7748f24ef8/regex-2024.9.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a738b937d512b30bf75995c0159c0ddf9eec0775c9d72ac0202076c72f24aa96", size = 855890 }, - { url = "https://files.pythonhosted.org/packages/45/14/d864b2db80a1a3358534392373e8a281d95b28c29c87d8548aed58813910/regex-2024.9.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e28f9faeb14b6f23ac55bfbbfd3643f5c7c18ede093977f1df249f73fd22c7b1", size = 781887 }, - { url = "https://files.pythonhosted.org/packages/4d/a9/bfb29b3de3eb11dc9b412603437023b8e6c02fb4e11311863d9bf62c403a/regex-2024.9.11-cp311-cp311-win32.whl", hash = "sha256:18e707ce6c92d7282dfce370cd205098384b8ee21544e7cb29b8aab955b66fa9", size = 261644 }, - { url = "https://files.pythonhosted.org/packages/c7/ab/1ad2511cf6a208fde57fafe49829cab8ca018128ab0d0b48973d8218634a/regex-2024.9.11-cp311-cp311-win_amd64.whl", hash = "sha256:313ea15e5ff2a8cbbad96ccef6be638393041b0a7863183c2d31e0c6116688cf", size = 274033 }, - { url = "https://files.pythonhosted.org/packages/6e/92/407531450762bed778eedbde04407f68cbd75d13cee96c6f8d6903d9c6c1/regex-2024.9.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b0d0a6c64fcc4ef9c69bd5b3b3626cc3776520a1637d8abaa62b9edc147a58f7", size = 483590 }, - { url = "https://files.pythonhosted.org/packages/8e/a2/048acbc5ae1f615adc6cba36cc45734e679b5f1e4e58c3c77f0ed611d4e2/regex-2024.9.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:49b0e06786ea663f933f3710a51e9385ce0cba0ea56b67107fd841a55d56a231", size = 288175 }, - { url = "https://files.pythonhosted.org/packages/8a/ea/909d8620329ab710dfaf7b4adee41242ab7c9b95ea8d838e9bfe76244259/regex-2024.9.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5b513b6997a0b2f10e4fd3a1313568e373926e8c252bd76c960f96fd039cd28d", size = 284749 }, - { url = "https://files.pythonhosted.org/packages/ca/fa/521eb683b916389b4975337873e66954e0f6d8f91bd5774164a57b503185/regex-2024.9.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee439691d8c23e76f9802c42a95cfeebf9d47cf4ffd06f18489122dbb0a7ad64", size = 795181 }, - { url = "https://files.pythonhosted.org/packages/28/db/63047feddc3280cc242f9c74f7aeddc6ee662b1835f00046f57d5630c827/regex-2024.9.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8f877c89719d759e52783f7fe6e1c67121076b87b40542966c02de5503ace42", size = 835842 }, - { url = "https://files.pythonhosted.org/packages/e3/94/86adc259ff8ec26edf35fcca7e334566c1805c7493b192cb09679f9c3dee/regex-2024.9.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23b30c62d0f16827f2ae9f2bb87619bc4fba2044911e2e6c2eb1af0161cdb766", size = 823533 }, - { url = "https://files.pythonhosted.org/packages/29/52/84662b6636061277cb857f658518aa7db6672bc6d1a3f503ccd5aefc581e/regex-2024.9.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ab7824093d8f10d44330fe1e6493f756f252d145323dd17ab6b48733ff6c0a", size = 797037 }, - { url = "https://files.pythonhosted.org/packages/c3/2a/cd4675dd987e4a7505f0364a958bc41f3b84942de9efaad0ef9a2646681c/regex-2024.9.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8dee5b4810a89447151999428fe096977346cf2f29f4d5e29609d2e19e0199c9", size = 784106 }, - { url = "https://files.pythonhosted.org/packages/6f/75/3ea7ec29de0bbf42f21f812f48781d41e627d57a634f3f23947c9a46e303/regex-2024.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98eeee2f2e63edae2181c886d7911ce502e1292794f4c5ee71e60e23e8d26b5d", size = 782468 }, - { url = "https://files.pythonhosted.org/packages/d3/67/15519d69b52c252b270e679cb578e22e0c02b8dd4e361f2b04efcc7f2335/regex-2024.9.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:57fdd2e0b2694ce6fc2e5ccf189789c3e2962916fb38779d3e3521ff8fe7a822", size = 790324 }, - { url = "https://files.pythonhosted.org/packages/9c/71/eff77d3fe7ba08ab0672920059ec30d63fa7e41aa0fb61c562726e9bd721/regex-2024.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d552c78411f60b1fdaafd117a1fca2f02e562e309223b9d44b7de8be451ec5e0", size = 860214 }, - { url = "https://files.pythonhosted.org/packages/81/11/e1bdf84a72372e56f1ea4b833dd583b822a23138a616ace7ab57a0e11556/regex-2024.9.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a0b2b80321c2ed3fcf0385ec9e51a12253c50f146fddb2abbb10f033fe3d049a", size = 859420 }, - { url = "https://files.pythonhosted.org/packages/ea/75/9753e9dcebfa7c3645563ef5c8a58f3a47e799c872165f37c55737dadd3e/regex-2024.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a", size = 787333 }, - { url = "https://files.pythonhosted.org/packages/bc/4e/ba1cbca93141f7416624b3ae63573e785d4bc1834c8be44a8f0747919eca/regex-2024.9.11-cp312-cp312-win32.whl", hash = "sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776", size = 262058 }, - { url = "https://files.pythonhosted.org/packages/6e/16/efc5f194778bf43e5888209e5cec4b258005d37c613b67ae137df3b89c53/regex-2024.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009", size = 273526 }, - { url = "https://files.pythonhosted.org/packages/93/0a/d1c6b9af1ff1e36832fe38d74d5c5bab913f2bdcbbd6bc0e7f3ce8b2f577/regex-2024.9.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784", size = 483376 }, - { url = "https://files.pythonhosted.org/packages/a4/42/5910a050c105d7f750a72dcb49c30220c3ae4e2654e54aaaa0e9bc0584cb/regex-2024.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36", size = 288112 }, - { url = "https://files.pythonhosted.org/packages/8d/56/0c262aff0e9224fa7ffce47b5458d373f4d3e3ff84e99b5ff0cb15e0b5b2/regex-2024.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92", size = 284608 }, - { url = "https://files.pythonhosted.org/packages/b9/54/9fe8f9aec5007bbbbce28ba3d2e3eaca425f95387b7d1e84f0d137d25237/regex-2024.9.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86", size = 795337 }, - { url = "https://files.pythonhosted.org/packages/b2/e7/6b2f642c3cded271c4f16cc4daa7231be544d30fe2b168e0223724b49a61/regex-2024.9.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85", size = 835848 }, - { url = "https://files.pythonhosted.org/packages/cd/9e/187363bdf5d8c0e4662117b92aa32bf52f8f09620ae93abc7537d96d3311/regex-2024.9.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963", size = 823503 }, - { url = "https://files.pythonhosted.org/packages/f8/10/601303b8ee93589f879664b0cfd3127949ff32b17f9b6c490fb201106c4d/regex-2024.9.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6", size = 797049 }, - { url = "https://files.pythonhosted.org/packages/ef/1c/ea200f61ce9f341763f2717ab4daebe4422d83e9fd4ac5e33435fd3a148d/regex-2024.9.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802", size = 784144 }, - { url = "https://files.pythonhosted.org/packages/d8/5c/d2429be49ef3292def7688401d3deb11702c13dcaecdc71d2b407421275b/regex-2024.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29", size = 782483 }, - { url = "https://files.pythonhosted.org/packages/12/d9/cbc30f2ff7164f3b26a7760f87c54bf8b2faed286f60efd80350a51c5b99/regex-2024.9.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8", size = 790320 }, - { url = "https://files.pythonhosted.org/packages/19/1d/43ed03a236313639da5a45e61bc553c8d41e925bcf29b0f8ecff0c2c3f25/regex-2024.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84", size = 860435 }, - { url = "https://files.pythonhosted.org/packages/34/4f/5d04da61c7c56e785058a46349f7285ae3ebc0726c6ea7c5c70600a52233/regex-2024.9.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554", size = 859571 }, - { url = "https://files.pythonhosted.org/packages/12/7f/8398c8155a3c70703a8e91c29532558186558e1aea44144b382faa2a6f7a/regex-2024.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8", size = 787398 }, - { url = "https://files.pythonhosted.org/packages/58/3a/f5903977647a9a7e46d5535e9e96c194304aeeca7501240509bde2f9e17f/regex-2024.9.11-cp313-cp313-win32.whl", hash = "sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8", size = 262035 }, - { url = "https://files.pythonhosted.org/packages/ff/80/51ba3a4b7482f6011095b3a036e07374f64de180b7d870b704ed22509002/regex-2024.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f", size = 273510 }, +version = "2024.11.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/58/7e4d9493a66c88a7da6d205768119f51af0f684fe7be7bac8328e217a52c/regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638", size = 482669 }, + { url = "https://files.pythonhosted.org/packages/34/4c/8f8e631fcdc2ff978609eaeef1d6994bf2f028b59d9ac67640ed051f1218/regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7", size = 287684 }, + { url = "https://files.pythonhosted.org/packages/c5/1b/f0e4d13e6adf866ce9b069e191f303a30ab1277e037037a365c3aad5cc9c/regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20", size = 284589 }, + { url = "https://files.pythonhosted.org/packages/25/4d/ab21047f446693887f25510887e6820b93f791992994f6498b0318904d4a/regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114", size = 792121 }, + { url = "https://files.pythonhosted.org/packages/45/ee/c867e15cd894985cb32b731d89576c41a4642a57850c162490ea34b78c3b/regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3", size = 831275 }, + { url = "https://files.pythonhosted.org/packages/b3/12/b0f480726cf1c60f6536fa5e1c95275a77624f3ac8fdccf79e6727499e28/regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f", size = 818257 }, + { url = "https://files.pythonhosted.org/packages/bf/ce/0d0e61429f603bac433910d99ef1a02ce45a8967ffbe3cbee48599e62d88/regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0", size = 792727 }, + { url = "https://files.pythonhosted.org/packages/e4/c1/243c83c53d4a419c1556f43777ccb552bccdf79d08fda3980e4e77dd9137/regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55", size = 780667 }, + { url = "https://files.pythonhosted.org/packages/c5/f4/75eb0dd4ce4b37f04928987f1d22547ddaf6c4bae697623c1b05da67a8aa/regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89", size = 776963 }, + { url = "https://files.pythonhosted.org/packages/16/5d/95c568574e630e141a69ff8a254c2f188b4398e813c40d49228c9bbd9875/regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d", size = 784700 }, + { url = "https://files.pythonhosted.org/packages/8e/b5/f8495c7917f15cc6fee1e7f395e324ec3e00ab3c665a7dc9d27562fd5290/regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34", size = 848592 }, + { url = "https://files.pythonhosted.org/packages/1c/80/6dd7118e8cb212c3c60b191b932dc57db93fb2e36fb9e0e92f72a5909af9/regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d", size = 852929 }, + { url = "https://files.pythonhosted.org/packages/11/9b/5a05d2040297d2d254baf95eeeb6df83554e5e1df03bc1a6687fc4ba1f66/regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45", size = 781213 }, + { url = "https://files.pythonhosted.org/packages/26/b7/b14e2440156ab39e0177506c08c18accaf2b8932e39fb092074de733d868/regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9", size = 261734 }, + { url = "https://files.pythonhosted.org/packages/80/32/763a6cc01d21fb3819227a1cc3f60fd251c13c37c27a73b8ff4315433a8e/regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60", size = 274052 }, + { url = "https://files.pythonhosted.org/packages/ba/30/9a87ce8336b172cc232a0db89a3af97929d06c11ceaa19d97d84fa90a8f8/regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a", size = 483781 }, + { url = "https://files.pythonhosted.org/packages/01/e8/00008ad4ff4be8b1844786ba6636035f7ef926db5686e4c0f98093612add/regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9", size = 288455 }, + { url = "https://files.pythonhosted.org/packages/60/85/cebcc0aff603ea0a201667b203f13ba75d9fc8668fab917ac5b2de3967bc/regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2", size = 284759 }, + { url = "https://files.pythonhosted.org/packages/94/2b/701a4b0585cb05472a4da28ee28fdfe155f3638f5e1ec92306d924e5faf0/regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4", size = 794976 }, + { url = "https://files.pythonhosted.org/packages/4b/bf/fa87e563bf5fee75db8915f7352e1887b1249126a1be4813837f5dbec965/regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577", size = 833077 }, + { url = "https://files.pythonhosted.org/packages/a1/56/7295e6bad94b047f4d0834e4779491b81216583c00c288252ef625c01d23/regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3", size = 823160 }, + { url = "https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e", size = 796896 }, + { url = "https://files.pythonhosted.org/packages/24/56/0b3f1b66d592be6efec23a795b37732682520b47c53da5a32c33ed7d84e3/regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe", size = 783997 }, + { url = "https://files.pythonhosted.org/packages/f9/a1/eb378dada8b91c0e4c5f08ffb56f25fcae47bf52ad18f9b2f33b83e6d498/regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e", size = 781725 }, + { url = "https://files.pythonhosted.org/packages/83/f2/033e7dec0cfd6dda93390089864732a3409246ffe8b042e9554afa9bff4e/regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29", size = 789481 }, + { url = "https://files.pythonhosted.org/packages/83/23/15d4552ea28990a74e7696780c438aadd73a20318c47e527b47a4a5a596d/regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39", size = 852896 }, + { url = "https://files.pythonhosted.org/packages/e3/39/ed4416bc90deedbfdada2568b2cb0bc1fdb98efe11f5378d9892b2a88f8f/regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51", size = 860138 }, + { url = "https://files.pythonhosted.org/packages/93/2d/dd56bb76bd8e95bbce684326302f287455b56242a4f9c61f1bc76e28360e/regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad", size = 787692 }, + { url = "https://files.pythonhosted.org/packages/0b/55/31877a249ab7a5156758246b9c59539abbeba22461b7d8adc9e8475ff73e/regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54", size = 262135 }, + { url = "https://files.pythonhosted.org/packages/38/ec/ad2d7de49a600cdb8dd78434a1aeffe28b9d6fc42eb36afab4a27ad23384/regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b", size = 273567 }, + { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525 }, + { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324 }, + { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617 }, + { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023 }, + { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072 }, + { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130 }, + { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857 }, + { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006 }, + { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650 }, + { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545 }, + { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045 }, + { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182 }, + { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733 }, + { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122 }, + { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545 }, ] [[package]] @@ -1709,14 +1468,14 @@ wheels = [ [[package]] name = "tqdm" -version = "4.66.5" +version = "4.67.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "platform_system == 'Windows'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/58/83/6ba9844a41128c62e810fddddd72473201f3eacde02046066142a2d96cc5/tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad", size = 169504 } +sdist = { url = "https://files.pythonhosted.org/packages/e8/4f/0153c21dc5779a49a0598c445b1978126b1344bab9ee71e53e44877e14e0/tqdm-4.67.0.tar.gz", hash = "sha256:fe5a6f95e6fe0b9755e9469b77b9c3cf850048224ecaa8293d7d2d31f97d869a", size = 169739 } wheels = [ - { url = "https://files.pythonhosted.org/packages/48/5d/acf5905c36149bbaec41ccf7f2b68814647347b72075ac0b1fe3022fdc73/tqdm-4.66.5-py3-none-any.whl", hash = "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd", size = 78351 }, + { url = "https://files.pythonhosted.org/packages/2b/78/57043611a16c655c8350b4c01b8d6abfb38cc2acb475238b62c2146186d7/tqdm-4.67.0-py3-none-any.whl", hash = "sha256:0cd8af9d56911acab92182e88d763100d4788bdf421d251616040cc4d44863be", size = 78590 }, ] [[package]] diff --git a/libraries/python/skills/skill-library/uv.lock b/libraries/python/skills/skill-library/uv.lock index 04f4a194..e8482832 100644 --- a/libraries/python/skills/skill-library/uv.lock +++ b/libraries/python/skills/skill-library/uv.lock @@ -1350,55 +1350,55 @@ wheels = [ [[package]] name = "regex" -version = "2024.9.11" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f9/38/148df33b4dbca3bd069b963acab5e0fa1a9dbd6820f8c322d0dd6faeff96/regex-2024.9.11.tar.gz", hash = "sha256:6c188c307e8433bcb63dc1915022deb553b4203a70722fc542c363bf120a01fd", size = 399403 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/a1/d526b7b6095a0019aa360948c143aacfeb029919c898701ce7763bbe4c15/regex-2024.9.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2cce2449e5927a0bf084d346da6cd5eb016b2beca10d0013ab50e3c226ffc0df", size = 482483 }, - { url = "https://files.pythonhosted.org/packages/32/d9/bfdd153179867c275719e381e1e8e84a97bd186740456a0dcb3e7125c205/regex-2024.9.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b37fa423beefa44919e009745ccbf353d8c981516e807995b2bd11c2c77d268", size = 287442 }, - { url = "https://files.pythonhosted.org/packages/33/c4/60f3370735135e3a8d673ddcdb2507a8560d0e759e1398d366e43d000253/regex-2024.9.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:64ce2799bd75039b480cc0360907c4fb2f50022f030bf9e7a8705b636e408fad", size = 284561 }, - { url = "https://files.pythonhosted.org/packages/b1/51/91a5ebdff17f9ec4973cb0aa9d37635efec1c6868654bbc25d1543aca4ec/regex-2024.9.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4cc92bb6db56ab0c1cbd17294e14f5e9224f0cc6521167ef388332604e92679", size = 791779 }, - { url = "https://files.pythonhosted.org/packages/07/4a/022c5e6f0891a90cd7eb3d664d6c58ce2aba48bff107b00013f3d6167069/regex-2024.9.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d05ac6fa06959c4172eccd99a222e1fbf17b5670c4d596cb1e5cde99600674c4", size = 832605 }, - { url = "https://files.pythonhosted.org/packages/ac/1c/3793990c8c83ca04e018151ddda83b83ecc41d89964f0f17749f027fc44d/regex-2024.9.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040562757795eeea356394a7fb13076ad4f99d3c62ab0f8bdfb21f99a1f85664", size = 818556 }, - { url = "https://files.pythonhosted.org/packages/e9/5c/8b385afbfacb853730682c57be56225f9fe275c5bf02ac1fc88edbff316d/regex-2024.9.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6113c008a7780792efc80f9dfe10ba0cd043cbf8dc9a76ef757850f51b4edc50", size = 792808 }, - { url = "https://files.pythonhosted.org/packages/9b/8b/a4723a838b53c771e9240951adde6af58c829fb6a6a28f554e8131f53839/regex-2024.9.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e5fb5f77c8745a60105403a774fe2c1759b71d3e7b4ca237a5e67ad066c7199", size = 781115 }, - { url = "https://files.pythonhosted.org/packages/83/5f/031a04b6017033d65b261259c09043c06f4ef2d4eac841d0649d76d69541/regex-2024.9.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:54d9ff35d4515debf14bc27f1e3b38bfc453eff3220f5bce159642fa762fe5d4", size = 778155 }, - { url = "https://files.pythonhosted.org/packages/fd/cd/4660756070b03ce4a66663a43f6c6e7ebc2266cc6b4c586c167917185eb4/regex-2024.9.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:df5cbb1fbc74a8305b6065d4ade43b993be03dbe0f8b30032cced0d7740994bd", size = 784614 }, - { url = "https://files.pythonhosted.org/packages/93/8d/65b9bea7df120a7be8337c415b6d256ba786cbc9107cebba3bf8ff09da99/regex-2024.9.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7fb89ee5d106e4a7a51bce305ac4efb981536301895f7bdcf93ec92ae0d91c7f", size = 853744 }, - { url = "https://files.pythonhosted.org/packages/96/a7/fba1eae75eb53a704475baf11bd44b3e6ccb95b316955027eb7748f24ef8/regex-2024.9.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a738b937d512b30bf75995c0159c0ddf9eec0775c9d72ac0202076c72f24aa96", size = 855890 }, - { url = "https://files.pythonhosted.org/packages/45/14/d864b2db80a1a3358534392373e8a281d95b28c29c87d8548aed58813910/regex-2024.9.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e28f9faeb14b6f23ac55bfbbfd3643f5c7c18ede093977f1df249f73fd22c7b1", size = 781887 }, - { url = "https://files.pythonhosted.org/packages/4d/a9/bfb29b3de3eb11dc9b412603437023b8e6c02fb4e11311863d9bf62c403a/regex-2024.9.11-cp311-cp311-win32.whl", hash = "sha256:18e707ce6c92d7282dfce370cd205098384b8ee21544e7cb29b8aab955b66fa9", size = 261644 }, - { url = "https://files.pythonhosted.org/packages/c7/ab/1ad2511cf6a208fde57fafe49829cab8ca018128ab0d0b48973d8218634a/regex-2024.9.11-cp311-cp311-win_amd64.whl", hash = "sha256:313ea15e5ff2a8cbbad96ccef6be638393041b0a7863183c2d31e0c6116688cf", size = 274033 }, - { url = "https://files.pythonhosted.org/packages/6e/92/407531450762bed778eedbde04407f68cbd75d13cee96c6f8d6903d9c6c1/regex-2024.9.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b0d0a6c64fcc4ef9c69bd5b3b3626cc3776520a1637d8abaa62b9edc147a58f7", size = 483590 }, - { url = "https://files.pythonhosted.org/packages/8e/a2/048acbc5ae1f615adc6cba36cc45734e679b5f1e4e58c3c77f0ed611d4e2/regex-2024.9.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:49b0e06786ea663f933f3710a51e9385ce0cba0ea56b67107fd841a55d56a231", size = 288175 }, - { url = "https://files.pythonhosted.org/packages/8a/ea/909d8620329ab710dfaf7b4adee41242ab7c9b95ea8d838e9bfe76244259/regex-2024.9.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5b513b6997a0b2f10e4fd3a1313568e373926e8c252bd76c960f96fd039cd28d", size = 284749 }, - { url = "https://files.pythonhosted.org/packages/ca/fa/521eb683b916389b4975337873e66954e0f6d8f91bd5774164a57b503185/regex-2024.9.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee439691d8c23e76f9802c42a95cfeebf9d47cf4ffd06f18489122dbb0a7ad64", size = 795181 }, - { url = "https://files.pythonhosted.org/packages/28/db/63047feddc3280cc242f9c74f7aeddc6ee662b1835f00046f57d5630c827/regex-2024.9.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8f877c89719d759e52783f7fe6e1c67121076b87b40542966c02de5503ace42", size = 835842 }, - { url = "https://files.pythonhosted.org/packages/e3/94/86adc259ff8ec26edf35fcca7e334566c1805c7493b192cb09679f9c3dee/regex-2024.9.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23b30c62d0f16827f2ae9f2bb87619bc4fba2044911e2e6c2eb1af0161cdb766", size = 823533 }, - { url = "https://files.pythonhosted.org/packages/29/52/84662b6636061277cb857f658518aa7db6672bc6d1a3f503ccd5aefc581e/regex-2024.9.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ab7824093d8f10d44330fe1e6493f756f252d145323dd17ab6b48733ff6c0a", size = 797037 }, - { url = "https://files.pythonhosted.org/packages/c3/2a/cd4675dd987e4a7505f0364a958bc41f3b84942de9efaad0ef9a2646681c/regex-2024.9.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8dee5b4810a89447151999428fe096977346cf2f29f4d5e29609d2e19e0199c9", size = 784106 }, - { url = "https://files.pythonhosted.org/packages/6f/75/3ea7ec29de0bbf42f21f812f48781d41e627d57a634f3f23947c9a46e303/regex-2024.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98eeee2f2e63edae2181c886d7911ce502e1292794f4c5ee71e60e23e8d26b5d", size = 782468 }, - { url = "https://files.pythonhosted.org/packages/d3/67/15519d69b52c252b270e679cb578e22e0c02b8dd4e361f2b04efcc7f2335/regex-2024.9.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:57fdd2e0b2694ce6fc2e5ccf189789c3e2962916fb38779d3e3521ff8fe7a822", size = 790324 }, - { url = "https://files.pythonhosted.org/packages/9c/71/eff77d3fe7ba08ab0672920059ec30d63fa7e41aa0fb61c562726e9bd721/regex-2024.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d552c78411f60b1fdaafd117a1fca2f02e562e309223b9d44b7de8be451ec5e0", size = 860214 }, - { url = "https://files.pythonhosted.org/packages/81/11/e1bdf84a72372e56f1ea4b833dd583b822a23138a616ace7ab57a0e11556/regex-2024.9.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a0b2b80321c2ed3fcf0385ec9e51a12253c50f146fddb2abbb10f033fe3d049a", size = 859420 }, - { url = "https://files.pythonhosted.org/packages/ea/75/9753e9dcebfa7c3645563ef5c8a58f3a47e799c872165f37c55737dadd3e/regex-2024.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a", size = 787333 }, - { url = "https://files.pythonhosted.org/packages/bc/4e/ba1cbca93141f7416624b3ae63573e785d4bc1834c8be44a8f0747919eca/regex-2024.9.11-cp312-cp312-win32.whl", hash = "sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776", size = 262058 }, - { url = "https://files.pythonhosted.org/packages/6e/16/efc5f194778bf43e5888209e5cec4b258005d37c613b67ae137df3b89c53/regex-2024.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009", size = 273526 }, - { url = "https://files.pythonhosted.org/packages/93/0a/d1c6b9af1ff1e36832fe38d74d5c5bab913f2bdcbbd6bc0e7f3ce8b2f577/regex-2024.9.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784", size = 483376 }, - { url = "https://files.pythonhosted.org/packages/a4/42/5910a050c105d7f750a72dcb49c30220c3ae4e2654e54aaaa0e9bc0584cb/regex-2024.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36", size = 288112 }, - { url = "https://files.pythonhosted.org/packages/8d/56/0c262aff0e9224fa7ffce47b5458d373f4d3e3ff84e99b5ff0cb15e0b5b2/regex-2024.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92", size = 284608 }, - { url = "https://files.pythonhosted.org/packages/b9/54/9fe8f9aec5007bbbbce28ba3d2e3eaca425f95387b7d1e84f0d137d25237/regex-2024.9.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86", size = 795337 }, - { url = "https://files.pythonhosted.org/packages/b2/e7/6b2f642c3cded271c4f16cc4daa7231be544d30fe2b168e0223724b49a61/regex-2024.9.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85", size = 835848 }, - { url = "https://files.pythonhosted.org/packages/cd/9e/187363bdf5d8c0e4662117b92aa32bf52f8f09620ae93abc7537d96d3311/regex-2024.9.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963", size = 823503 }, - { url = "https://files.pythonhosted.org/packages/f8/10/601303b8ee93589f879664b0cfd3127949ff32b17f9b6c490fb201106c4d/regex-2024.9.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6", size = 797049 }, - { url = "https://files.pythonhosted.org/packages/ef/1c/ea200f61ce9f341763f2717ab4daebe4422d83e9fd4ac5e33435fd3a148d/regex-2024.9.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802", size = 784144 }, - { url = "https://files.pythonhosted.org/packages/d8/5c/d2429be49ef3292def7688401d3deb11702c13dcaecdc71d2b407421275b/regex-2024.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29", size = 782483 }, - { url = "https://files.pythonhosted.org/packages/12/d9/cbc30f2ff7164f3b26a7760f87c54bf8b2faed286f60efd80350a51c5b99/regex-2024.9.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8", size = 790320 }, - { url = "https://files.pythonhosted.org/packages/19/1d/43ed03a236313639da5a45e61bc553c8d41e925bcf29b0f8ecff0c2c3f25/regex-2024.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84", size = 860435 }, - { url = "https://files.pythonhosted.org/packages/34/4f/5d04da61c7c56e785058a46349f7285ae3ebc0726c6ea7c5c70600a52233/regex-2024.9.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554", size = 859571 }, - { url = "https://files.pythonhosted.org/packages/12/7f/8398c8155a3c70703a8e91c29532558186558e1aea44144b382faa2a6f7a/regex-2024.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8", size = 787398 }, - { url = "https://files.pythonhosted.org/packages/58/3a/f5903977647a9a7e46d5535e9e96c194304aeeca7501240509bde2f9e17f/regex-2024.9.11-cp313-cp313-win32.whl", hash = "sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8", size = 262035 }, - { url = "https://files.pythonhosted.org/packages/ff/80/51ba3a4b7482f6011095b3a036e07374f64de180b7d870b704ed22509002/regex-2024.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f", size = 273510 }, +version = "2024.11.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/58/7e4d9493a66c88a7da6d205768119f51af0f684fe7be7bac8328e217a52c/regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638", size = 482669 }, + { url = "https://files.pythonhosted.org/packages/34/4c/8f8e631fcdc2ff978609eaeef1d6994bf2f028b59d9ac67640ed051f1218/regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7", size = 287684 }, + { url = "https://files.pythonhosted.org/packages/c5/1b/f0e4d13e6adf866ce9b069e191f303a30ab1277e037037a365c3aad5cc9c/regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20", size = 284589 }, + { url = "https://files.pythonhosted.org/packages/25/4d/ab21047f446693887f25510887e6820b93f791992994f6498b0318904d4a/regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114", size = 792121 }, + { url = "https://files.pythonhosted.org/packages/45/ee/c867e15cd894985cb32b731d89576c41a4642a57850c162490ea34b78c3b/regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3", size = 831275 }, + { url = "https://files.pythonhosted.org/packages/b3/12/b0f480726cf1c60f6536fa5e1c95275a77624f3ac8fdccf79e6727499e28/regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f", size = 818257 }, + { url = "https://files.pythonhosted.org/packages/bf/ce/0d0e61429f603bac433910d99ef1a02ce45a8967ffbe3cbee48599e62d88/regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0", size = 792727 }, + { url = "https://files.pythonhosted.org/packages/e4/c1/243c83c53d4a419c1556f43777ccb552bccdf79d08fda3980e4e77dd9137/regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55", size = 780667 }, + { url = "https://files.pythonhosted.org/packages/c5/f4/75eb0dd4ce4b37f04928987f1d22547ddaf6c4bae697623c1b05da67a8aa/regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89", size = 776963 }, + { url = "https://files.pythonhosted.org/packages/16/5d/95c568574e630e141a69ff8a254c2f188b4398e813c40d49228c9bbd9875/regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d", size = 784700 }, + { url = "https://files.pythonhosted.org/packages/8e/b5/f8495c7917f15cc6fee1e7f395e324ec3e00ab3c665a7dc9d27562fd5290/regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34", size = 848592 }, + { url = "https://files.pythonhosted.org/packages/1c/80/6dd7118e8cb212c3c60b191b932dc57db93fb2e36fb9e0e92f72a5909af9/regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d", size = 852929 }, + { url = "https://files.pythonhosted.org/packages/11/9b/5a05d2040297d2d254baf95eeeb6df83554e5e1df03bc1a6687fc4ba1f66/regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45", size = 781213 }, + { url = "https://files.pythonhosted.org/packages/26/b7/b14e2440156ab39e0177506c08c18accaf2b8932e39fb092074de733d868/regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9", size = 261734 }, + { url = "https://files.pythonhosted.org/packages/80/32/763a6cc01d21fb3819227a1cc3f60fd251c13c37c27a73b8ff4315433a8e/regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60", size = 274052 }, + { url = "https://files.pythonhosted.org/packages/ba/30/9a87ce8336b172cc232a0db89a3af97929d06c11ceaa19d97d84fa90a8f8/regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a", size = 483781 }, + { url = "https://files.pythonhosted.org/packages/01/e8/00008ad4ff4be8b1844786ba6636035f7ef926db5686e4c0f98093612add/regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9", size = 288455 }, + { url = "https://files.pythonhosted.org/packages/60/85/cebcc0aff603ea0a201667b203f13ba75d9fc8668fab917ac5b2de3967bc/regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2", size = 284759 }, + { url = "https://files.pythonhosted.org/packages/94/2b/701a4b0585cb05472a4da28ee28fdfe155f3638f5e1ec92306d924e5faf0/regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4", size = 794976 }, + { url = "https://files.pythonhosted.org/packages/4b/bf/fa87e563bf5fee75db8915f7352e1887b1249126a1be4813837f5dbec965/regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577", size = 833077 }, + { url = "https://files.pythonhosted.org/packages/a1/56/7295e6bad94b047f4d0834e4779491b81216583c00c288252ef625c01d23/regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3", size = 823160 }, + { url = "https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e", size = 796896 }, + { url = "https://files.pythonhosted.org/packages/24/56/0b3f1b66d592be6efec23a795b37732682520b47c53da5a32c33ed7d84e3/regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe", size = 783997 }, + { url = "https://files.pythonhosted.org/packages/f9/a1/eb378dada8b91c0e4c5f08ffb56f25fcae47bf52ad18f9b2f33b83e6d498/regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e", size = 781725 }, + { url = "https://files.pythonhosted.org/packages/83/f2/033e7dec0cfd6dda93390089864732a3409246ffe8b042e9554afa9bff4e/regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29", size = 789481 }, + { url = "https://files.pythonhosted.org/packages/83/23/15d4552ea28990a74e7696780c438aadd73a20318c47e527b47a4a5a596d/regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39", size = 852896 }, + { url = "https://files.pythonhosted.org/packages/e3/39/ed4416bc90deedbfdada2568b2cb0bc1fdb98efe11f5378d9892b2a88f8f/regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51", size = 860138 }, + { url = "https://files.pythonhosted.org/packages/93/2d/dd56bb76bd8e95bbce684326302f287455b56242a4f9c61f1bc76e28360e/regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad", size = 787692 }, + { url = "https://files.pythonhosted.org/packages/0b/55/31877a249ab7a5156758246b9c59539abbeba22461b7d8adc9e8475ff73e/regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54", size = 262135 }, + { url = "https://files.pythonhosted.org/packages/38/ec/ad2d7de49a600cdb8dd78434a1aeffe28b9d6fc42eb36afab4a27ad23384/regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b", size = 273567 }, + { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525 }, + { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324 }, + { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617 }, + { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023 }, + { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072 }, + { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130 }, + { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857 }, + { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006 }, + { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650 }, + { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545 }, + { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045 }, + { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182 }, + { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733 }, + { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122 }, + { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545 }, ] [[package]] diff --git a/libraries/python/skills/skills/document-skill/uv.lock b/libraries/python/skills/skills/document-skill/uv.lock index 54dbb947..2a8ddd7d 100644 --- a/libraries/python/skills/skills/document-skill/uv.lock +++ b/libraries/python/skills/skills/document-skill/uv.lock @@ -320,7 +320,6 @@ dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, - { name = "python-liquid" }, { name = "requests" }, { name = "tiktoken" }, ] @@ -336,7 +335,6 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "python-liquid", specifier = ">=1.12.1" }, { name = "requests", specifier = ">=2.32.0" }, { name = "tiktoken", specifier = ">=0.7.0" }, ] diff --git a/libraries/python/skills/skills/form-filler-skill/uv.lock b/libraries/python/skills/skills/form-filler-skill/uv.lock index f14275b7..7b5e6c93 100644 --- a/libraries/python/skills/skills/form-filler-skill/uv.lock +++ b/libraries/python/skills/skills/form-filler-skill/uv.lock @@ -5,15 +5,6 @@ resolution-markers = [ "python_full_version >= '3.13'", ] -[[package]] -name = "aiofiles" -version = "24.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/0b/03/a88171e277e8caa88a4c77808c20ebb04ba74cc4681bf1e9416c862de237/aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c", size = 30247 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5", size = 15896 }, -] - [[package]] name = "aiohappyeyeballs" version = "2.4.3" @@ -136,7 +127,6 @@ name = "assistant-drive" version = "0.1.0" source = { editable = "../../../assistant-drive" } dependencies = [ - { name = "aiofiles" }, { name = "context" }, { name = "pydantic" }, { name = "pydantic-settings" }, @@ -144,7 +134,6 @@ dependencies = [ [package.metadata] requires-dist = [ - { name = "aiofiles", specifier = ">=24.1.0" }, { name = "context", editable = "../../../context" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.5.2" }, @@ -327,10 +316,10 @@ dependencies = [ { name = "events" }, { name = "function-registry" }, { name = "openai" }, + { name = "openai-client" }, { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, - { name = "python-liquid" }, { name = "requests" }, { name = "tiktoken" }, ] @@ -342,10 +331,10 @@ requires-dist = [ { name = "events", editable = "../../../events" }, { name = "function-registry", editable = "../../../function-registry" }, { name = "openai", specifier = ">=1.16.1" }, + { name = "openai-client", editable = "../../../openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "python-liquid", specifier = ">=1.12.1" }, { name = "requests", specifier = ">=2.32.0" }, { name = "tiktoken", specifier = ">=0.7.0" }, ] @@ -935,8 +924,10 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, + { name = "function-registry" }, { name = "openai" }, { name = "pillow" }, + { name = "python-liquid" }, { name = "semantic-workbench-assistant" }, { name = "tiktoken" }, ] @@ -946,8 +937,10 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "function-registry", editable = "../../../function-registry" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, + { name = "python-liquid", specifier = ">=1.12.1" }, { name = "semantic-workbench-assistant", editable = "../../../semantic-workbench-assistant" }, { name = "tiktoken", specifier = ">=0.7.0" }, ] diff --git a/libraries/python/skills/skills/posix-skill/uv.lock b/libraries/python/skills/skills/posix-skill/uv.lock index 3f0e051e..ae772499 100644 --- a/libraries/python/skills/skills/posix-skill/uv.lock +++ b/libraries/python/skills/skills/posix-skill/uv.lock @@ -320,7 +320,6 @@ dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, - { name = "python-liquid" }, { name = "requests" }, { name = "tiktoken" }, ] @@ -336,7 +335,6 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "python-liquid", specifier = ">=1.12.1" }, { name = "requests", specifier = ">=2.32.0" }, { name = "tiktoken", specifier = ">=0.7.0" }, ] diff --git a/libraries/python/skills/skills/prospector-skill/uv.lock b/libraries/python/skills/skills/prospector-skill/uv.lock index 3741b1fb..fb7c57c0 100644 --- a/libraries/python/skills/skills/prospector-skill/uv.lock +++ b/libraries/python/skills/skills/prospector-skill/uv.lock @@ -320,7 +320,6 @@ dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, - { name = "python-liquid" }, { name = "requests" }, { name = "tiktoken" }, ] @@ -336,7 +335,6 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "python-liquid", specifier = ">=1.12.1" }, { name = "requests", specifier = ">=2.32.0" }, { name = "tiktoken", specifier = ">=0.7.0" }, ] diff --git a/libraries/python/skills/skills/skill-template/uv.lock b/libraries/python/skills/skills/skill-template/uv.lock index a5787da7..bf6c6414 100644 --- a/libraries/python/skills/skills/skill-template/uv.lock +++ b/libraries/python/skills/skills/skill-template/uv.lock @@ -320,7 +320,6 @@ dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, - { name = "python-liquid" }, { name = "requests" }, { name = "tiktoken" }, ] @@ -336,7 +335,6 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "python-liquid", specifier = ">=1.12.1" }, { name = "requests", specifier = ">=2.32.0" }, { name = "tiktoken", specifier = ">=0.7.0" }, ] From 6a09a5873a7e347717111b47a6ed273924242b06 Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Wed, 6 Nov 2024 00:01:17 +0000 Subject: [PATCH 09/14] Fix assistant import to fix a test. --- .../skills/skill-library/skill_library/assistant.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/python/skills/skill-library/skill_library/assistant.py b/libraries/python/skills/skill-library/skill_library/assistant.py index c62aa0bb..a6b5cb1b 100644 --- a/libraries/python/skills/skill-library/skill_library/assistant.py +++ b/libraries/python/skills/skill-library/skill_library/assistant.py @@ -8,9 +8,11 @@ TEXT_RESPONSE_FORMAT, ChatDriver, ChatDriverConfig, - ResponseFormat, ) from events import BaseEvent, EventProtocol +from openai.types.chat.completion_create_params import ( + ResponseFormat, +) from .run_context import RunContext from .skill import Skill @@ -219,9 +221,7 @@ def list_routines(self, context: RunContext) -> list[str]: """Lists all the routines available in the assistant.""" return self.assistant.list_routines() - async def run_routine( - self, context: RunContext, name: str, vars: dict[str, Any] | None = None - ) -> Any: + async def run_routine(self, context: RunContext, name: str, vars: dict[str, Any] | None = None) -> Any: """ Run an assistant routine. """ From 10bc18d746306810e19ebc9e054d138ab361c745 Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Tue, 12 Nov 2024 00:34:29 +0000 Subject: [PATCH 10/14] Pulls context out of skills and chat drivers and openai helpers. --- .../assistant/assistant_registry.py | 23 +- .../assistant/skill_assistant.py | 47 +- .../chat-driver/chat_driver/chat_driver.py | 59 +- .../local_message_history_provider.py | 5 +- .../openai-client/openai_client/errors.py | 2 +- .../openai-client/openai_client/messages.py | 6 +- .../openai-client/openai_client/tools.py | 453 +++- .../notebooks/notebooks/chat_driver.ipynb | 2371 ++++++++--------- .../skill-library/skill_library/__init__.py | 7 +- .../skill-library/skill_library/actions.py | 232 ++ .../skill-library/skill_library/assistant.py | 38 +- .../skill_library/run_context.py | 4 +- .../skill-library/skill_library/skill.py | 39 +- .../chat_drivers/draft_content.py | 9 +- .../chat_drivers/draft_outline.py | 9 +- .../get_user_feedback_for_outline_decision.py | 9 +- .../get_user_feedback_for_page_decision.py | 9 +- .../document_skill/document_skill.py | 54 +- .../form_filler_skill/artifact.py | 59 +- .../chat_drivers/final_update.py | 4 +- .../chat_drivers/fix_agenda_error.py | 4 +- .../chat_drivers/fix_artifact_error.py | 7 +- .../chat_drivers/unneeded/choose_action.py | 36 +- .../unneeded/execute_reasoning.py | 4 +- .../chat_drivers/update_artifact.py | 32 +- .../form_filler_skill/form_filler_skill.py | 3 + .../chat_drivers/gc_final_update.py | 4 +- .../chat_drivers/gc_fix_agenda_error.py | 8 +- .../chat_drivers/gc_update_agenda.py | 35 +- .../chat_drivers/gc_update_artifact.py | 4 +- .../guided_conversation_skill.py | 26 +- .../posix-skill/posix_skill/posix_skill.py | 22 +- .../prospector_skill/skill.py | 3 - .../skills/skill-template/your_skill/skill.py | 3 - semantic-workbench.code-workspace | 10 +- 35 files changed, 2044 insertions(+), 1596 deletions(-) create mode 100644 libraries/python/skills/skill-library/skill_library/actions.py diff --git a/assistants/skill-assistant/assistant/assistant_registry.py b/assistants/skill-assistant/assistant/assistant_registry.py index 5285da1f..a4503b54 100644 --- a/assistants/skill-assistant/assistant/assistant_registry.py +++ b/assistants/skill-assistant/assistant/assistant_registry.py @@ -26,7 +26,7 @@ def __init__(self) -> None: async def get_or_create_assistant( self, - session_id: str, + assistant_id: str, event_mapper: SkillEventMapperProtocol, chat_driver_config: ChatDriverConfig, skills: List[Skill] = [], @@ -34,24 +34,22 @@ async def get_or_create_assistant( """ Get or create an assistant for the given conversation context. """ - assistant = self.get_assistant(session_id) + assistant = self.get_assistant(assistant_id) if not assistant: - assistant = await self.register_assistant( - session_id, event_mapper, chat_driver_config, skills - ) + assistant = await self.register_assistant(assistant_id, event_mapper, chat_driver_config, skills) return assistant def get_assistant( self, - session_id: str, + assistant_id: str, ) -> Assistant | None: - if session_id in self.assistants: - return self.assistants[session_id] + if assistant_id in self.assistants: + return self.assistants[assistant_id] return None async def register_assistant( self, - session_id: str, + assistant_id: str, event_mapper: SkillEventMapperProtocol, chat_driver_config: ChatDriverConfig, skills: List[Skill] = [], @@ -65,9 +63,10 @@ async def register_assistant( # Create the assistant. assistant = Assistant( name="Assistant", + assistant_id=assistant_id, + drive_root=Path(".data") / assistant_id / "assistant", + metadrive_drive_root=Path(".data") / assistant_id / ".assistant", chat_driver_config=chat_driver_config, - session_id=session_id, - metadrive_root=Path(".data") / session_id / ".assistant", ) assistant.register_skills(skills) @@ -82,7 +81,7 @@ async def subscribe() -> None: await assistant.wait() # Register the assistant - self.assistants[session_id] = assistant + self.assistants[assistant_id] = assistant # Start an event consumer task and save a reference. task = asyncio.create_task(subscribe()) diff --git a/assistants/skill-assistant/assistant/skill_assistant.py b/assistants/skill-assistant/assistant/skill_assistant.py index 777a6998..6a36376d 100644 --- a/assistants/skill-assistant/assistant/skill_assistant.py +++ b/assistants/skill-assistant/assistant/skill_assistant.py @@ -13,7 +13,8 @@ import openai_client from chat_driver import ChatDriverConfig from content_safety.evaluators import CombinedContentSafetyEvaluator -from form_filler_skill import FormFillerSkill + +# from form_filler_skill import FormFillerSkill from posix_skill import PosixSkill from semantic_workbench_api_model.workbench_model import ( ConversationEvent, @@ -41,20 +42,20 @@ # define the service ID, name, and description # -# the service id to be registered in the workbench to identify the assistant +# The service id to be registered in the workbench to identify the assistant. service_id = "skill-assistant.made-exploration" -# the name of the assistant service, as it will appear in the workbench UI + +# The name of the assistant service, as it will appear in the workbench UI. service_name = "Skill Assistant" -# a description of the assistant service, as it will appear in the workbench UI + +# A description of the assistant service, as it will appear in the workbench UI. service_description = "A skills-based assistant using the Semantic Workbench Assistant SDK." -# -# create the configuration provider, using the extended configuration model -# +# Create the configuration provider, using the extended configuration model. assistant_config = BaseModelAssistantConfig(AssistantConfigModel) -# define the content safety evaluator factory +# Create the content safety interceptor. async def content_evaluator_factory(context: ConversationContext) -> ContentSafetyEvaluator: config = await assistant_config.get(context.assistant) return CombinedContentSafetyEvaluator(config.content_safety_config) @@ -78,16 +79,20 @@ async def content_evaluator_factory(context: ConversationContext) -> ContentSafe app = assistant.fastapi_app() -# The AssistantApp class provides a set of decorators for adding event handlers to respond to conversation -# events. In VS Code, typing "@assistant." (or the name of your AssistantApp instance) will show available -# events and methods. +# The AssistantApp class provides a set of decorators for adding event handlers +# to respond to conversation events. In VS Code, typing "@assistant." (or the +# name of your AssistantApp instance) will show available events and methods. # -# See the semantic-workbench-assistant AssistantApp class for more information on available events and methods. -# Examples: -# - @assistant.events.conversation.on_created (event triggered when the assistant is added to a conversation) -# - @assistant.events.conversation.participant.on_created (event triggered when a participant is added) -# - @assistant.events.conversation.message.on_created (event triggered when a new message of any type is created) -# - @assistant.events.conversation.message.chat.on_created (event triggered when a new chat message is created) +# See the semantic-workbench-assistant AssistantApp class for more information +# on available events and methods. Examples: +# - @assistant.events.conversation.on_created (event triggered when the +# assistant is added to a conversation) +# - @assistant.events.conversation.participant.on_created (event triggered when +# a participant is added) +# - @assistant.events.conversation.message.on_created (event triggered when a +# new message of any type is created) +# - @assistant.events.conversation.message.chat.on_created (event triggered when +# a new chat message is created) assistant_registry = AssistantRegistry() @@ -183,12 +188,12 @@ async def respond_to_conversation( [ PosixSkill( sandbox_dir=Path(".data") / conversation_context.id, - mount_dir="/mnt/data", - chat_driver_config=chat_driver_config, - ), - FormFillerSkill( chat_driver_config=chat_driver_config, + mount_dir="/mnt/data", ), + # FormFillerSkill( + # chat_driver_config=chat_driver_config, + # ), ], ) diff --git a/libraries/python/chat-driver/chat_driver/chat_driver.py b/libraries/python/chat-driver/chat_driver/chat_driver.py index 9da1016a..bf93803c 100644 --- a/libraries/python/chat-driver/chat_driver/chat_driver.py +++ b/libraries/python/chat-driver/chat_driver/chat_driver.py @@ -1,9 +1,7 @@ -from dataclasses import dataclass, field +from dataclasses import dataclass from typing import Any, Callable, Union -from context import Context, ContextProtocol from events import BaseEvent, ErrorEvent, MessageEvent -from function_registry.function_registry import FunctionRegistry from openai import AsyncOpenAI from openai.types.chat import ( ChatCompletionMessageParam, @@ -14,13 +12,10 @@ from openai_client.completion import TEXT_RESPONSE_FORMAT, message_content_from_completion from openai_client.errors import CompletionError from openai_client.messages import MessageFormatter, format_with_dict -from openai_client.tools import complete_with_tool_calls, function_list_to_tools, function_registry_to_tools +from openai_client.tools import ToolFunction, ToolFunctions, complete_with_tool_calls, function_list_to_tool_choice from pydantic import BaseModel -from .local_message_history_provider import ( - LocalMessageHistoryProvider, - LocalMessageHistoryProviderConfig, -) +from .in_memory_message_history_provider import InMemoryMessageHistoryProvider from .message_history_provider import MessageHistoryProviderProtocol @@ -30,10 +25,9 @@ class ChatDriverConfig: model: str instructions: str | list[str] = "You are a helpful assistant." instruction_formatter: MessageFormatter | None = None - context: ContextProtocol | None = None message_provider: MessageHistoryProviderProtocol | None = None - commands: list[Callable] = field(default_factory=list) - functions: list[Callable] = field(default_factory=list) + commands: list[Callable] | None = None + functions: list[Callable] | None = None class ChatDriver: @@ -56,17 +50,11 @@ class ChatDriver: """ def __init__(self, config: ChatDriverConfig) -> None: - # A context object holds information about the current session, such as - # the session ID, the user ID, and the conversation ID. It also provides - # a method to emit events. If you do not supply one, one will be created - # for you with a random session ID. - self.context: ContextProtocol = config.context or Context() - # Set up a default message provider. This provider stores messages in a # local file. You can replace this with your own message provider that # implements the MessageHistoryProviderProtocol. - self.message_provider: MessageHistoryProviderProtocol = config.message_provider or LocalMessageHistoryProvider( - LocalMessageHistoryProviderConfig(context=self.context) + self.message_provider: MessageHistoryProviderProtocol = ( + config.message_provider or InMemoryMessageHistoryProvider() ) self.instructions: list[str] = ( @@ -83,15 +71,17 @@ def __init__(self, config: ChatDriverConfig) -> None: # call to a function, the function will be executed, the result passed # back to the model, and the model will continue generating the # response. - self.function_registry = FunctionRegistry(self.context, config.functions) - self.functions = self.function_registry.functions + self.function_list = ToolFunctions(functions=[ToolFunction(function) for function in (config.functions or [])]) + self.functions = self.function_list.functions # Commands are functions that can be called by the user by typing a # command in the chat. When a command is received, the chat driver will # execute the corresponding function and return the result to the user # directly. - self.command_registry = FunctionRegistry(self.context, config.commands) - self.commands = self.command_registry.functions + self.command_list = ToolFunctions( + functions=[ToolFunction(function) for function in (config.commands or [])], with_help=True + ) + self.commands = self.command_list.functions def _formatted_instructions(self, vars: dict[str, Any] | None) -> list[ChatCompletionSystemMessageParam]: return ChatDriver.format_instructions(self.instructions, vars, self.instruction_formatter) @@ -101,18 +91,20 @@ async def add_message(self, message: ChatCompletionMessageParam) -> None: # Commands are available to be run by the user message. def register_command(self, function: Callable) -> None: - self.command_registry.register_function(function) + self.command_list.add_function(function) def register_commands(self, functions: list[Callable]) -> None: - self.command_registry.register_functions(functions) + for function in functions: + self.register_command(function) # Functions are available to be called by the model during response # generation. def register_function(self, function: Callable) -> None: - self.function_registry.register_function(function) + self.function_list.add_function(function) def register_functions(self, functions: list[Callable]) -> None: - self.function_registry.register_functions(functions) + for function in functions: + self.register_function # Sometimes we want to register a function to be used by both the user and # the model. @@ -125,10 +117,10 @@ def register_functions_and_commands(self, functions: list[Callable]) -> None: self.register_functions(functions) def get_functions(self) -> list[Callable]: - return [function.fn for function in self.function_registry.get_functions()] + return [function.fn for function in self.function_list.get_functions()] def get_commands(self) -> list[Callable]: - commands = [function.fn for function in self.command_registry.get_functions()] + commands = [function.fn for function in self.command_list.get_functions()] return commands async def respond( @@ -158,7 +150,7 @@ async def respond( if message and message.startswith("/"): command_string = message[1:] try: - results = await self.command_registry.execute_function_string_with_string_response(command_string) + results = await self.command_list.execute_function_string(command_string, string_response=True) return MessageEvent(message=results) except Exception as e: return ErrorEvent(message=f"Error! {e}", metadata={"error": str(e)}) @@ -177,15 +169,14 @@ async def respond( completion_args = { "model": self.model, "messages": [*self._formatted_instructions(instruction_parameters), *(await self.message_provider.get())], - "tools": function_registry_to_tools(self.function_registry), - "tool_choice": function_list_to_tools(function_choice), "response_format": response_format, + "tool_choice": function_list_to_tool_choice(function_choice), } try: completion, new_messages = await complete_with_tool_calls( self.client, - self.function_registry, completion_args, + self.function_list, metadata=metadata, ) except CompletionError as e: @@ -211,7 +202,7 @@ def format_instructions( """ Chat Driver instructions are system messages given to the OpenAI model before any other messages. These instructions are used to guide the model in - generating a response. We oftentimes need inject variables into the + generating a response. We oftentimes need to inject variables into the instructions, so we provide a formatter function to format the instructions with the variables. This method returns a list of system messages formatted with the variables. diff --git a/libraries/python/chat-driver/chat_driver/local_message_history_provider.py b/libraries/python/chat-driver/chat_driver/local_message_history_provider.py index d16d1889..a37bafce 100644 --- a/libraries/python/chat-driver/chat_driver/local_message_history_provider.py +++ b/libraries/python/chat-driver/chat_driver/local_message_history_provider.py @@ -4,7 +4,6 @@ from pathlib import Path from typing import Any -from context.context import ContextProtocol from openai.types.chat import ( ChatCompletionMessageParam, ) @@ -17,7 +16,7 @@ @dataclass class LocalMessageHistoryProviderConfig: - context: ContextProtocol + session_id: str data_dir: PathLike | str | None = None messages: list[ChatCompletionMessageParam] = field(default_factory=list) formatter: MessageFormatter | None = None @@ -26,7 +25,7 @@ class LocalMessageHistoryProviderConfig: class LocalMessageHistoryProvider(MessageHistoryProviderProtocol): def __init__(self, config: LocalMessageHistoryProviderConfig) -> None: if not config.data_dir: - self.data_dir = DEFAULT_DATA_DIR / "chat_driver" / config.context.session_id + self.data_dir = DEFAULT_DATA_DIR / "chat_driver" / config.session_id else: self.data_dir = Path(config.data_dir) self.formatter = config.formatter or format_with_liquid diff --git a/libraries/python/openai-client/openai_client/errors.py b/libraries/python/openai-client/openai_client/errors.py index a56260c8..fc2b4406 100644 --- a/libraries/python/openai-client/openai_client/errors.py +++ b/libraries/python/openai-client/openai_client/errors.py @@ -59,7 +59,7 @@ def __init__(self, error: Exception) -> None: super().__init__(message) -def validate_completion(completion: ParsedChatCompletion[None]) -> None: +def validate_completion(completion: ParsedChatCompletion | None) -> None: if completion is None: raise CompletionIsNoneError() diff --git a/libraries/python/openai-client/openai_client/messages.py b/libraries/python/openai-client/openai_client/messages.py index 13b981ae..37dd4547 100644 --- a/libraries/python/openai-client/openai_client/messages.py +++ b/libraries/python/openai-client/openai_client/messages.py @@ -109,7 +109,7 @@ def format_with_liquid(value: str, vars: dict[str, Any]) -> str: def create_system_message( - content: str, var: dict[str, Any] | None = None, formatter: MessageFormatter = format_with_dict + content: str, var: dict[str, Any] | None = None, formatter: MessageFormatter = format_with_liquid ) -> ChatCompletionSystemMessageParam: if var: content = formatter(content, var) @@ -117,7 +117,7 @@ def create_system_message( def create_user_message( - content: str, var: dict[str, Any] | None = None, formatter: MessageFormatter = format_with_dict + content: str, var: dict[str, Any] | None = None, formatter: MessageFormatter = format_with_liquid ) -> ChatCompletionUserMessageParam: if var: content = formatter(content, var) @@ -129,7 +129,7 @@ def create_assistant_message( refusal: Optional[str] = None, tool_calls: Iterable[ChatCompletionMessageToolCallParam] | None = None, var: dict[str, Any] | None = None, - formatter: MessageFormatter = format_with_dict, + formatter: MessageFormatter = format_with_liquid, ) -> ChatCompletionAssistantMessageParam: if var: content = formatter(content, var) diff --git a/libraries/python/openai-client/openai_client/tools.py b/libraries/python/openai-client/openai_client/tools.py index 64d6f59e..f17c4be0 100644 --- a/libraries/python/openai-client/openai_client/tools.py +++ b/libraries/python/openai-client/openai_client/tools.py @@ -1,8 +1,11 @@ +import ast +import inspect import json -from typing import Any, Iterable +from dataclasses import dataclass +from typing import Any, Callable, Iterable -from function_registry import FunctionRegistry from openai import ( + NOT_GIVEN, AsyncAzureOpenAI, AsyncOpenAI, NotGiven, @@ -13,6 +16,8 @@ ParsedChatCompletion, ParsedFunctionToolCall, ) +from pydantic import BaseModel, create_model +from pydantic.fields import FieldInfo from . import logger from .completion import assistant_message_from_completion @@ -20,57 +25,35 @@ from .logging import add_serializable_data, make_completion_args_serializable -async def execute_tool_call( - tool_call: ParsedFunctionToolCall, - function_registry: FunctionRegistry, -) -> ChatCompletionMessageParam | None: +def to_string(value: Any) -> str: """ - Execute a tool call function using a Function Registry and return the response as a message. + Convert a value to a string. This is a helper function to get the response + of a tool function call into a message. """ - function = tool_call.function - if function_registry.has_function(function.name): - logger.debug( - "Function call.", - extra=add_serializable_data({"name": function.name, "arguments": function.arguments}), - ) - try: - kwargs: dict[str, Any] = json.loads(function.arguments) - value = await function_registry.execute_function_with_string_response(function.name, (), kwargs) - except Exception as e: - logger.error("Error.", extra=add_serializable_data({"error": e})) - value = f"Error: {e}" - finally: - logger.debug( - "Function response.", extra=add_serializable_data({"tool_call_id": tool_call.id, "content": value}) - ) - return { - "role": "tool", - "content": value, - "tool_call_id": tool_call.id, - } + if value is None: + return "Function executed successfully." + elif isinstance(value, str): + return value + elif isinstance(value, (int, float)): + return str(value) + elif isinstance(value, dict): + return json.dumps(value) + elif isinstance(value, list): + return json.dumps(value, indent=2) + elif isinstance(value, tuple): + return json.dumps(value) + elif isinstance(value, BaseModel): + return value.model_dump_json(indent=2) else: - logger.error(f"Function not found: {function.name}") - + return str(value) -def function_registry_to_tools(function_registry: FunctionRegistry) -> Iterable[ChatCompletionToolParam] | NotGiven: - # Only the "functions" tool is available in the Chat API. - # https://platform.openai.com/docs/guides/function-calling - # If the only tool is the default function registry help function, then - # we don't want to tell the chat response that we have any tools. - if function_registry.list_functions() == ["help"]: - return NotGiven() - - return [ - ChatCompletionToolParam(**{ - "type": "function", - "function": func.schema, - }) - for func in function_registry.get_functions() - ] - - -def function_list_to_tools(functions: list[str] | None) -> Iterable[ChatCompletionToolParam] | None: +def function_list_to_tool_choice(functions: list[str] | None) -> Iterable[ChatCompletionToolParam] | None: + """ + Convert a list of function names to a list of ChatCompletionToolParam + objects. This is used in the Chat Completions API if you want to tell the + completion it MUST use a specific set of tool functions. + """ if not functions: return None return [ @@ -82,25 +65,378 @@ def function_list_to_tools(functions: list[str] | None) -> Iterable[ChatCompleti ] or None +@dataclass +class Parameter: + """ + Tool functions are described by their parameters. This dataclass + describes a single parameter of a tool function. + """ + + name: str + type: Any + description: str | None + default_value: Any | None = None + + +class ToolFunction: + """ + A tool function is a Python function that can be called as a tool from the + chat completion API. This class wraps a function so you can generate it's + JSON schema for the chat completion API, execute it with arguments, and + generate a usage string (for help messages) + """ + + def __init__(self, fn: Callable, name: str | None = None, description: str | None = None) -> None: + self.fn = fn + self.name = name or fn.__name__ + self.description = description or inspect.getdoc(fn) or self.name.replace("_", " ").title() + + def parameters(self, exclude: list[str] = []) -> list[Parameter]: + """ + This function's parameters and their default values. + """ + parameters = dict(inspect.signature(self.fn).parameters) + for param_name in exclude: + del parameters[param_name] + return [ + Parameter( + name=param_name, + type=param.annotation, + description=None, # param.annotation.description, + default_value=param.default, + ) + for param_name, param in parameters.items() + ] + + def usage(self) -> str: + """ + A usage string for this function. This can be used in help messages. + """ + name = self.name + param_usages = [] + for param in self.parameters(): + param_type = param.type + try: + param_type = param.type.__name__ + except AttributeError: + param_type = param.type + usage = f"{param.name}: {param_type}" + if param.default_value is not inspect.Parameter.empty: + if isinstance(param.default_value, str): + usage += f' = "{param.default_value}"' + else: + usage += f" = {param.default_value}" + param_usages.append(usage) + + description = self.description + return f"{name}({', '.join(param_usages)}): {description}" + + def schema(self, strict: bool = True) -> dict[str, Any]: + """ + Generate a JSON schema for this function that is suitable for the OpenAI + completion API. + """ + + # Create the Pydantic model using create_model. + model_name = self.fn.__name__.title().replace("_", "") + fields = {} + for parameter in self.parameters(): + field_info = FieldInfo(description=parameter.description) + if parameter.default_value is not inspect.Parameter.empty: + field_info.default = parameter.default_value + fields[parameter.name] = ( + parameter.type, + field_info, + ) + pydantic_model = create_model(model_name, **fields) + + # Generate the JSON schema from the Pydantic model. + parameters_schema = pydantic_model.model_json_schema(mode="serialization") + + # Remove title attribute from all properties (not allowed by the Chat + # Completions API). + properties = parameters_schema["properties"] + for property_key in properties.keys(): + if "title" in properties[property_key]: + del properties[property_key]["title"] + + # And from the top-level object. + if "title" in parameters_schema: + del parameters_schema["title"] + + # Output a schema that matches OpenAI's "tool" format. + # e.g., https://platform.openai.com/docs/guides/function-calling + # We use this because they trained GPT on it. + schema = { + # "$schema": "http://json-schema.org/draft-07/schema#", + # "$id": f"urn:jsonschema:{name}", + "name": self.name, + "description": self.description, + "strict": strict, + "parameters": { + "type": "object", + "properties": parameters_schema["properties"], + }, + } + + # If this is a strict schema, OpenAI requires additionalProperties to be + # False. "strict mode" is required for JSON or structured output from + # the API. + if strict: + schema["parameters"]["additionalProperties"] = False + + # Add required fields (another Chat Completions API requirement). + if "required" in parameters_schema: + schema["parameters"]["required"] = parameters_schema["required"] + + # Add type definitions (another Chat Completions API requirement). + if "$defs" in parameters_schema: + schema["parameters"]["$defs"] = parameters_schema["$defs"] + for key in schema["parameters"]["$defs"]: + schema["parameters"]["$defs"][key]["additionalProperties"] = False + + return schema + + async def execute(self, string_response: bool = False, *args, **kwargs) -> Any: + """ + Run this function, and return its value. If the function is a coroutine, + it will be awaited. If string_response is True, the response will be + converted to a string. + """ + try: + result = self.fn(*args, **kwargs) + if inspect.iscoroutine(result): + result = await result + if string_response: + return to_string(result) + return result + except Exception as e: + if string_response: + return f"Error running function {self.name}: {e}" + raise e + + +class FunctionHandler: + def __init__(self, tool_functions: "ToolFunctions") -> None: + self.tool_functions = tool_functions + + def __getattr__(self, name: str) -> Callable: + """Makes registered functions accessible as attributes of the functions object.""" + if name not in self.tool_functions.function_map: + raise AttributeError(f"'FunctionHandler' object has no attribute '{name}'") + + async def wrapper(*args, **kwargs) -> Any: + return await self.tool_functions.execute_function(name, args, kwargs) + + return wrapper + + +class ToolFunctions: + """ + A set of tool functions that can be called from the Chat Completions API. + Pass this into the `complete_with_tool_calls` helper function to run a full + tool-call completion against the API. + """ + + def __init__(self, functions: list[ToolFunction] | None = None, with_help: bool = False) -> None: + # Set up function map. + self.function_map = {} + if functions: + for function in functions: + self.function_map[function.name] = function + + # A help message can be generated for the function map. + if with_help: + self.function_map["help"] = ToolFunction(self.help) + + # This allows actions to be called as attributes. + self.functions = FunctionHandler(self) + + def help(self) -> str: + """Return this help message.""" + + usage = [f"{command.usage()}" for command in self.function_map.values()] + usage.sort() + return "Commands:\n" + "\n".join(usage) + + def add_function(self, function: Callable, name: str | None = None, description: str | None = None) -> None: + """Register a function with the tool functions.""" + if not name: + name = function.__name__ + self.function_map[name] = ToolFunction(function, name, description) + + def has_function(self, name: str) -> bool: + return name in self.function_map + + def get_function(self, name: str) -> ToolFunction | None: + return self.function_map.get(name) + + def get_functions(self) -> list[ToolFunction]: + return [function for function in self.function_map.values()] + + async def execute_function( + self, name: str, args: tuple = (), kwargs: dict[str, Any] = {}, string_response: bool = False + ) -> Any: + """ + Run a function from the ToolFunctions list by name. If string_response + is True, the function return value will be converted to a string. + """ + function = self.get_function(name) + if not function: + raise ValueError(f"Function {name} not found in registry.") + return await function.execute(string_response, *args, **kwargs) + + async def execute_function_string(self, function_string: str, string_response: bool = False) -> Any: + """Parse a function string and execute the function.""" + try: + function, args, kwargs = self.parse_function_string(function_string) + except ValueError as e: + raise ValueError(f"{e}. Type: `/help` for more information.") + if not function: + raise ValueError("Function not found in registry. Type: `/help` for more information.") + return await function.execute(string_response, *args, **kwargs) + + def parse_function_string(self, function_string: str) -> tuple[ToolFunction | None, list[Any], dict[str, Any]]: + """Parse a function call string into a function and its arguments.""" + + # As a convenience, remove any leading slashes. + function_string = function_string.lstrip("/") + + # As a convenience, add parentheses if they are missing. + if " " not in function_string and "(" not in function_string: + function_string += "()" + + # Parse the string into an AST (Abstract Syntax Tree) + try: + tree = ast.parse(function_string) + except SyntaxError: + raise ValueError("Invalid function call. Please check your syntax.") + + # Ensure the tree contains exactly one expression (the function call) + if not (isinstance(tree, ast.Module) and len(tree.body) == 1 and isinstance(tree.body[0], ast.Expr)): + raise ValueError("Expected a single function call.") + + # The function call is stored as a `Call` node within the expression + call_node = tree.body[0].value + if not isinstance(call_node, ast.Call): + raise ValueError("Invalid function call. Please check your syntax.") + + # Extract the function name + if isinstance(call_node.func, ast.Name): + function_name = call_node.func.id + else: + raise ValueError("Unsupported function format. Please check your syntax.") + + # Helper function to evaluate AST nodes to their Python equivalent + def eval_node(node): + if isinstance(node, ast.Constant): + return node.value + elif isinstance(node, ast.List): + return [eval_node(elem) for elem in node.elts] + elif isinstance(node, ast.Tuple): + return tuple(eval_node(elem) for elem in node.elts) + elif isinstance(node, ast.Dict): + return {eval_node(key): eval_node(value) for key, value in zip(node.keys, node.values)} + elif isinstance(node, ast.Name): + return node.id # This can return variable names, but we assume they're constants + elif isinstance(node, ast.BinOp): # Handling arithmetic expressions + return eval(compile(ast.Expression(node), filename="", mode="eval")) + elif isinstance(node, ast.Call): + raise ValueError("Nested function calls are not supported.") + else: + raise ValueError(f"Unsupported AST node type: {type(node).__name__}") + + # Extract positional arguments + args = [eval_node(arg) for arg in call_node.args] + + # Extract keyword arguments + kwargs = {} + for kw in call_node.keywords: + kwargs[kw.arg] = eval_node(kw.value) + + function = self.get_function(function_name) + if not function: + return None, [], {} + + return function, args, kwargs + + def chat_completion_tools(self) -> list[ChatCompletionToolParam] | NotGiven: + """ + Return a list of ChatCompletionToolParam objects that describe the tool + functions in this ToolFunctions object. These can be passed to the Chat + Completions API (in the "tools" parameter) to enable tool function + calls. + """ + tools = [ + ChatCompletionToolParam(**{ + "type": "function", + "function": func.schema(), + }) + for func in self.function_map.values() + ] + return tools or NOT_GIVEN + + async def execute_tool_call(self, tool_call: ParsedFunctionToolCall) -> ChatCompletionMessageParam | None: + """ + Execute a function as requested by a ParsedFunctionToolCall (generated + by the Chat Completions API) and return the response as a + ChatCompletionMessageParam message (as required by the Chat Completions + API) + """ + function = tool_call.function + if self.has_function(function.name): + logger.debug( + "Function call.", + extra=add_serializable_data({"name": function.name, "arguments": function.arguments}), + ) + try: + kwargs: dict[str, Any] = json.loads(function.arguments) + value = await self.execute_function(function.name, (), kwargs, string_response=True) + except Exception as e: + logger.error("Error.", extra=add_serializable_data({"error": e})) + value = f"Error: {e}" + finally: + logger.debug( + "Function response.", extra=add_serializable_data({"tool_call_id": tool_call.id, "content": value}) + ) + return { + "role": "tool", + "content": value, + "tool_call_id": tool_call.id, + } + else: + logger.error(f"Function not found: {function.name}") + return None + + async def complete_with_tool_calls( async_client: AsyncOpenAI | AsyncAzureOpenAI, - function_registry: FunctionRegistry, completion_args: dict[str, Any], + tool_functions: ToolFunctions, metadata: dict[str, Any] = {}, ) -> tuple[ParsedChatCompletion | None, list[ChatCompletionMessageParam]]: """ - Complete a chat response with tool calls handled by Function Registry-registered functions. + Complete a chat response with tool calls handled by the supplied tool + functions. Parameters: + - async_client: The OpenAI client. - - function_registry: The function registry. - - completion_args: The completion arguments passed onto the OpenAI `parse` call. See the OpenAI API docs for more information. + - completion_args: The completion arguments passed onto the OpenAI `parse` + call. See the OpenAI API docs for more information. + - tool_functions: A ToolFunctions object that contains the tool functions to + be available to be called. - metadata: Metadata to be added to the completion response. """ # Pull out a reference to the completion args messages. messages: list[ChatCompletionMessageParam] = completion_args.get("messages", []) new_messages: list[ChatCompletionMessageParam] = [] + # Set up the tools if tool_functions exists. + if tool_functions: + # Note: this overwrites any existing tools. + completion_args["tools"] = tool_functions.chat_completion_tools() + # Completion call. logger.debug("Completion call.", extra=add_serializable_data(make_completion_args_serializable(completion_args))) metadata["completion_args"] = make_completion_args_serializable(completion_args) @@ -131,23 +467,26 @@ async def complete_with_tool_calls( # Call all tool functions and generate return messages. for tool_call in completion_message.tool_calls: - function_call_result_message = await execute_tool_call(tool_call, function_registry) + function_call_result_message = await tool_functions.execute_tool_call(tool_call) if function_call_result_message: new_messages.append(function_call_result_message) # Completion call for final response. final_args = {**completion_args, "messages": [*messages, *new_messages]} - del final_args["tools"] - del final_args["tool_choice"] + if "tools" in final_args: + # TODO: We *could* allow a while "tools" loop and let the agent keep going? + del final_args["tools"] + if "tool_choice" in final_args: + del final_args["tool_choice"] logger.debug("Tool completion call.", extra=add_serializable_data(make_completion_args_serializable(final_args))) metadata["tool_completion_args"] = make_completion_args_serializable(final_args) try: - tool_completion = await async_client.beta.chat.completions.parse( + tool_completion: ParsedChatCompletion = await async_client.beta.chat.completions.parse( **final_args, ) validate_completion(tool_completion) logger.debug("Tool completion response.", extra=add_serializable_data({"completion": completion.model_dump()})) - metadata["completion"] = completion.model_dump() + metadata["tool_completion"] = completion.model_dump() except Exception as e: tool_completion_error = CompletionError(e) metadata["tool_completion_error"] = tool_completion_error.message diff --git a/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb b/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb index 5c65e71e..15711770 100644 --- a/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb +++ b/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb @@ -1,1216 +1,1187 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Chat Driver\n", - "\n", - "An OpenAI Chat Completions API wrapper." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Notebook setup\n", - "\n", - "Run this cell to set the notebook up. Other sections can be run independently." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], - "source": [ - "%reload_ext autoreload\n", - "%autoreload 2\n", - "\n", - "import os\n", - "from dotenv import load_dotenv\n", - "from azure.identity import aio, DefaultAzureCredential, get_bearer_token_provider, AzureCliCredential\n", - "\n", - "from openai import AsyncAzureOpenAI, AzureOpenAI\n", - "\n", - "import logging \n", - "import json\n", - "from pathlib import Path\n", - "\n", - "LOGGING = {\n", - " \"version\": 1,\n", - " \"disable_existing_loggers\": False,\n", - " \"formatters\": {\n", - " \"json\": {\n", - " \"()\": \"pythonjsonlogger.jsonlogger.JsonFormatter\",\n", - " \"fmt\": \"%(asctime)s %(levelname)s %(name)s %(message)s\",\n", - "\n", - " }\n", - " },\n", - "}\n", - "\n", - "\n", - "# Set up structured logging to a file. All of the cells in this notebook use\n", - "# this logger. Find them at .data/logs.jsonl.\n", - "class JsonFormatter(logging.Formatter):\n", - " def format(self, record) -> str:\n", - " record_dict = record.__dict__\n", - " log_record = {\n", - " 'timestamp': self.formatTime(record, self.datefmt),\n", - " 'level': record.levelname,\n", - " 'session_id': record_dict.get('session_id', None),\n", - " 'run_id': record_dict.get('run_id', None),\n", - " 'message': record.getMessage(),\n", - " 'data': record_dict.get('data', None),\n", - " 'module': record.module,\n", - " 'funcName': record.funcName,\n", - " 'lineNumber': record.lineno,\n", - " 'logger': record.name,\n", - " }\n", - " extra_fields = {\n", - " key: value for key, value in record.__dict__.items() \n", - " if key not in ['levelname', 'msg', 'args', 'exc_info', 'funcName', 'module', 'lineno', 'name', 'message', 'asctime', 'session_id', 'run_id', 'data']\n", - " }\n", - " log_record.update(extra_fields)\n", - " return json.dumps(log_record)\n", - "\n", - "logger = logging.getLogger()\n", - "logger.setLevel(logging.DEBUG)\n", - "modules = ['httpcore.connection', 'httpcore.http11', 'httpcore.sync.connection', 'httpx', 'openai', 'urllib3.connectionpool', 'urllib3.util.retry']\n", - "for module in modules:\n", - " logging.getLogger(module).setLevel(logging.ERROR)\n", - "if logger.hasHandlers():\n", - " logger.handlers.clear()\n", - "data_dir = Path('.data')\n", - "if not data_dir.exists():\n", - " data_dir.mkdir()\n", - "handler = logging.FileHandler(data_dir / 'logs.jsonl')\n", - "handler.setFormatter(JsonFormatter())\n", - "logger.addHandler(handler)\n", - "\n", - "\n", - "load_dotenv()\n", - "credential = DefaultAzureCredential()\n", - "\n", - "azure_openai_config = {\n", - " \"azure_endpoint\": os.environ.get(\"AZURE_OPENAI_ENDPOINT\", \"\"),\n", - " \"azure_deployment\": os.environ.get(\"AZURE_OPENAI_DEPLOYMENT\", \"\"),\n", - " \"api_version\": os.environ.get(\"AZURE_OPENAI_API_VERSION\", \"\"),\n", - " \"max_retries\": 2,\n", - "}\n", - "logger.info(\"Azure OpenAI configuration\", extra=azure_openai_config)\n", - "\n", - "async_client = AsyncAzureOpenAI(\n", - " **azure_openai_config,\n", - " azure_ad_token_provider=aio.get_bearer_token_provider(\n", - " aio.AzureCliCredential(),\n", - " \"https://cognitiveservices.azure.com/.default\",\n", - " ),\n", - ")\n", - "\n", - "client = AzureOpenAI(\n", - " **azure_openai_config,\n", - " azure_ad_token_provider=get_bearer_token_provider(\n", - " AzureCliCredential(),\n", - " \"https://cognitiveservices.azure.com/.default\",\n", - " ),\n", - ")\n", - "\n", - "model: str = azure_openai_config.get(\"azure_deployment\", \"gpt-4o\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## ChatCompletionsAPI usage\n", - "\n", - "Azure/OpenAI's Chat Completions API is the fundamental building block of an AI assistant that uses the GPT model. \n", - "\n", - "- https://platform.openai.com/docs/api-reference/chat\n", - "- https://github.com/openai/openai-python/blob/main/api.md\n", - "- https://platform.openai.com/docs/api-reference/chat drivers" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Sync" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'id': 'chatcmpl-AQga9wXFldlhHVce3CfXMQ7jXo9L9', 'choices': [{'finish_reason': 'stop', 'index': 0, 'logprobs': None, 'message': {'content': 'This is a test.', 'refusal': None, 'role': 'assistant', 'function_call': None, 'tool_calls': None}}], 'created': 1730923577, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': {'completion_tokens': 5, 'prompt_tokens': 12, 'total_tokens': 17, 'completion_tokens_details': None, 'prompt_tokens_details': None}}\n" - ] - } - ], - "source": [ - "completion = client.chat.completions.create(\n", - " messages=[\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"Say this is a test\",\n", - " }\n", - " ],\n", - " model=model,\n", - ")\n", - "print(completion.model_dump_json(indent=2))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Async" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ChatCompletion(id='chatcmpl-AQgaCid05i8dGgUHijQsvPAsMYbv4', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='This is a test.', refusal=None, role='assistant', function_call=None, tool_calls=None))], created=1730923580, model='gpt-4o-2024-08-06', object='chat.completion', service_tier=None, system_fingerprint='fp_d54531d9eb', usage=CompletionUsage(completion_tokens=5, prompt_tokens=12, total_tokens=17, completion_tokens_details=None, prompt_tokens_details=None))\n" - ] - } - ], - "source": [ - "message_event = await async_client.chat.completions.create(\n", - " messages=[\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"Say this is a test\",\n", - " }\n", - " ],\n", - " model=model,\n", - ")\n", - "print(message_event)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Streaming" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': '', 'function_call': None, 'refusal': None, 'role': 'assistant', 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", - "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': 'This', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", - "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': ' is', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", - "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': ' a', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", - "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': ' test', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", - "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': '.', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", - "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': None, 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': 'stop', 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n" - ] - } - ], - "source": [ - "stream = await async_client.chat.completions.create(\n", - " messages=[\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"Say this is a test\",\n", - " }\n", - " ],\n", - " model=model,\n", - " stream=True,\n", - ")\n", - "async for chunk in stream:\n", - " print(chunk.model_dump())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## OpenAI Helpers" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Standardized response handling" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "The future of AI is both exciting and complex, with its trajectory shaped by advances in technology, ethical considerations, and societal needs. As we look ahead, several key themes emerge:\n", - "\n", - "1. **Integration and Personalization**: AI will become increasingly integrated into our daily lives, driving personalized experiences. From healthcare to education, AI systems will tailor recommendations and interventions to individual needs, optimizing outcomes across various sectors.\n", - "\n", - "2. **AI in Healthcare**: We can expect AI to revolutionize the healthcare industry by enhancing diagnostic accuracy, streamlining administrative processes, and developing personalized medicine. AI-driven tools could predict diseases, recommend treatments, and even aid in surgical procedures, ultimately improving patient care and reducing costs.\n", - "\n", - "3. **Autonomous Systems**: Autonomous vehicles, drones, and robotic systems will become more prevalent, transforming industries like transportation, logistics, and manufacturing. These systems will improve efficiency and safety while also creating new business models and opportunities.\n", - "\n", - "4. **Ethical and Responsible AI**: As AI systems become more autonomous, the demand for ethical AI frameworks will increase. Ensuring transparency, fairness, accountability, and privacy will be crucial to maintaining public trust. Developing AI systems that align with human values and societal norms will be an ongoing challenge.\n", - "\n", - "5. **AI and the Workforce**: While AI will automate certain tasks, it will also create new job opportunities and demand an upskilled workforce. It is important to focus on reskilling and education initiatives to prepare the workforce for an AI-augmented future.\n", - "\n", - "6. **AI in Climate and Sustainability**: AI will play a significant role in addressing climate change and promoting sustainability. From optimizing energy usage and improving agricultural practices to predicting environmental changes, AI could be a critical tool in creating a more sustainable future.\n", - "\n", - "7. **AI in Creativity and Arts**: AI is increasingly being used in creative fields, such as music, art, and literature. While it can augment human creativity by offering new tools and perspectives, there will be ongoing discussions about the nature of creativity and authorship.\n", - "\n", - "8. **AI Governance and Policy**: With AI's growing influence, policy and regulation will need to keep pace to address issues such as data ownership, algorithmic bias, and national security. International collaboration may be necessary to create coherent frameworks addressing these challenges.\n", - "\n", - "In summary, AI has the potential to greatly benefit society, but its development requires thoughtful consideration of ethical, social, and economic impacts. As we move forward, collaboration among technologists, policymakers, and the public will be essential to harness AI for the greater good.\n" - ] - } - ], - "source": [ - "from context import Context\n", - "from openai_client.errors import CompletionError, validate_completion\n", - "from openai_client.logging import extra_data, serializable_completion_args\n", - "from openai_client.completion import completion_message_string\n", - "\n", - "context = Context(\"conversation-id-1005\")\n", - "\n", - "# We use a metadata dictionary in our helpers to store information about the\n", - "# completion request.\n", - "metadata = {}\n", - "\n", - "# This is just standard OpenAI completion request arguments.\n", - "completion_args = {\n", - " \"model\": model,\n", - " \"messages\": [\n", - " {\n", - " \"role\": \"system\",\n", - " \"content\": \"You are a famous computer scientist. You are giving a talk at a conference. You are talking about the future of AI and how it will change the world. You are asked a questions by audience members and answer thoughtfully.\",\n", - " },\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"What is the future of AI?\",\n", - " }\n", - " ],\n", - "}\n", - "\n", - "# If we these completion args to logs and metadata, though, they need to be\n", - "# serializable. We have a helper for that.\n", - "metadata[\"completion_args\"] = serializable_completion_args(completion_args)\n", - "\n", - "# We have helpers for validating the response and handling exceptions in a\n", - "# standardized way. These ensure that logging happens and metadata is loaded up\n", - "# properly.\n", - "try:\n", - " completion = await async_client.beta.chat.completions.parse(**completion_args)\n", - "\n", - " # This helper looks for any error-like situations (the model refuses to\n", - " # answer, content filters, incomplete responses) and throws exceptions that\n", - " # are handled by the next helper. The first argument is an identifier that\n", - " # will be used for logs and metadata namespacing.\n", - " validate_completion(completion)\n", - " logger.debug(\"completion response.\", extra=extra_data(completion))\n", - " metadata[\"completion\"] = completion.model_dump()\n", - "\n", - "except Exception as e:\n", - " # This helper processes all the types of error conditions you might get from\n", - " # the OpenAI API in a standardized way.\n", - " completion_error = CompletionError(e)\n", - " print(completion_error)\n", - " print(completion_error.body)\n", - "\n", - "else:\n", - " # The message_string helper is used to extract the response from the completion\n", - " # (which can get tedious).\n", - " print(completion_message_string(completion))\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### JSON" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{\n", - " \"thoughts\": \"AI is rapidly evolving and has the potential to transform virtually every industry. With advancements in machine learning, natural language processing, and robotics, AI will continue to play a crucial role in automating routine tasks and providing intelligent insights.\",\n", - " \"answer\": \"The future of AI involves deeper integration into everyday life and industry. We will likely see AI systems becoming more autonomous, sophisticated, and seamlessly integrated into systems like healthcare, transportation, and personalized services. AI's future encompasses not only technological advancements but also ethical considerations and ensuring beneficial societal impacts.\"\n", - "}\n" - ] - } - ], - "source": [ - "from context import Context\n", - "from openai_client.errors import CompletionError, validate_completion\n", - "from openai_client.logging import extra_data, serializable_completion_args\n", - "from openai_client.completion import completion_message_dict, JSON_OBJECT_RESPONSE_FORMAT\n", - "\n", - "context = Context(\"conversation-id-1002\")\n", - "metadata = {}\n", - "completion_args = {\n", - " \"model\": model,\n", - " \"messages\": [\n", - " {\n", - " \"role\": \"system\",\n", - " \"content\": \"You are a famous computer scientist. You are giving a talk at a conference. You are talking about the future of AI and how it will change the world. You are asked a questions by audience members and return your answer as valid JSON like { \\\"thoughts\\\": , \\\"answer\\\": }.\",\n", - " },\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"What is the future of AI?\",\n", - " }\n", - " ],\n", - " \"response_format\": JSON_OBJECT_RESPONSE_FORMAT,\n", - "}\n", - "metadata[\"completion_args\"] = serializable_completion_args(completion_args)\n", - "try:\n", - " completion = await async_client.beta.chat.completions.parse(**completion_args)\n", - " validate_completion(completion)\n", - " metadata[\"completion\"] = completion.model_dump()\n", - "except Exception as e:\n", - " completion_error = CompletionError(e)\n", - " metadata[\"completion_error\"] = completion_error.body\n", - " logger.error(completion_error.message, extra=extra_data({\"error\": completion_error.body, \"metadata\": metadata}))\n", - "else:\n", - " message = completion_message_dict(completion)\n", - " print(json.dumps(message, indent=2))\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Structured Output\n", - "\n", - "Any Pydantic BaseModel can be used as the \"response_format\" and OpenAI will try to load it up for you." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{\n", - " \"thoughts\": \"AI has shown immense potential in various fields, including healthcare, transportation, and climate science. The trajectory of its development suggests even greater integration into daily life and business operations.\",\n", - " \"answer\": \"The future of AI lies in its ability to become more autonomous, adaptive, and integrated into various facets of life and industry. We will likely see AI taking on increasingly complex tasks with minimal human intervention, improving efficiency and productivity. It will transform sectors like healthcare through predictive diagnostics, personalize education, and enhance decision-making in businesses with deeper insights from data analytics. However, it will also be crucial to address ethical concerns, such as privacy, bias, and the impact on jobs, to ensure AI serves the broader good.\"\n", - "}\n" - ] - } - ], - "source": [ - "from context import Context\n", - "from pydantic import BaseModel\n", - "from typing import cast\n", - "from openai_client.errors import CompletionError, validate_completion\n", - "from openai_client.logging import extra_data, serializable_completion_args\n", - "from openai_client.completion import completion_message_dict, JSON_OBJECT_RESPONSE_FORMAT\n", - "\n", - "class Output(BaseModel):\n", - " thoughts: str\n", - " answer: str\n", - "\n", - "context = Context(\"conversation-id-1002\")\n", - "metadata = {}\n", - "completion_args = {\n", - " \"model\": model,\n", - " \"messages\": [\n", - " {\n", - " \"role\": \"system\",\n", - " \"content\": \"You are a famous computer scientist. You are giving a talk at a conference. You are talking about the future of AI and how it will change the world. You are asked a questions by audience members and return your answer as valid JSON like { \\\"thoughts\\\": , \\\"answer\\\": }.\",\n", - " },\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"What is the future of AI?\",\n", - " }\n", - " ],\n", - " \"response_format\": Output,\n", - "}\n", - "\n", - "metadata[\"completion_args\"] = serializable_completion_args(completion_args)\n", - "try:\n", - " completion = await async_client.beta.chat.completions.parse(**completion_args)\n", - " validate_completion(completion)\n", - " metadata[\"completion\"] = completion.model_dump()\n", - "except Exception as e:\n", - " completion_error = CompletionError(e)\n", - " metadata[\"completion_error\"] = completion_error.body\n", - " logger.error(completion_error.message, extra=extra_data({\"error\": completion_error.body, \"metadata\": metadata}))\n", - "else:\n", - " # The parsed message is in the `parsed` attribute.\n", - " output = cast(Output, completion.choices[0].message.parsed)\n", - " print(output.model_dump_json(indent=2))\n", - "\n", - " # Or you can just get the text of the message like usual.\n", - " # print(completion.choices[0].message.content)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## OpenAI Chat Completion Driver (a.k.a \"chat driver\")\n", - "\n", - "### OpenAI Assistants\n", - "\n", - "The Azure/OpenAI Assistants API is newer, stateful API that splits an `assistant` from the data about a conversation `thread` that can be `run` against an `assistant`. Additionally, you can add `tools` to an assistant that enable the assistant to have more interactive capabilities. The tools currently available are:\n", - "\n", - "- *Functions*: Registering local functions with the assistant so it knows it can call them before generating a response. This is a \"hold on let me look that up for you\" kind of interaction.\n", - "- *File Search* (formerly the retrieval plugin): Attach one or more files and they will be RAG-vectorized and available as content to the assistant.\n", - "- *Code Interpreter*: Run python code in a secure sandbox.\n", - "\n", - "The Assistant API productized as OpenAI's `GPTs` product. The `GPT Builder` lets developers create and deploy GPTs assistants using a web interface.\n", - "\n", - "### Chat Driver\n", - "\n", - "But an \"assistant\" requires pretty strong \"abstraction lock-in\". This thing isn't really an assistant in the fullest sense... it's more like a \"pseudo-assistant\", but this confuses things. Let's just let the Chat Completion API be what it is and drive it as necessary as we create our assistants. Let's just wrap up the function calling bits (which, ultimately, can give you the other tools like Functions and File Search) in a simple-to-use GPT-like interface we'll call a *chat driver*.\n", - "\n", - "The chat driver is meant to be used the exact way the Chat Completions API is... just easier.\n", - "\n", - "Our chat driver provides:\n", - "\n", - "- The ability to almost magically register functions to the function tool using a `FunctionRegistry`.\n", - "- Tracking of message history.\n", - "- Management of a `Context` object that can be used for session management and supply additional context to functions.\n", - "- Some prompt creation helpers.\n", - "- Other utilities... this is just meant to be an interface you can use to forget about all the api complexities." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Here is the simplest usage of a chat driver\n", - "\n", - "Notice that a .data directory is created by default. This is where the conversation history is stored." - ] - }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Chat Driver\n", + "\n", + "An OpenAI Chat Completions API wrapper." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Notebook setup\n", + "\n", + "Run this cell to set the notebook up. Other sections can be run independently." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "%reload_ext autoreload\n", + "%autoreload 2\n", + "\n", + "import os\n", + "from dotenv import load_dotenv\n", + "from azure.identity import aio, DefaultAzureCredential, get_bearer_token_provider, AzureCliCredential\n", + "\n", + "from openai import AsyncAzureOpenAI, AzureOpenAI\n", + "\n", + "import logging \n", + "import json\n", + "from pathlib import Path\n", + "\n", + "LOGGING = {\n", + " \"version\": 1,\n", + " \"disable_existing_loggers\": False,\n", + " \"formatters\": {\n", + " \"json\": {\n", + " \"()\": \"pythonjsonlogger.jsonlogger.JsonFormatter\",\n", + " \"fmt\": \"%(asctime)s %(levelname)s %(name)s %(message)s\",\n", + "\n", + " }\n", + " },\n", + "}\n", + "\n", + "\n", + "# Set up structured logging to a file. All of the cells in this notebook use\n", + "# this logger. Find them at .data/logs.jsonl.\n", + "class JsonFormatter(logging.Formatter):\n", + " def format(self, record) -> str:\n", + " record_dict = record.__dict__\n", + " log_record = {\n", + " 'timestamp': self.formatTime(record, self.datefmt),\n", + " 'level': record.levelname,\n", + " 'session_id': record_dict.get('session_id', None),\n", + " 'run_id': record_dict.get('run_id', None),\n", + " 'message': record.getMessage(),\n", + " 'data': record_dict.get('data', None),\n", + " 'module': record.module,\n", + " 'funcName': record.funcName,\n", + " 'lineNumber': record.lineno,\n", + " 'logger': record.name,\n", + " }\n", + " extra_fields = {\n", + " key: value for key, value in record.__dict__.items() \n", + " if key not in ['levelname', 'msg', 'args', 'exc_info', 'funcName', 'module', 'lineno', 'name', 'message', 'asctime', 'session_id', 'run_id', 'data']\n", + " }\n", + " log_record.update(extra_fields)\n", + " return json.dumps(log_record)\n", + "\n", + "logger = logging.getLogger()\n", + "logger.setLevel(logging.DEBUG)\n", + "modules = ['httpcore.connection', 'httpcore.http11', 'httpcore.sync.connection', 'httpx', 'openai', 'urllib3.connectionpool', 'urllib3.util.retry']\n", + "for module in modules:\n", + " logging.getLogger(module).setLevel(logging.ERROR)\n", + "if logger.hasHandlers():\n", + " logger.handlers.clear()\n", + "data_dir = Path('.data')\n", + "if not data_dir.exists():\n", + " data_dir.mkdir()\n", + "handler = logging.FileHandler(data_dir / 'logs.jsonl')\n", + "handler.setFormatter(JsonFormatter())\n", + "logger.addHandler(handler)\n", + "\n", + "\n", + "load_dotenv()\n", + "credential = DefaultAzureCredential()\n", + "\n", + "azure_openai_config = {\n", + " \"azure_endpoint\": os.environ.get(\"AZURE_OPENAI_ENDPOINT\", \"\"),\n", + " \"azure_deployment\": os.environ.get(\"AZURE_OPENAI_DEPLOYMENT\", \"\"),\n", + " \"api_version\": os.environ.get(\"AZURE_OPENAI_API_VERSION\", \"\"),\n", + " \"max_retries\": 2,\n", + "}\n", + "logger.info(\"Azure OpenAI configuration\", extra=azure_openai_config)\n", + "\n", + "async_client = AsyncAzureOpenAI(\n", + " **azure_openai_config,\n", + " azure_ad_token_provider=aio.get_bearer_token_provider(\n", + " aio.AzureCliCredential(),\n", + " \"https://cognitiveservices.azure.com/.default\",\n", + " ),\n", + ")\n", + "\n", + "client = AzureOpenAI(\n", + " **azure_openai_config,\n", + " azure_ad_token_provider=get_bearer_token_provider(\n", + " AzureCliCredential(),\n", + " \"https://cognitiveservices.azure.com/.default\",\n", + " ),\n", + ")\n", + "\n", + "model: str = azure_openai_config.get(\"azure_deployment\", \"gpt-4o\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## ChatCompletionsAPI usage\n", + "\n", + "Azure/OpenAI's Chat Completions API is the fundamental building block of an AI assistant that uses the GPT model. \n", + "\n", + "- https://platform.openai.com/docs/api-reference/chat\n", + "- https://github.com/openai/openai-python/blob/main/api.md\n", + "- https://platform.openai.com/docs/api-reference/chat drivers" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Sync" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "conversation-id-1000\n", - "\n", - "Hello Paul! How can I assist you today?\n", - "\n", - "Commands:\n", - "help(): Return this help message.\n", - "erase(name: str): Erases a stored value.\n", - "echo(text: str): Return the text.\n", - "get_file_contents(file_path: str): Return the contents of a file.\n", - "\n", - "conversation-id-1000: Hi, my name is Paul.\n", - "\n", - "The content of \"123.txt\" is: \"The purpose of life is to be happy.\"\n", - "\n", - "{\n", - " \"id\": \"9444f8f2-aa5a-4c19-9bf4-d36b6bfa9ba4\",\n", - " \"session_id\": null,\n", - " \"timestamp\": \"2024-11-06T20:06:27.777169\",\n", - " \"message\": \"The content of \\\"123.txt\\\" is: \\\"The purpose of life is to be happy.\\\"\",\n", - " \"metadata\": {\n", - " \"completion_args\": {\n", - " \"model\": \"gpt-4o\",\n", - " \"messages\": [\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"What is the future of AI?\"\n", - " },\n", - " {\n", - " \"role\": \"assistant\",\n", - " \"content\": \"The future of AI is incredibly promising and will likely be revolutionary in many aspects of our lives. In the coming years and decades, we can expect several major trends and developments to shape the landscape of artificial intelligence:\\n\\n1. **Ubiquitous Integration**: AI will continue to permeate all aspects of our daily lives, from personal assistants and smart home devices to complex systems in healthcare, finance, and transportation. This integration will enable more efficient, personalized, and automated experiences.\\n\\n2. **Advanced Machine Learning**: We will see significant advancements in machine learning techniques, particularly in areas such as reinforcement learning, unsupervised learning, and transfer learning. These advancements will improve AI's ability to learn from fewer examples and adapt more flexibly to new and changing environments.\\n\\n3. **Ethical and Explainable AI**: As AI becomes more entrenched in critical decision-making processes, there will be a stronger emphasis on developing ethical guidelines and explainable AI systems. This will involve creating transparent models that can be understood and trusted by humans, ensuring fairness and reducing bias.\\n\\n4. **AI and Human Collaboration**: The future will see AI as a collaborator rather than a mere tool. AI systems will augment human abilities, providing insights and recommendations so that people can make better decisions and enhance creativity and productivity across various fields.\\n\\n5. **AI in Healthcare**: AI will play a transformative role in healthcare, enabling early diagnosis, personalized treatment plans, drug discovery, and efficient management of healthcare systems. This can lead to significant improvements in patient outcomes and accessibility to medical services.\\n\\n6. **Autonomous Systems**: The development of autonomous vehicles, drones, and robots will advance, impacting industries such as logistics, agriculture, and urban planning. These systems will greatly improve efficiency and safety in operations.\\n\\n7. **AI Governance and Regulation**: As AI systems grow more powerful, there will be an increasing need for regulation to ensure they are used responsibly and do not harm society. This includes addressing issues such as privacy, security, and the impact on labor markets.\\n\\n8. **AI for Sustainability**: AI will be crucial in addressing global challenges like climate change, resource management, and conservation efforts, optimizing energy use, predicting environmental changes, and developing sustainable practices.\\n\\n9. **Quantum Computing and AI**: The integration of AI with quantum computing holds the potential to solve problems previously considered intractable, speeding up computation and enhancing AI's capabilities.\\n\\n10. **AI and Creativity**: AI will increasingly be involved in creative domains, assisting with tasks such as art, music, and writing, leading to new forms of expression and collaboration between humans and machines.\\n\\nIn summary, while AI presents numerous opportunities, it also comes with challenges that society must address. Ensuring that its development is aligned with societal values will be crucial for leveraging AI's potential in a way that benefits everyone.\"\n", - " },\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"What is the future of AI?\"\n", - " },\n", - " {\n", - " \"role\": \"assistant\",\n", - " \"content\": \"Hello Paul! How can I assist you today?\"\n", - " },\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"Please tell me what's in file 123.txt.\"\n", - " }\n", - " ],\n", - " \"tools\": [\n", - " {\n", - " \"type\": \"function\",\n", - " \"function\": {\n", - " \"name\": \"help\",\n", - " \"description\": \"Return this help message.\",\n", - " \"strict\": true,\n", - " \"parameters\": {\n", - " \"type\": \"object\",\n", - " \"properties\": {},\n", - " \"additionalProperties\": false\n", - " }\n", - " }\n", - " },\n", - " {\n", - " \"type\": \"function\",\n", - " \"function\": {\n", - " \"name\": \"erase\",\n", - " \"description\": \"Erases a stored value.\",\n", - " \"strict\": true,\n", - " \"parameters\": {\n", - " \"type\": \"object\",\n", - " \"properties\": {\n", - " \"name\": {\n", - " \"type\": \"string\"\n", - " }\n", - " },\n", - " \"additionalProperties\": false,\n", - " \"required\": [\n", - " \"name\"\n", - " ]\n", - " }\n", - " }\n", - " },\n", - " {\n", - " \"type\": \"function\",\n", - " \"function\": {\n", - " \"name\": \"echo\",\n", - " \"description\": \"Return the text.\",\n", - " \"strict\": true,\n", - " \"parameters\": {\n", - " \"type\": \"object\",\n", - " \"properties\": {\n", - " \"text\": {\n", - " \"type\": \"string\"\n", - " }\n", - " },\n", - " \"additionalProperties\": false,\n", - " \"required\": [\n", - " \"text\"\n", - " ]\n", - " }\n", - " }\n", - " },\n", - " {\n", - " \"type\": \"function\",\n", - " \"function\": {\n", - " \"name\": \"get_file_contents\",\n", - " \"description\": \"Return the contents of a file.\",\n", - " \"strict\": true,\n", - " \"parameters\": {\n", - " \"type\": \"object\",\n", - " \"properties\": {\n", - " \"file_path\": {\n", - " \"type\": \"string\"\n", - " }\n", - " },\n", - " \"additionalProperties\": false,\n", - " \"required\": [\n", - " \"file_path\"\n", - " ]\n", - " }\n", - " }\n", - " }\n", - " ],\n", - " \"tool_choice\": null,\n", - " \"response_format\": {\n", - " \"type\": \"text\"\n", - " }\n", - " },\n", - " \"completion\": {\n", - " \"id\": \"chatcmpl-AQgaIFjYmKV3PUaYNUoYOKQ9LraYg\",\n", - " \"choices\": [\n", - " {\n", - " \"finish_reason\": \"stop\",\n", - " \"index\": 0,\n", - " \"logprobs\": null,\n", - " \"message\": {\n", - " \"content\": \"The future of AI is set to be transformative, with significant advancements and implications across many areas of life and industry. Here are some key trends and developments expected in the future of AI:\\n\\n1. **Widespread Integration**: AI will become deeply embedded into everyday life, enhancing technologies in sectors such as healthcare, finance, education, and entertainment. This integration will facilitate more efficient, personalized, and automated experiences.\\n\\n2. **Advanced Machine Learning**: Continuous improvements in machine learning algorithms, including deep learning, will enable AI systems to process and interpret complex data more effectively. This advancement will help AI systems become more autonomous and capable.\\n\\n3. **Ethical and Fair AI**: As AI's role grows, developing ethical guidelines and ensuring fairness will become increasingly important. Efforts will focus on minimizing bias and increasing transparency, fostering trust and acceptability.\\n\\n4. **Human-AI Collaboration**: AI will increasingly act as a collaborative partner, augmenting human abilities and enhancing creativity, decision-making, and productivity across various fields. This symbiosis will redefine how we work and interact with technology.\\n\\n5. **Healthcare Innovations**: AI is expected to revolutionize healthcare through improved diagnostics, personalized treatments, predictive analytics, and efficient management of healthcare operations. This could lead to better patient outcomes and more accessible healthcare services.\\n\\n6. **Growth of Autonomous Systems**: The development of autonomous vehicles, drones, and robotics will continue to advance, transforming industries like transportation, logistics, and agriculture by improving safety, efficiency, and sustainability.\\n\\n7. **AI for Sustainability**: AI will play a crucial role in tackling environmental challenges, optimizing resource usage, improving climate models, and promoting sustainable practices, thereby contributing to environmental conservation efforts.\\n\\n8. **Quantum Computing and AI**: The synergy between AI and quantum computing could result in unprecedented computational capabilities, leading to significant breakthroughs in fields such as cryptography, complex simulations, and material science.\\n\\n9. **Creative Applications**: AI will increasingly contribute to creative industries, aiding in the production of art, music, and literature, and providing innovative tools and mediums for artistic exploration.\\n\\n10. **Focus on Explainability**: As AI systems become more integral to decision-making, the demand for explainable AI will grow. Developing AI that can clearly articulate its decision-making processes will be crucial for building trust and ensuring accountability.\\n\\nWhile the future of AI offers immense potential, it also poses challenges—including ethical considerations, privacy issues, and potential job displacement. Navigating these challenges will require careful thought, regulation, and collaboration across various stakeholders to ensure that AI benefits society as a whole.\",\n", - " \"refusal\": null,\n", - " \"role\": \"assistant\",\n", - " \"function_call\": null,\n", - " \"tool_calls\": [\n", - " {\n", - " \"id\": \"call_hCAzGLjdWGTBMVbJDi3ZYs2Z\",\n", - " \"function\": {\n", - " \"arguments\": \"{\\\"file_path\\\":\\\"123.txt\\\"}\",\n", - " \"name\": \"get_file_contents\",\n", - " \"parsed_arguments\": {\n", - " \"file_path\": \"123.txt\"\n", - " }\n", - " },\n", - " \"type\": \"function\"\n", - " }\n", - " ],\n", - " \"parsed\": null\n", - " }\n", - " }\n", - " ],\n", - " \"created\": 1730923586,\n", - " \"model\": \"gpt-4o-2024-08-06\",\n", - " \"object\": \"chat.completion\",\n", - " \"service_tier\": null,\n", - " \"system_fingerprint\": \"fp_d54531d9eb\",\n", - " \"usage\": {\n", - " \"completion_tokens\": 17,\n", - " \"prompt_tokens\": 135,\n", - " \"total_tokens\": 152,\n", - " \"completion_tokens_details\": null,\n", - " \"prompt_tokens_details\": null\n", - " }\n", - " },\n", - " \"tool_completion_args\": {\n", - " \"model\": \"gpt-4o\",\n", - " \"messages\": [\n", - " {\n", - " \"role\": \"system\",\n", - " \"content\": \"You are a helpful assistant.\"\n", - " },\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"Hi, my name is Paul.\"\n", - " },\n", - " {\n", - " \"role\": \"assistant\",\n", - " \"content\": \"Hello Paul! How can I assist you today?\"\n", - " },\n", - " {\n", - " \"role\": \"user\",\n", - " \"content\": \"Please tell me what's in file 123.txt.\"\n", - " },\n", - " {\n", - " \"role\": \"assistant\",\n", - " \"tool_calls\": [\n", - " {\n", - " \"id\": \"call_hCAzGLjdWGTBMVbJDi3ZYs2Z\",\n", - " \"function\": {\n", - " \"arguments\": \"{\\\"file_path\\\":\\\"123.txt\\\"}\",\n", - " \"name\": \"get_file_contents\",\n", - " \"parsed_arguments\": {\n", - " \"file_path\": \"123.txt\"\n", - " }\n", - " },\n", - " \"type\": \"function\"\n", - " }\n", - " ]\n", - " },\n", - " {\n", - " \"role\": \"tool\",\n", - " \"content\": \"The purpose of life is to be happy.\",\n", - " \"tool_call_id\": \"call_hCAzGLjdWGTBMVbJDi3ZYs2Z\"\n", - " }\n", - " ],\n", - " \"response_format\": {\n", - " \"type\": \"text\"\n", - " }\n", - " }\n", - " }\n", - "}\n" - ] - } - ], - "source": [ - "from chat_driver import ChatDriver, ChatDriverConfig\n", - "from context import Context\n", - "\n", - "# When an chat driver is created, it will automatically create a context with a\n", - "# session_id. Or, if you want to use a specific session_id, you can pass it as\n", - "# an argument. This is useful for scoping this chat driver instance to an\n", - "# external identifier.\n", - "context = Context(\"simple-id-1000\")\n", - "\n", - "instructions = \"You are a famous computer scientist. You are giving a talk at a conference. You are talking about the future of AI and how it will change the world. You are asked a questions by audience members.\"\n", - "\n", - "chat_driver = ChatDriver(\n", - " ChatDriverConfig(\n", - " openai_client=async_client,\n", - " model=model,\n", - " instructions=instructions,\n", - " context=context,\n", - " ),\n", - ")\n", - "\n", - "message_event = await chat_driver.respond(\"What is the future of AI?\")\n", - "print(message_event.model_dump_json(indent=2))" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"id\": \"chatcmpl-ARRAZhqMa0AhQEzs0YAstZfa5CMm8\",\n", + " \"choices\": [\n", + " {\n", + " \"finish_reason\": \"stop\",\n", + " \"index\": 0,\n", + " \"logprobs\": null,\n", + " \"message\": {\n", + " \"content\": \"This is a test. How can I assist you further?\",\n", + " \"refusal\": null,\n", + " \"role\": \"assistant\",\n", + " \"function_call\": null,\n", + " \"tool_calls\": null\n", + " }\n", + " }\n", + " ],\n", + " \"created\": 1731102659,\n", + " \"model\": \"gpt-4o-2024-08-06\",\n", + " \"object\": \"chat.completion\",\n", + " \"service_tier\": null,\n", + " \"system_fingerprint\": \"fp_d54531d9eb\",\n", + " \"usage\": {\n", + " \"completion_tokens\": 12,\n", + " \"prompt_tokens\": 12,\n", + " \"total_tokens\": 24,\n", + " \"completion_tokens_details\": null,\n", + " \"prompt_tokens_details\": null\n", + " }\n", + "}\n" + ] + } + ], + "source": [ + "completion = client.chat.completions.create(\n", + " messages=[\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"Say this is a test\",\n", + " }\n", + " ],\n", + " model=model,\n", + ")\n", + "print(completion.model_dump_json(indent=2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Async" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### You can tell the chat driver to always return JSON\n", - "\n", - "Note: You MUST include the word \"JSON\" somewhere in your instructions. This is an OpenAI requirement for JSON return. However, note that a ChatDriver response method only returns string responses in its returned `MessageEvent` since these events are intended to be used in chat scenarios. If you want to transform it into an actual JSON object, you'll need to `json.loads(response.message)` it yourself." - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "ChatCompletion(id='chatcmpl-AQgaCid05i8dGgUHijQsvPAsMYbv4', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='This is a test.', refusal=None, role='assistant', function_call=None, tool_calls=None))], created=1730923580, model='gpt-4o-2024-08-06', object='chat.completion', service_tier=None, system_fingerprint='fp_d54531d9eb', usage=CompletionUsage(completion_tokens=5, prompt_tokens=12, total_tokens=17, completion_tokens_details=None, prompt_tokens_details=None))\n" + ] + } + ], + "source": [ + "message_event = await async_client.chat.completions.create(\n", + " messages=[\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"Say this is a test\",\n", + " }\n", + " ],\n", + " model=model,\n", + ")\n", + "print(message_event)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Streaming" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{ \"thoughts\": \"The future of AI is a topic filled with both excitement and caution, as it holds the potential for transformative impacts across various facets of society.\", \"answer\": \"The future of AI is likely to involve increased integration into everyday life, with advancements in areas such as natural language processing, computer vision, and data analysis. AI is set to enhance fields like healthcare through predictive diagnostics, personalized medicine, and robotic surgery. In transportation, autonomous vehicles will likely become more common. AI will also improve efficiencies in industries like manufacturing and logistics. However, this future will also require addressing ethical considerations, data privacy concerns, and ensuring that AI technologies are accessible and beneficial for all members of society. A key focus will be on developing fair and unbiased AI systems, and creating governance frameworks that promote responsible AI development and usage.\" }\n", - "{\n", - " \"thoughts\": \"The future of AI is a topic filled with both excitement and caution, as it holds the potential for transformative impacts across various facets of society.\",\n", - " \"answer\": \"The future of AI is likely to involve increased integration into everyday life, with advancements in areas such as natural language processing, computer vision, and data analysis. AI is set to enhance fields like healthcare through predictive diagnostics, personalized medicine, and robotic surgery. In transportation, autonomous vehicles will likely become more common. AI will also improve efficiencies in industries like manufacturing and logistics. However, this future will also require addressing ethical considerations, data privacy concerns, and ensuring that AI technologies are accessible and beneficial for all members of society. A key focus will be on developing fair and unbiased AI systems, and creating governance frameworks that promote responsible AI development and usage.\"\n", - "}\n" - ] - } - ], - "source": [ - "\n", - "from chat_driver import ChatDriver, JSON_OBJECT_RESPONSE_FORMAT, ChatDriverConfig\n", - "from context import Context\n", - "\n", - "context = Context(\"conversation-id-1002\")\n", - "instructions = 'You are a famous computer scientist. You are giving a talk at a conference. You are talking about the future of AI and how it will change the world. You are asked a questions by audience members and return your answer as valid json, like this: { \"thoughts\": , \"answer\": }.'\n", - "\n", - "chat_driver = ChatDriver(\n", - " ChatDriverConfig(\n", - " openai_client=async_client,\n", - " model=model,\n", - " instructions=instructions,\n", - " context=context,\n", - " ),\n", - ")\n", - "\n", - "message_event = await chat_driver.respond(\"What is the future of AI?\", response_format=JSON_OBJECT_RESPONSE_FORMAT)\n", - "print(message_event.message)\n", - "\n", - "print(json.dumps(json.loads(message_event.message or \"\"), indent=2))\n" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': '', 'function_call': None, 'refusal': None, 'role': 'assistant', 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': 'This', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': ' is', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': ' a', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': ' test', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': '.', 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': None, 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n", + "{'id': 'chatcmpl-AQgaEhy4ed19h72VpBu8nJBJE3g3L', 'choices': [{'delta': {'content': None, 'function_call': None, 'refusal': None, 'role': None, 'tool_calls': None}, 'finish_reason': 'stop', 'index': 0, 'logprobs': None}], 'created': 1730923582, 'model': 'gpt-4o-2024-08-06', 'object': 'chat.completion.chunk', 'service_tier': None, 'system_fingerprint': 'fp_d54531d9eb', 'usage': None}\n" + ] + } + ], + "source": [ + "stream = await async_client.chat.completions.create(\n", + " messages=[\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"Say this is a test\",\n", + " }\n", + " ],\n", + " model=model,\n", + " stream=True,\n", + ")\n", + "async for chunk in stream:\n", + " print(chunk.model_dump())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## OpenAI Helpers" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Standardized response handling" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Chat drivers can return structured responses\n", - "\n", - "Just give it a class that inherits from Pydantic BaseModel and it will return your response in that structure. Most the time, if you want this kind of thing, you probably don't want a Chat Driver. Just use the OpenAI client with the helpers above. However, in the rare case that you want to actually use the structured output to guarantee the response from the model, this is here for you. You'll need to marshal the object yourself." - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "The future of AI is both exciting and complex, with its trajectory shaped by advances in technology, ethical considerations, and societal needs. As we look ahead, several key themes emerge:\n", + "\n", + "1. **Integration and Personalization**: AI will become increasingly integrated into our daily lives, driving personalized experiences. From healthcare to education, AI systems will tailor recommendations and interventions to individual needs, optimizing outcomes across various sectors.\n", + "\n", + "2. **AI in Healthcare**: We can expect AI to revolutionize the healthcare industry by enhancing diagnostic accuracy, streamlining administrative processes, and developing personalized medicine. AI-driven tools could predict diseases, recommend treatments, and even aid in surgical procedures, ultimately improving patient care and reducing costs.\n", + "\n", + "3. **Autonomous Systems**: Autonomous vehicles, drones, and robotic systems will become more prevalent, transforming industries like transportation, logistics, and manufacturing. These systems will improve efficiency and safety while also creating new business models and opportunities.\n", + "\n", + "4. **Ethical and Responsible AI**: As AI systems become more autonomous, the demand for ethical AI frameworks will increase. Ensuring transparency, fairness, accountability, and privacy will be crucial to maintaining public trust. Developing AI systems that align with human values and societal norms will be an ongoing challenge.\n", + "\n", + "5. **AI and the Workforce**: While AI will automate certain tasks, it will also create new job opportunities and demand an upskilled workforce. It is important to focus on reskilling and education initiatives to prepare the workforce for an AI-augmented future.\n", + "\n", + "6. **AI in Climate and Sustainability**: AI will play a significant role in addressing climate change and promoting sustainability. From optimizing energy usage and improving agricultural practices to predicting environmental changes, AI could be a critical tool in creating a more sustainable future.\n", + "\n", + "7. **AI in Creativity and Arts**: AI is increasingly being used in creative fields, such as music, art, and literature. While it can augment human creativity by offering new tools and perspectives, there will be ongoing discussions about the nature of creativity and authorship.\n", + "\n", + "8. **AI Governance and Policy**: With AI's growing influence, policy and regulation will need to keep pace to address issues such as data ownership, algorithmic bias, and national security. International collaboration may be necessary to create coherent frameworks addressing these challenges.\n", + "\n", + "In summary, AI has the potential to greatly benefit society, but its development requires thoughtful consideration of ethical, social, and economic impacts. As we move forward, collaboration among technologists, policymakers, and the public will be essential to harness AI for the greater good.\n" + ] + } + ], + "source": [ + "from context import Context\n", + "from openai_client.errors import CompletionError, validate_completion\n", + "from openai_client.logging import make_completion_args_serializable, add_serializable_data\n", + "from openai_client.completion import message_content_from_completion\n", + "\n", + "context = Context(\"conversation-id-1005\")\n", + "\n", + "# We use a metadata dictionary in our helpers to store information about the\n", + "# completion request.\n", + "metadata = {}\n", + "\n", + "# This is just standard OpenAI completion request arguments.\n", + "completion_args = {\n", + " \"model\": model,\n", + " \"messages\": [\n", + " {\n", + " \"role\": \"system\",\n", + " \"content\": \"You are a famous computer scientist. You are giving a talk at a conference. You are talking about the future of AI and how it will change the world. You are asked a questions by audience members and answer thoughtfully.\",\n", + " },\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"What is the future of AI?\",\n", + " }\n", + " ],\n", + "}\n", + "\n", + "# If we these completion args to logs and metadata, though, they need to be\n", + "# serializable. We have a helper for that.\n", + "metadata[\"completion_args\"] = make_completion_args_serializable(completion_args)\n", + "\n", + "# We have helpers for validating the response and handling exceptions in a\n", + "# standardized way. These ensure that logging happens and metadata is loaded up\n", + "# properly.\n", + "try:\n", + " completion = await async_client.beta.chat.completions.parse(**completion_args)\n", + "\n", + " # This helper looks for any error-like situations (the model refuses to\n", + " # answer, content filters, incomplete responses) and throws exceptions that\n", + " # are handled by the next helper. The first argument is an identifier that\n", + " # will be used for logs and metadata namespacing.\n", + " validate_completion(completion)\n", + " logger.debug(\"completion response.\", extra=add_serializable_data(completion))\n", + " metadata[\"completion\"] = completion.model_dump()\n", + "\n", + "except Exception as e:\n", + " # This helper processes all the types of error conditions you might get from\n", + " # the OpenAI API in a standardized way.\n", + " completion_error = CompletionError(e)\n", + " print(completion_error)\n", + " print(completion_error.body)\n", + "\n", + "else:\n", + " # The message_string helper is used to extract the response from the completion\n", + " # (which can get tedious).\n", + " print(message_content_from_completion(completion))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Output types" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### JSON output" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{\"thoughts\":\"AI is rapidly advancing and its future holds great potential and considerable responsibility. As AI technologies become more integrated into society, we will see transformations across various sectors, including healthcare, transportation, education, and manufacturing. However, these advancements also come with ethical considerations and the need for responsible development.\",\"answer\":\"The future of AI is both exciting and complex. We will likely see AI becoming more autonomous, improving its ability to understand and interpret nuanced human interactions, and solving complex problems in ways that were previously unimaginable. In healthcare, AI could lead to personalized medicine and better diagnostic tools. In transportation, we'll see more autonomous vehicles that could reshape our cities and daily commutes. However, with these advancements comes the responsibility to address ethical concerns such as privacy, security, and fairness. It's crucial that as AI capabilities grow, we also develop frameworks to guide its ethical use and ensure that its benefits are distributed equitably across society.\"}\n", - "{\n", - " \"thoughts\": \"AI is rapidly advancing and its future holds great potential and considerable responsibility. As AI technologies become more integrated into society, we will see transformations across various sectors, including healthcare, transportation, education, and manufacturing. However, these advancements also come with ethical considerations and the need for responsible development.\",\n", - " \"answer\": \"The future of AI is both exciting and complex. We will likely see AI becoming more autonomous, improving its ability to understand and interpret nuanced human interactions, and solving complex problems in ways that were previously unimaginable. In healthcare, AI could lead to personalized medicine and better diagnostic tools. In transportation, we'll see more autonomous vehicles that could reshape our cities and daily commutes. However, with these advancements comes the responsibility to address ethical concerns such as privacy, security, and fairness. It's crucial that as AI capabilities grow, we also develop frameworks to guide its ethical use and ensure that its benefits are distributed equitably across society.\"\n", - "}\n" - ] - } - ], - "source": [ - "# Simple chat driver w/ structured response\n", - "\n", - "from typing import cast\n", - "from chat_driver import ChatDriver, ChatDriverConfig, LocalMessageHistoryProvider\n", - "from context import Context\n", - "from pydantic import BaseModel\n", - "\n", - "context = Context(\"structured-1000\")\n", - "\n", - "instructions = 'You are a famous computer scientist. You are giving a talk at a conference. You are talking about the future of AI and how it will change the world. You are asked a questions by audience members and return a thoughtful response.'\n", - "\n", - "class ThoughtfulResponse(BaseModel):\n", - " \"\"\"A thoughtful response to a question.\"\"\"\n", - " thoughts: str\n", - " answer: str\n", - "\n", - "chat_driver = ChatDriver(\n", - " ChatDriverConfig(\n", - " openai_client=async_client,\n", - " model=model,\n", - " instructions=instructions,\n", - " context=context,\n", - " ),\n", - ")\n", - "\n", - "# Let's clear the data from previous runs.\n", - "message_provider = cast(LocalMessageHistoryProvider, chat_driver.message_provider)\n", - "message_provider.delete_all()\n", - "\n", - "message_event = await chat_driver.respond(\"What is the future of AI?\", response_format=ThoughtfulResponse)\n", - "\n", - "# As always, the event will come back with a string message.\n", - "print(message_event.message)\n", - "\n", - "# If you really want to, you can turn the JSON string back into a Pydantic model.\n", - "thoughtful_response = ThoughtfulResponse(**json.loads(message_event.message or \"\"))\n", - "print(thoughtful_response.model_dump_json(indent=2))" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"thoughts\": \"AI is rapidly evolving and has the potential to transform virtually every industry. With advancements in machine learning, natural language processing, and robotics, AI will continue to play a crucial role in automating routine tasks and providing intelligent insights.\",\n", + " \"answer\": \"The future of AI involves deeper integration into everyday life and industry. We will likely see AI systems becoming more autonomous, sophisticated, and seamlessly integrated into systems like healthcare, transportation, and personalized services. AI's future encompasses not only technological advancements but also ethical considerations and ensuring beneficial societal impacts.\"\n", + "}\n" + ] + } + ], + "source": [ + "from context import Context\n", + "from openai_client.errors import CompletionError, validate_completion\n", + "\n", + "from openai_client.logging import make_completion_args_serializable, add_serializable_data\n", + "from openai_client.completion import message_content_dict_from_completion, JSON_OBJECT_RESPONSE_FORMAT\n", + "\n", + "context = Context(\"conversation-id-1002\")\n", + "metadata = {}\n", + "completion_args = {\n", + " \"model\": model,\n", + " \"messages\": [\n", + " {\n", + " \"role\": \"system\",\n", + " \"content\": \"You are a famous computer scientist. You are giving a talk at a conference. You are talking about the future of AI and how it will change the world. You are asked a questions by audience members and return your answer as valid JSON like { \\\"thoughts\\\": , \\\"answer\\\": }.\",\n", + " },\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"What is the future of AI?\",\n", + " }\n", + " ],\n", + " \"response_format\": JSON_OBJECT_RESPONSE_FORMAT,\n", + "}\n", + "metadata[\"completion_args\"] = make_completion_args_serializable(completion_args)\n", + "try:\n", + " completion = await async_client.beta.chat.completions.parse(**completion_args)\n", + " validate_completion(completion)\n", + " metadata[\"completion\"] = completion.model_dump()\n", + "except Exception as e:\n", + " completion_error = CompletionError(e)\n", + " metadata[\"completion_error\"] = completion_error.body\n", + " logger.error(completion_error.message, extra=add_serializable_data({\"error\": completion_error.body, \"metadata\": metadata}))\n", + "else:\n", + " message = message_content_dict_from_completion(completion)\n", + " print(json.dumps(message, indent=2))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Structured output\n", + "\n", + "Any Pydantic BaseModel can be used as the \"response_format\" and OpenAI will try to load it up for you." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### You can register functions to chat drivers\n", - "\n", - "Chat drivers will use any functions you give it as both OpenAI tool calls, and as commands.\n", - "\n", - "With each response call, you can specify what type of response you want to have... string, dictionary, or Pydantic model." - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"thoughts\": \"The future of AI is a convergence of technological advancement, ethical consideration, and societal adaptation. Its trajectory will be shaped by how well we manage its integration into daily life, ensuring it remains a tool to augment human capabilities rather than replace them entirely.\",\n", + " \"answer\": \"The future of AI is incredibly promising and multifaceted, with potential developments across various domains. In healthcare, AI may revolutionize diagnostics and personalized medicine, allowing for earlier detection of diseases and tailored treatment plans. In the realm of transportation, we can expect more sophisticated autonomous vehicles, improving safety and efficiency on our roads. Moreover, AI could enhance environmental monitoring and response, aiding in the fight against climate change by optimizing energy use and predicting environmental changes.\\n\\nHowever, as we look to this future, it is crucial to address the ethical implications of AI. This includes ensuring data privacy, reducing algorithmic bias, and contemplating the social impacts of automation on employment. Governance and regulation will play vital roles in guiding AI development to benefit society as a whole, promoting fairness, transparency, and accountability.\\n\\nUltimately, the future of AI will be defined by how humans choose to steer its development, balancing innovation with the responsibilities it entails. By fostering collaboration among technologists, ethicists, lawmakers, and the general public, we can harness AI's potential to create a more informed, just, and equitable world.\"\n", + "}\n" + ] + } + ], + "source": [ + "from context import Context\n", + "from pydantic import BaseModel\n", + "from typing import cast\n", + "from openai_client.errors import CompletionError, validate_completion\n", + "from openai_client.logging import add_serializable_data, make_completion_args_serializable\n", + "\n", + "\n", + "class Output(BaseModel):\n", + " thoughts: str\n", + " answer: str\n", + "\n", + "context = Context(\"conversation-id-1002\")\n", + "metadata = {}\n", + "completion_args = {\n", + " \"model\": model,\n", + " \"messages\": [\n", + " {\n", + " \"role\": \"system\",\n", + " \"content\": \"You are a famous computer scientist. You are giving a talk at a conference. You are talking about the future of AI and how it will change the world. You are asked a questions by audience members and return your thoughtful answer.\",\n", + " },\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"What is the future of AI?\",\n", + " }\n", + " ],\n", + " \"response_format\": Output,\n", + "}\n", + "\n", + "metadata[\"completion_args\"] = make_completion_args_serializable(completion_args)\n", + "try:\n", + " completion = await async_client.beta.chat.completions.parse(**completion_args)\n", + " validate_completion(completion)\n", + " metadata[\"completion\"] = completion.model_dump()\n", + "except Exception as e:\n", + " completion_error = CompletionError(e)\n", + " metadata[\"completion_error\"] = completion_error.body\n", + " logger.error(completion_error.message, extra=add_serializable_data({\"error\": completion_error.body, \"metadata\": metadata}))\n", + "else:\n", + " # The parsed message is in the `parsed` attribute.\n", + " output = cast(Output, completion.choices[0].message.parsed)\n", + " print(output.model_dump_json(indent=2))\n", + "\n", + " # Or you can just get the text of the message like usual.\n", + " # print(completion.choices[0].message.content)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tools" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Simple tool usage\n", + "\n", + "The OpenAI chat completions API used the idea of \"tools\" to let the model request running a local tool and then processing the output. To use it, you need to create a JSON Schema representation of the function you want to use as a tool, check the response for the model requesting to run that function, run the function, and give the model the results of the function run for a final call.\n", + "\n", + "While you can continue doing all of this yourself, our `complete_with_tool_calls` helper function makes this all easier for you.\n", + "\n", + "Instead of generating JSON schema and executing functions yourself, you can use our `ToolFunctions` class to define the functions you want to be used." + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "conversation-id-1002\n", - "\n", - "Hello Paul! How can I assist you today?\n", - "\n", - "Commands:\n", - "help(): Return this help message.\n", - "erase(name: str): Erases a stored value.\n", - "json_thing(): Return json.\n", - "get_weather(input: Input): Return the weather.\n", - "echo(text: str): Return the text.\n", - "get_file_contents(file_path: str): Return the contents of a file.\n", - "\n", - "Args:\n", - "- file_path: The path to the file.\n", - "\n", - "conversation-id-1002: Echo this.\n", - "\n", - "The content of \"123.txt\" is: \"The purpose of life is to be happy.\"\n", - "\n", - "{\"description\":\"Sunny\",\"cloud_cover\":0.2,\"temp_c\":25.0,\"temp_f\":77.0}\n" - ] - } - ], - "source": [ - "from typing import Any, cast\n", - "from chat_driver import ChatDriver, ChatDriverConfig\n", - "from context import Context, ContextProtocol\n", - "from chat_driver import LocalMessageHistoryProvider\n", - "from pydantic import BaseModel, Field\n", - "\n", - "\n", - "# When an chat driver is created, it will automatically create a context with a\n", - "# session_id. Or, if you want to use a specific session_id, you can pass it as\n", - "# an argument. This is useful for scoping this chat driver instance to an\n", - "# external identifier.\n", - "context = Context(\"conversation-id-1002\")\n", - "\n", - "\n", - "# Define tool functions for the chat driver. All functions used by the chat driver\n", - "# require a session_id as the first argument.\n", - "def get_file_contents(context: Context, file_path: str) -> str:\n", - " \"\"\"\n", - " Return the contents of a file.\n", - "\n", - " Args:\n", - " - file_path: The path to the file.\n", - " \"\"\"\n", - " return \"The purpose of life is to be happy.\"\n", - "\n", - "\n", - "def erase(context: Context, name: str) -> str:\n", - " \"\"\"Erases a stored value.\"\"\"\n", - " return f\"{context.session_id}: {name} erased\"\n", - "\n", - "def json_thing(context: Context) -> dict[str, Any]:\n", - " \"\"\"Return json.\"\"\"\n", - " return {\"key\": \"value\"}\n", - "\n", - "class Input(BaseModel):\n", - " zipcode: str\n", - "\n", - "class Weather(BaseModel):\n", - " description: str = Field(description=\"The weather description.\")\n", - " cloud_cover: float\n", - " temp_c: float\n", - " temp_f: float\n", - "\n", - "def get_weather(context: Context, input: Input) -> Weather:\n", - " \"\"\"Return the weather.\"\"\"\n", - " return Weather(description=\"Sunny\", cloud_cover=0.2, temp_c=25.0, temp_f=77.0)\n", - "\n", - "# Define the chat driver.\n", - "instructions = \"You are a helpful assistant.\"\n", - "\n", - "# Define the conversation so far (optional).\n", - "# messages: List[ChatCompletionMessageParam] = []\n", - "# localMessageHistoryConfig = LocalMessageHistoryProviderConfig(f\"./data/{context.session_id}\", messages)\n", - "# message_provider = LocalMessageHistoryProvider(localMessageHistoryConfig)\n", - "\n", - "chat_driver = ChatDriver(\n", - " ChatDriverConfig(\n", - " openai_client=async_client,\n", - " model=model,\n", - " instructions=instructions,\n", - " context=context,\n", - " # message_provider=message_provider,\n", - " commands=[erase, json_thing, get_weather], # Commands can be registered when instantiating the chat driver.\n", - " functions=[erase, json_thing, get_weather], # Functions can be registered when instantiating the chat driver.\n", - " ),\n", - ")\n", - "\n", - "# Let's clear the data from previous runs.\n", - "message_provider = cast(LocalMessageHistoryProvider, chat_driver.message_provider)\n", - "message_provider.delete_all()\n", - "\n", - "\n", - "# You can also use the `register_function` decorator to register a function.\n", - "# Remember, all functions used by the chat driver require a session_id as the\n", - "# first argument.\n", - "@chat_driver.register_function_and_command\n", - "def echo(context: ContextProtocol, text: str) -> str:\n", - " \"\"\"Return the text.\"\"\"\n", - " return f\"{context.session_id}: {text}\"\n", - "\n", - "\n", - "# You can also register functions manually.\n", - "chat_driver.register_function_and_command(get_file_contents)\n", - "\n", - "# Ok. Let's see if we got one.\n", - "print(chat_driver.context.session_id)\n", - "\n", - "# Let's see if the agent can respond.\n", - "message_event = await chat_driver.respond(\"Hi, my name is Paul.\")\n", - "print()\n", - "print(message_event.message)\n", - "\n", - "# Help command (shows command available).\n", - "message_event = await chat_driver.respond(\"/help\")\n", - "print()\n", - "print(message_event.message)\n", - "\n", - "# We can run any function or command directly.\n", - "message_event = await chat_driver.functions.echo(\"Echo this.\")\n", - "print()\n", - "print(message_event)\n", - "\n", - "# Let's see if the chat driver has the ability to run it's own registered function.\n", - "message_event = await chat_driver.respond(\"Please tell me what's in file 123.txt.\")\n", - "print()\n", - "print(message_event.message)\n", - "\n", - "# Stuctured output.\n", - "message_event = await chat_driver.respond(\"What is the weather in 90210?\", response_format=Weather)\n", - "print()\n", - "print(message_event.message)\n", - "\n", - "# Let's see the full response event.\n", - "# print()\n", - "# print(response.to_json())" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "The square of 53 is 2809.\n" + ] + } + ], + "source": [ + "from pydantic import Field\n", + "from openai_client.errors import CompletionError, validate_completion\n", + "from openai_client.tools import complete_with_tool_calls, ToolFunctions, ToolFunction\n", + "\n", + "\n", + "def square_the_number(number: int) -> int:\n", + " \"\"\"\n", + " Return the square of the number.\n", + " \"\"\"\n", + " return number * number\n", + "\n", + "\n", + "tool_functions = ToolFunctions([\n", + " ToolFunction(square_the_number),\n", + "])\n", + "\n", + "metadata = {}\n", + "completion_args = {\n", + " \"model\": model,\n", + " \"messages\": [\n", + " {\n", + " \"role\": \"system\",\n", + " \"content\": \"You are an assistant.\",\n", + " },\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"What's the square of 53?\",\n", + " }\n", + " ],\n", + "}\n", + "\n", + "try:\n", + " completion, new_messages = await complete_with_tool_calls(async_client, completion_args, tool_functions, metadata)\n", + " validate_completion(completion)\n", + "except Exception as e:\n", + " completion_error = CompletionError(e)\n", + " metadata[\"completion_error\"] = completion_error.body\n", + " print(completion_error.message)\n", + " print(completion_error.body)\n", + " print(json.dumps(metadata, indent=2))\n", + "else:\n", + " if completion:\n", + " print(completion.choices[0].message.content)\n", + " # print(json.dumps(metadata, indent=2))\n", + " else:\n", + " print(\"No completion returned.\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Structured tool inputs and output\n", + "\n", + "You can use Pydantic models as input to tool function arguments.\n", + "\n", + "You can also tell the model to respond with structured JSON or Pydantic model structures.\n", + "\n", + "Here's an example of doing both things." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Chat with a chat driver" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"thoughts\": \"The weather is typically sunny in Beverly Hills, especially considering the geographic location known for its warm climate.\",\n", + " \"answer\": \"The weather in the 90210 area (Beverly Hills) is currently sunny with a temperature of 25°C (77°F). There is minimal cloud cover, at 20%.\"\n", + "}\n" + ] + } + ], + "source": [ + "from pydantic import BaseModel\n", + "from typing import cast\n", + "from openai_client.errors import CompletionError, validate_completion\n", + "from openai_client.tools import complete_with_tool_calls, ToolFunctions, ToolFunction\n", + "\n", + "\n", + "class Input(BaseModel):\n", + " zipcode: str\n", + "\n", + "class Weather(BaseModel):\n", + " description: str = Field(description=\"The weather description.\")\n", + " cloud_cover: float\n", + " temp_c: float\n", + " temp_f: float\n", + "\n", + "def get_weather(input: Input) -> Weather:\n", + " \"\"\"Return the weather.\"\"\"\n", + " return Weather(description=\"Sunny\", cloud_cover=0.2, temp_c=25.0, temp_f=77.0)\n", + "\n", + "class Output(BaseModel):\n", + " thoughts: str\n", + " answer: str\n", + "\n", + "metadata = {}\n", + "completion_args = {\n", + " \"model\": model,\n", + " \"messages\": [\n", + " {\n", + " \"role\": \"system\",\n", + " \"content\": \"You are an assistant.\",\n", + " },\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"what is the weather in 90210?\",\n", + " }\n", + " ],\n", + " \"response_format\": Output,\n", + "}\n", + "\n", + "functions = ToolFunctions([\n", + " ToolFunction(get_weather),\n", + "])\n", + "\n", + "try:\n", + " completion, new_messages = await complete_with_tool_calls(async_client, completion_args, functions, metadata)\n", + " validate_completion(completion)\n", + "except Exception as e:\n", + " completion_error = CompletionError(e)\n", + " metadata[\"completion_error\"] = completion_error.body\n", + " print(completion_error.message)\n", + " print(completion_error.body)\n", + " print(json.dumps(metadata, indent=2))\n", + "else:\n", + " if completion:\n", + " # The parsed message is in the `parsed` attribute.\n", + " output = cast(Output, completion.choices[0].message.parsed)\n", + " print(output.model_dump_json(indent=2))\n", + " else:\n", + " print(\"No completion returned.\")\n", + "\n", + " # Or you can just get the text of the message like usual.\n", + " # print(completion.choices[0].message.content)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Tool functions with shadowed locals\n", + "\n", + "If you want to make a local function available to be run as a chat completion\n", + "tool, you can. However, oftentimes, the local function might have some extra\n", + "arguments that you don't want the model to have to fill out for you in a tool\n", + "call. In this case, you can create a wrapper function that has the same\n", + "signature as the tool call and then calls the local function with the extra\n", + "arguments filled in." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "User: /echo(\"hello world\")\n", - "Assistant: hello world\n" - ] - } - ], - "source": [ - "from chat_driver import ChatDriverConfig, ChatDriver\n", - "from context import Context\n", - "\n", - "context = Context(\"conversation-id-1006\")\n", - "\n", - "\n", - "def get_file_contents(context: Context, file_path: str) -> str:\n", - " \"\"\"Returns the contents of a file.\"\"\"\n", - " return \"The purpose of life is to be happy.\"\n", - "\n", - "\n", - "def erase(context: Context, name: str) -> str:\n", - " \"\"\"Erases a stored value.\"\"\"\n", - " return f\"{context.session_id}: {name} erased\"\n", - "\n", - "\n", - "def echo(context: Context, value: Any) -> str: # noqa: F811\n", - " \"\"\"Echos a value as a string.\"\"\"\n", - " match value:\n", - " case str():\n", - " return value\n", - " case list():\n", - " return \", \".join(map(str, value))\n", - " case dict():\n", - " return json.dumps(value)\n", - " case int() | bool() | float():\n", - " return str(value)\n", - " case _:\n", - " return str(value)\n", - "\n", - "\n", - "functions = [get_file_contents, erase, echo]\n", - "\n", - "# Define the chat driver.\n", - "chat_driver_config = ChatDriverConfig(\n", - " openai_client=async_client,\n", - " model=model,\n", - " instructions=\"You are an assistant that has access to a sand-boxed Posix shell.\",\n", - " context=context,\n", - " commands=functions,\n", - " functions=functions,\n", - ")\n", - "\n", - "chat_driver = ChatDriver(chat_driver_config)\n", - "\n", - "# Note: Look in the .data directory for the logs, message history, and other data.\n", - "\n", - "# Chat with the skill.\n", - "while True:\n", - " message = input(\"User: \")\n", - " if message == \"\":\n", - " break\n", - " print(f\"User: {message}\", flush=True)\n", - " message_event = await chat_driver.respond(message)\n", - " if message_event.metadata.get(\"error\"):\n", - " print(f\"Error: {message_event.metadata.get('error')}\")\n", - " print(message_event.to_json())\n", - " continue\n", - " # You can print the entire message event! \n", - " # print(response.to_json())\n", - " print(f\"Assistant: {message_event.message}\", flush=True)" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "The result of the fish calculation on the number 53 is: `0b101011111001` in binary representation.\n" + ] + } + ], + "source": [ + "from openai_client.errors import CompletionError, validate_completion\n", + "from openai_client.tools import complete_with_tool_calls, ToolFunctions, ToolFunction\n", + "\n", + "# Here is the real function that does the work.\n", + "def real_square_the_number(number: int, binary: bool = True) -> str:\n", + " \"\"\"\n", + " Return the square of the number.\n", + " \"\"\"\n", + " if binary:\n", + " return bin(number * number)\n", + " return str(number * number)\n", + "\n", + "\n", + "# Here is the wrapper function that whose signature will be used as the tool\n", + "# call. You can just have it calls the real function with the extra arguments\n", + "# filled in.\n", + "def fish_calc(number: int) -> str:\n", + " \"\"\"\n", + " Return the square of the number.\n", + " \"\"\"\n", + " return real_square_the_number(number, binary=True)\n", + "\n", + "# Add then just add wrapper to the tool functions you pass to the\n", + "# `complete_with_tool_calls` function. This is a way you can expose _any_\n", + "# function to be called by the model, but with the args you want the model to\n", + "# fill in!\n", + "tool_functions = ToolFunctions([\n", + " ToolFunction(fish_calc),\n", + "])\n", + "\n", + "metadata = {}\n", + "completion_args = {\n", + " \"model\": model,\n", + " \"messages\": [\n", + " {\n", + " \"role\": \"system\",\n", + " \"content\": \"You are an assistant.\",\n", + " },\n", + " {\n", + " \"role\": \"user\",\n", + " \"content\": \"Run a fish calculation on 53 for me.\",\n", + " }\n", + " ],\n", + "}\n", + "\n", + "try:\n", + " completion, new_messages = await complete_with_tool_calls(async_client, completion_args, tool_functions, metadata)\n", + " validate_completion(completion)\n", + "except Exception as e:\n", + " completion_error = CompletionError(e)\n", + " metadata[\"completion_error\"] = completion_error.body\n", + " print(completion_error.message)\n", + " print(completion_error.body)\n", + " print(json.dumps(metadata, indent=2))\n", + "else:\n", + " if completion:\n", + " print(completion.choices[0].message.content)\n", + " # print(json.dumps(metadata, indent=2))\n", + " else:\n", + " print(\"No completion returned.\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## OpenAI Chat Completion Driver (a.k.a \"chat driver\")\n", + "\n", + "### OpenAI Assistants\n", + "\n", + "The Azure/OpenAI Assistants API is newer, stateful API that splits an `assistant` from the data about a conversation `thread` that can be `run` against an `assistant`. Additionally, you can add `tools` to an assistant that enable the assistant to have more interactive capabilities. The tools currently available are:\n", + "\n", + "- *Functions*: Registering local functions with the assistant so it knows it can call them before generating a response. This is a \"hold on let me look that up for you\" kind of interaction.\n", + "- *File Search* (formerly the retrieval plugin): Attach one or more files and they will be RAG-vectorized and available as content to the assistant.\n", + "- *Code Interpreter*: Run python code in a secure sandbox.\n", + "\n", + "The Assistant API productized as OpenAI's `GPTs` product. The `GPT Builder` lets developers create and deploy GPTs assistants using a web interface.\n", + "\n", + "### Chat Driver\n", + "\n", + "But an \"assistant\" requires pretty strong \"abstraction lock-in\". This thing isn't really an assistant in the fullest sense... it's more like a \"pseudo-assistant\", but this confuses things. Let's just let the Chat Completion API be what it is and drive it as necessary as we create our assistants. Let's just wrap up the function calling bits (which, ultimately, can give you the other tools like Functions and File Search) in a simple-to-use GPT-like interface we'll call a *chat driver*.\n", + "\n", + "The chat driver is meant to be used the exact way the Chat Completions API is... just easier.\n", + "\n", + "Our chat driver provides:\n", + "\n", + "- The ability to almost magically register functions to the function tool using a `FunctionRegistry`.\n", + "- Tracking of message history.\n", + "- Management of a `Context` object that can be used for session management and supply additional context to functions.\n", + "- Some prompt creation helpers.\n", + "- Other utilities... this is just meant to be an interface you can use to forget about all the api complexities." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Here is the simplest usage of a chat driver\n", + "\n", + "Notice that a .data directory is created by default. This is where the conversation history is stored." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Chat Driver with an Assistant Drive" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "The future of AI is both exciting and complex, with the potential to profoundly transform many aspects of our lives over the coming decades. Let's explore a few key areas where AI is expected to make significant impacts:\n", + "\n", + "1. **Healthcare**: AI has the potential to revolutionize healthcare by improving diagnostics, personalizing treatment plans, and enhancing patient monitoring. Machine learning algorithms can analyze vast amounts of medical data to detect patterns that might be missed by human doctors, leading to earlier and more accurate diagnoses.\n", + "\n", + "2. **Autonomous Systems**: From self-driving cars to drones, autonomous systems powered by AI are likely to become increasingly common. These systems can improve efficiency, safety, and accessibility in transportation and logistics, while also opening up new possibilities in areas like agriculture and disaster response.\n", + "\n", + "3. **Work and Productivity**: AI can automate routine tasks, freeing up humans to focus on more complex and creative work. This has the potential to increase productivity and innovation, but also raises questions about job displacement and the future of work, necessitating thoughtful discussions on workforce retraining and the evolution of job roles.\n", + "\n", + "4. **Personalization**: AI can enhance consumer experiences by providing personalized recommendations and services, from content and product suggestions to educational platforms tailored to individual learning styles. This can lead to increased satisfaction and efficiency, but also raises issues regarding privacy and data security.\n", + "\n", + "5. **Scientific Research**: AI is becoming an indispensable tool in scientific research, capable of analyzing complex datasets more quickly and accurately than traditional methods. This can accelerate discoveries in fields such as genomics, climate modeling, and materials science, potentially leading to groundbreaking innovations.\n", + "\n", + "6. **Ethics and Fairness**: As AI becomes more integrated into society, it's crucial to address ethical considerations, including biases in AI systems and the impact on privacy and decision-making processes. Developing fair, transparent, and accountable AI systems will be essential for gaining public trust and maximizing benefits.\n", + "\n", + "7. **Global Challenges**: AI could play a crucial role in addressing global challenges like climate change, resource management, and sustainable development. By optimizing processes and offering innovative solutions, AI can contribute to making societies more resilient and adaptable.\n", + "\n", + "Overall, the future of AI promises to be a catalyst for growth and change across various domains. However, realizing this potential will require collaborative efforts from researchers, policymakers, businesses, and the public to ensure these technologies are developed and deployed in ways that are ethical and beneficial to all of humanity.\n" + ] + } + ], + "source": [ + "from chat_driver import ChatDriver, ChatDriverConfig\n", + "\n", + "instructions = \"You are a famous computer scientist. You are giving a talk at a conference. You are talking about the future of AI and how it will change the world. You are asked a questions by audience members.\"\n", + "\n", + "chat_driver = ChatDriver(\n", + " ChatDriverConfig(\n", + " openai_client=async_client,\n", + " model=model,\n", + " instructions=instructions,\n", + " ),\n", + ")\n", + "\n", + "message_event = await chat_driver.respond(\"What is the future of AI?\")\n", + "print(message_event.message)\n", + "# print(message_event.model_dump_json(indent=2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### You can register functions to chat drivers\n", + "\n", + "Chat drivers will use any functions you give it as both OpenAI tool calls, and as commands.\n", + "\n", + "With each response call, you can specify what type of response you want to have... string, dictionary, or Pydantic model." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from io import BytesIO\n", - "from typing import Any, BinaryIO\n", - "from chat_driver import ChatDriverConfig, ChatDriver, ChatDriverConfig\n", - "from context import Context\n", - "from assistant_drive import Drive, DriveConfig, IfDriveFileExistsBehavior \n", - "\n", - "session_id = \"conversation-id-1001\"\n", - "\n", - "context = Context(session_id)\n", - "\n", - "def get_drive_from_context(context):\n", - " return Drive(DriveConfig(root=f\".data/drive/{context.session_id}\"))\n", - "\n", - "def write_file_contents(context: Context, file_path: str, contents: str) -> str:\n", - " \"\"\"Writes the contents to a file.\"\"\"\n", - " drive = get_drive_from_context(context)\n", - " content_bytes: BinaryIO = BytesIO(contents.encode(\"utf-8\"))\n", - " drive.write(content_bytes, file_path, if_exists=IfDriveFileExistsBehavior.OVERWRITE)\n", - " return f\"{file_path} updated.\"\n", - "\n", - "def read_file_contents(context: Context, file_path: str) -> str:\n", - " \"\"\"Returns the contents of a file.\"\"\"\n", - " drive = get_drive_from_context(context)\n", - " with drive.open_file(file_path) as file:\n", - " return file.read().decode(\"utf-8\")\n", - "\n", - "functions = [write_file_contents, read_file_contents]\n", - "\n", - "# Define the chat driver.\n", - "chat_driver_config = ChatDriverConfig(\n", - " openai_client=async_client,\n", - " model=model,\n", - " instructions=\"You are an assistant that has access to a sand-boxed Posix shell.\",\n", - " context=context,\n", - " commands=functions,\n", - " functions=functions,\n", - ")\n", - "\n", - "chat_driver = ChatDriver(chat_driver_config)\n", - "\n", - "# Note: Look in the .data directory for the logs, message history, and other data.\n", - "\n", - "# Chat with the skill.\n", - "while True:\n", - " message = input(\"User: \")\n", - " if message == \"\":\n", - " break\n", - " print(f\"User: {message}\", flush=True)\n", - " message_event = await chat_driver.respond(message)\n", - " # You can print the entire response event! \n", - " # print(response.to_json())\n", - " print(f\"Assistant: {message_event.message}\", flush=True)" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Hello, Paul! How can I assist you today?\n", + "\n", + "Commands:\n", + "echo(text: str): Return the text.\n", + "erase(name: str): Erases a stored value.\n", + "get_file_contents(file_path: str): Return the contents of a file.\n", + "\n", + "Args:\n", + "- file_path: The path to the file.\n", + "get_weather(input: Input): Return the weather.\n", + "help(): Return this help message.\n", + "json_thing(): Return json.\n", + "\n", + "Echoing: Echo this.\n", + "\n", + "The content of \"123.txt\" is: \"The purpose of life is to be happy.\" How else can I help you today?\n", + "\n", + "{\"description\":\"Sunny\",\"cloud_cover\":0.2,\"temp_c\":25.0,\"temp_f\":77.0}\n" + ] } - ], - "metadata": { - "kernelspec": { - "display_name": ".venv", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.10" + ], + "source": [ + "from typing import Any, cast\n", + "from chat_driver import ChatDriver, ChatDriverConfig\n", + "from chat_driver import LocalMessageHistoryProvider\n", + "from pydantic import BaseModel, Field\n", + "from openai_client.tools import ToolFunctions, ToolFunction\n", + "\n", + "\n", + "# When an chat driver is created, it will automatically create a context with a\n", + "# session_id. Or, if you want to use a specific session_id, you can pass it as\n", + "# an argument. This is useful for scoping this chat driver instance to an\n", + "# external identifier.\n", + "session_id = \"conversation-id-1002\"\n", + "\n", + "\n", + "# Define tool functions for the chat driver.\n", + "def get_file_contents(file_path: str) -> str:\n", + " \"\"\"\n", + " Return the contents of a file.\n", + "\n", + " Args:\n", + " - file_path: The path to the file.\n", + " \"\"\"\n", + " return \"The purpose of life is to be happy.\"\n", + "\n", + "\n", + "def erase(name: str) -> str:\n", + " \"\"\"Erases a stored value.\"\"\"\n", + " return f\"{context.session_id}: {name} erased\"\n", + "\n", + "def json_thing() -> dict[str, Any]:\n", + " \"\"\"Return json.\"\"\"\n", + " return {\"key\": \"value\"}\n", + "\n", + "class Input(BaseModel):\n", + " zipcode: str\n", + "\n", + "class Weather(BaseModel):\n", + " description: str = Field(description=\"The weather description.\")\n", + " cloud_cover: float\n", + " temp_c: float\n", + " temp_f: float\n", + "\n", + "def get_weather(input: Input) -> Weather:\n", + " \"\"\"Return the weather.\"\"\"\n", + " return Weather(description=\"Sunny\", cloud_cover=0.2, temp_c=25.0, temp_f=77.0)\n", + "\n", + "# Define the chat driver.\n", + "instructions = \"You are a helpful assistant.\"\n", + "\n", + "all_funcs = [ get_file_contents, erase, json_thing, get_weather ]\n", + "\n", + "chat_driver = ChatDriver(\n", + " ChatDriverConfig(\n", + " openai_client=async_client,\n", + " model=model,\n", + " instructions=instructions,\n", + " # message_provider=message_provider,\n", + " commands=all_funcs, # Commands can be registered when instantiating the chat driver.\n", + " functions=all_funcs, # Functions can be registered when instantiating the chat driver.\n", + " ),\n", + ")\n", + "\n", + "# Let's clear the data from previous runs by using a custom message provider.\n", + "message_provider = cast(LocalMessageHistoryProvider, chat_driver.message_provider)\n", + "message_provider.delete_all()\n", + "\n", + "\n", + "# You can also use the `register_function` decorator to register a function.\n", + "@chat_driver.register_function_and_command\n", + "def echo(text: str) -> str:\n", + " \"\"\"Return the text.\"\"\"\n", + " return f\"Echoing: {text}\"\n", + "\n", + "\n", + "# You can also register functions manually.\n", + "chat_driver.register_function_and_command(get_file_contents)\n", + "\n", + "# Let's see if the agent can respond.\n", + "message_event = await chat_driver.respond(\"Hi, my name is Paul.\")\n", + "print()\n", + "print(message_event.message)\n", + "\n", + "# Help command (shows command available).\n", + "message_event = await chat_driver.respond(\"/help\")\n", + "print()\n", + "print(message_event.message)\n", + "\n", + "# We can run any function or command directly.\n", + "message_event = await chat_driver.functions.echo(\"Echo this.\")\n", + "print()\n", + "print(message_event)\n", + "\n", + "# Let's see if the chat driver has the ability to run it's own registered function.\n", + "message_event = await chat_driver.respond(\"Please tell me what's in file 123.txt.\")\n", + "print()\n", + "print(message_event.message)\n", + "\n", + "# Stuctured output.\n", + "message_event = await chat_driver.respond(\"What is the weather in 90210?\", response_format=Weather)\n", + "print()\n", + "print(message_event.message)\n", + "\n", + "# Let's see the full response event.\n", + "# print()\n", + "# print(response.to_json())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Chat with a chat driver" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "User: Hi!\n", + "Assistant: Hello! How can I assist you today?\n", + "User: What's the capital of America?\n", + "Assistant: The capital of the United States of America is Washington, D.C.\n", + "User: No, I meant South America.\n", + "Assistant: South America is a continent composed of multiple countries, each with its own capital. Could you specify which country's capital you're interested in within South America?\n", + "User: Mexico.\n", + "Assistant: Mexico is actually part of North America. The capital of Mexico is Mexico City.\n", + "User: Brazil.\n", + "Assistant: The capital of Brazil is Brasília.\n" + ] } + ], + "source": [ + "from chat_driver import ChatDriverConfig, ChatDriver\n", + "from context import Context\n", + "from openai_client.tools import ToolFunction, ToolFunctions\n", + "\n", + "\n", + "def get_file_contents(file_path: str) -> str:\n", + " \"\"\"Returns the contents of a file.\"\"\"\n", + " return \"The purpose of life is to be happy.\"\n", + "\n", + "\n", + "def erase(name: str) -> str:\n", + " \"\"\"Erases a stored value.\"\"\"\n", + " return f\"{session_id}: {name} erased\"\n", + "\n", + "\n", + "def echo(value: str) -> str: # noqa: F811\n", + " \"\"\"Echos a value as a string.\"\"\"\n", + " match value:\n", + " case str():\n", + " return value\n", + " case list():\n", + " return \", \".join(map(str, value))\n", + " case dict():\n", + " return json.dumps(value)\n", + " case int() | bool() | float():\n", + " return str(value)\n", + " case _:\n", + " return str(value)\n", + "\n", + "# Define the chat driver.\n", + "chat_driver_config = ChatDriverConfig(\n", + " openai_client=async_client,\n", + " model=model,\n", + " instructions=\"You are an assistant that has access to a sand-boxed Posix shell.\",\n", + " commands=[ get_file_contents, erase, echo ],\n", + " functions=[ get_file_contents, erase, echo ],\n", + ")\n", + "\n", + "chat_driver = ChatDriver(chat_driver_config)\n", + "\n", + "# Note: Look in the .data directory for the logs, message history, and other data.\n", + "\n", + "# Chat with the skill.\n", + "while True:\n", + " message = input(\"User: \")\n", + " if message == \"\":\n", + " break\n", + " print(f\"User: {message}\", flush=True)\n", + " message_event = await chat_driver.respond(message)\n", + " if message_event.metadata.get(\"error\"):\n", + " print(f\"Error: {message_event.metadata.get('error')}\")\n", + " print(message_event.to_json())\n", + " continue\n", + " # You can print the entire message event! \n", + " # print(response.to_json())\n", + " print(f\"Assistant: {message_event.message}\", flush=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Chat Driver with an Assistant Drive" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from io import BytesIO\n", + "from typing import Any, BinaryIO\n", + "from chat_driver import ChatDriverConfig, ChatDriver, ChatDriverConfig\n", + "from context import Context\n", + "from assistant_drive import Drive, DriveConfig, IfDriveFileExistsBehavior \n", + "\n", + "def get_drive_from_context(context):\n", + " return Drive(DriveConfig(root=f\".data/drive/{context.session_id}\"))\n", + "\n", + "def write_file_contents(file_path: str, contents: str) -> str:\n", + " \"\"\"Writes the contents to a file.\"\"\"\n", + " drive = get_drive_from_context(context)\n", + " content_bytes: BinaryIO = BytesIO(contents.encode(\"utf-8\"))\n", + " drive.write(content_bytes, file_path, if_exists=IfDriveFileExistsBehavior.OVERWRITE)\n", + " return f\"{file_path} updated.\"\n", + "\n", + "def read_file_contents(file_path: str) -> str:\n", + " \"\"\"Returns the contents of a file.\"\"\"\n", + " drive = get_drive_from_context(context)\n", + " with drive.open_file(file_path) as file:\n", + " return file.read().decode(\"utf-8\")\n", + "\n", + "functions = [write_file_contents, read_file_contents]\n", + "\n", + "# Define the chat driver.\n", + "chat_driver_config = ChatDriverConfig(\n", + " openai_client=async_client,\n", + " model=model,\n", + " instructions=\"You are an assistant that has access to a sand-boxed Posix shell.\",\n", + " commands=functions,\n", + " functions=functions,\n", + ")\n", + "\n", + "chat_driver = ChatDriver(chat_driver_config)\n", + "\n", + "# Note: Look in the .data directory for the logs, message history, and other data.\n", + "\n", + "# Chat with the skill.\n", + "while True:\n", + " message = input(\"User: \")\n", + " if message == \"\":\n", + " break\n", + " print(f\"User: {message}\", flush=True)\n", + " message_event = await chat_driver.respond(message)\n", + " # You can print the entire response event! \n", + " # print(response.to_json())\n", + " print(f\"Assistant: {message_event.message}\", flush=True)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" }, - "nbformat": 4, - "nbformat_minor": 2 + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.10" + } + }, + "nbformat": 4, + "nbformat_minor": 2 } diff --git a/libraries/python/skills/skill-library/skill_library/__init__.py b/libraries/python/skills/skill-library/skill_library/__init__.py index c2538675..afe9eecb 100644 --- a/libraries/python/skills/skill-library/skill_library/__init__.py +++ b/libraries/python/skills/skill-library/skill_library/__init__.py @@ -1,12 +1,17 @@ +import logging + from context import Context from .assistant import Assistant from .routine import FunctionRoutine, InstructionRoutine, ProgramRoutine, RoutineTypes -from .skill import Skill +from .skill import EmitterType, Skill + +logger = logging.getLogger(__name__) __all__ = [ "Assistant", "Context", + "EmitterType", "FunctionRoutine", "InstructionRoutine", "ProgramRoutine", diff --git a/libraries/python/skills/skill-library/skill_library/actions.py b/libraries/python/skills/skill-library/skill_library/actions.py new file mode 100644 index 00000000..8cbd0e20 --- /dev/null +++ b/libraries/python/skills/skill-library/skill_library/actions.py @@ -0,0 +1,232 @@ +import ast +import inspect +from dataclasses import dataclass +from typing import Any, Callable + + +@dataclass +class Parameter: + """ + Tool functions are described by their parameters. This dataclass + describes a single parameter of a tool function. + """ + + name: str + type: Any + description: str | None + default_value: Any | None = None + + +class Action: + """ + A tool function is a Python function that can be called as a tool from the + chat completion API. This class wraps a function so you can generate it's + JSON schema for the chat completion API, execute it with arguments, and + generate a usage string (for help messages) + """ + + def __init__(self, fn: Callable, name: str | None = None, description: str | None = None) -> None: + self.fn = fn + self.name = name or fn.__name__ + self.description = description or inspect.getdoc(fn) or self.name.replace("_", " ").title() + + def parameters(self, exclude: list[str] = []) -> list[Parameter]: + """ + This function's parameters and their default values. + """ + parameters = dict(inspect.signature(self.fn).parameters) + for param_name in exclude: + del parameters[param_name] + return [ + Parameter( + name=param_name, + type=param.annotation, + description=None, # param.annotation.description, + default_value=param.default, + ) + for param_name, param in parameters.items() + ] + + def usage(self) -> str: + """ + A usage string for this function. This can be used in help messages. + """ + name = self.name + param_usages = [] + for param in self.parameters(): + param_type = param.type + try: + param_type = param.type.__name__ + except AttributeError: + param_type = param.type + usage = f"{param.name}: {param_type}" + if param.default_value is not inspect.Parameter.empty: + if isinstance(param.default_value, str): + usage += f' = "{param.default_value}"' + else: + usage += f" = {param.default_value}" + param_usages.append(usage) + + description = self.description + return f"{name}({', '.join(param_usages)}): {description}" + + async def execute(self, *args, **kwargs) -> Any: + """ + Run this function, and return its value. If the function is a coroutine, + it will be awaited. If string_response is True, the response will be + converted to a string. + """ + result = self.fn(*args, **kwargs) + if inspect.iscoroutine(result): + result = await result + return result + + +class ActionHandler: + def __init__(self, actions: "Actions") -> None: + self.actions = actions + + def __getattr__(self, name: str) -> Callable: + """Makes registered functions accessible as attributes of the functions object.""" + if name not in self.actions.action_map: + raise AttributeError(f"'FunctionHandler' object has no attribute '{name}'") + + async def wrapper(*args, **kwargs) -> Any: + return await self.actions.execute_action(name, args, kwargs) + + return wrapper + + +class Actions: + """ + A set of tool functions that can be called from the Chat Completions API. + Pass this into the `complete_with_tool_calls` helper function to run a full + tool-call completion against the API. + """ + + def __init__(self, actions: list[Action] | None = None, with_help: bool = False) -> None: + # Set up function map. + self.action_map = {} + if actions: + for function in actions: + self.action_map[function.name] = function + + # A help message can be generated for the function map. + if with_help: + self.action_map["help"] = Action(self.help) + + # This allows actions to be called as attributes. + self.functions = ActionHandler(self) + + def help(self) -> str: + """Return this help message.""" + + usage = [f"{command.usage()}" for command in self.action_map.values()] + usage.sort() + return "Commands:\n" + "\n".join(usage) + + def add_function(self, function: Callable, name: str | None = None, description: str | None = None) -> None: + """Register a function as an action.""" + if not name: + name = function.__name__ + self.action_map[name] = Action(function, name, description) + + def add_functions(self, functions: list[Callable]) -> None: + """Register a list of functions as actions.""" + for function in functions: + self.add_function(function) + + def has_action(self, name: str) -> bool: + return name in self.action_map + + def get_action(self, name: str) -> Action | None: + return self.action_map.get(name) + + def get_actions(self) -> list[Action]: + return [function for function in self.action_map.values()] + + async def execute_action( + self, name: str, args: tuple = (), kwargs: dict[str, Any] = {}, string_response: bool = False + ) -> Any: + """ + Run a function from the ToolFunctions list by name. If string_response + is True, the function return value will be converted to a string. + """ + function = self.get_action(name) + if not function: + raise ValueError(f"Function {name} not found in registry.") + return await function.execute(string_response, *args, **kwargs) + + async def execute_action_string(self, function_string: str, string_response: bool = False) -> Any: + """Parse a function string and execute the function.""" + try: + function, args, kwargs = self.parse_action_string(function_string) + except ValueError as e: + raise ValueError(f"{e}. Type: `/help` for more information.") + if not function: + raise ValueError("Function not found in registry. Type: `/help` for more information.") + return await function.execute(string_response, *args, **kwargs) + + def parse_action_string(self, action_string: str) -> tuple[Action | None, list[Any], dict[str, Any]]: + """Parse a function call string into a function and its arguments.""" + + # As a convenience, remove any leading slashes. + action_string = action_string.lstrip("/") + + # As a convenience, add parentheses if they are missing. + if " " not in action_string and "(" not in action_string: + action_string += "()" + + # Parse the string into an AST (Abstract Syntax Tree) + try: + tree = ast.parse(action_string) + except SyntaxError: + raise ValueError("Invalid function call. Please check your syntax.") + + # Ensure the tree contains exactly one expression (the function call) + if not (isinstance(tree, ast.Module) and len(tree.body) == 1 and isinstance(tree.body[0], ast.Expr)): + raise ValueError("Expected a single function call.") + + # The function call is stored as a `Call` node within the expression + call_node = tree.body[0].value + if not isinstance(call_node, ast.Call): + raise ValueError("Invalid function call. Please check your syntax.") + + # Extract the function name + if isinstance(call_node.func, ast.Name): + action_name = call_node.func.id + else: + raise ValueError("Unsupported function format. Please check your syntax.") + + # Helper function to evaluate AST nodes to their Python equivalent + def eval_node(node): + if isinstance(node, ast.Constant): + return node.value + elif isinstance(node, ast.List): + return [eval_node(elem) for elem in node.elts] + elif isinstance(node, ast.Tuple): + return tuple(eval_node(elem) for elem in node.elts) + elif isinstance(node, ast.Dict): + return {eval_node(key): eval_node(value) for key, value in zip(node.keys, node.values)} + elif isinstance(node, ast.Name): + return node.id # This can return variable names, but we assume they're constants + elif isinstance(node, ast.BinOp): # Handling arithmetic expressions + return eval(compile(ast.Expression(node), filename="", mode="eval")) + elif isinstance(node, ast.Call): + raise ValueError("Nested function calls are not supported.") + else: + raise ValueError(f"Unsupported AST node type: {type(node).__name__}") + + # Extract positional arguments + args = [eval_node(arg) for arg in call_node.args] + + # Extract keyword arguments + kwargs = {} + for kw in call_node.keywords: + kwargs[kw.arg] = eval_node(kw.value) + + action = self.get_action(action_name) + if not action: + return None, [], {} + + return action, args, kwargs diff --git a/libraries/python/skills/skill-library/skill_library/assistant.py b/libraries/python/skills/skill-library/skill_library/assistant.py index a6b5cb1b..f8b8d3da 100644 --- a/libraries/python/skills/skill-library/skill_library/assistant.py +++ b/libraries/python/skills/skill-library/skill_library/assistant.py @@ -9,10 +9,12 @@ ChatDriver, ChatDriverConfig, ) +from chat_driver.local_message_history_provider import LocalMessageHistoryProvider, LocalMessageHistoryProviderConfig from events import BaseEvent, EventProtocol from openai.types.chat.completion_create_params import ( ResponseFormat, ) +from openai_client.messages import format_with_liquid from .run_context import RunContext from .skill import Skill @@ -23,17 +25,27 @@ class Assistant: def __init__( self, name, + assistant_id: str | None, + drive_root: PathLike | None, + metadrive_drive_root: PathLike | None, chat_driver_config: ChatDriverConfig, - session_id: str | None = None, skills: list[Skill] = [], - drive_root: PathLike | None = None, - metadrive_root: PathLike | None = None, ) -> None: self.skill_registry: SkillRegistry = SkillRegistry() self.name = name + + if not assistant_id: + assistant_id = str(uuid4()) + + # Configure the assistant chat interface. + if chat_driver_config.message_provider is None: + chat_driver_config.message_provider = LocalMessageHistoryProvider( + LocalMessageHistoryProviderConfig(session_id=assistant_id, formatter=format_with_liquid) + ) self.chat_driver = self._register_chat_driver(chat_driver_config) + # Set up the assistant event queue. self._event_queue = asyncio.Queue() # Async queue for events self._stopped = asyncio.Event() # Event to signal when the assistant has stopped if skills: @@ -44,7 +56,7 @@ def __init__( # assistant-specific data and not for general data storage. self.drive: Drive = Drive( DriveConfig( - root=drive_root or f".data/{session_id}/assistant", + root=drive_root or f".data/{assistant_id}/assistant", default_if_exists_behavior=IfDriveFileExistsBehavior.OVERWRITE, ) ) @@ -55,11 +67,11 @@ def __init__( # driver commands and functions and all skill actions and routines that # are run by the assistant. self.run_context = RunContext( - session_id=session_id or str(uuid4()), + session_id=assistant_id or str(uuid4()), assistant_drive=self.drive, emit=self._emit, run_routine=self.skill_registry.run_routine_by_name, - drive_root=metadrive_root, + metadata_drive_root=metadrive_drive_root, ) ###################################### @@ -118,7 +130,7 @@ async def put_message(self, message: str) -> None: send the message to the chat driver. """ # If a routine is running, send the message to the routine. - if self.run_context.routine_stack.peek(): + if await self.run_context.routine_stack.peek(): await self.step_active_routine(message) else: # Otherwise, send the message to the chat driver. @@ -141,10 +153,6 @@ def _register_chat_driver(self, chat_driver_config: ChatDriverConfig) -> ChatDri "Available routines and their available vars: {routines}. " ) - # Overwrite whatever run context was passed in with this assistant's - # actual context. - config.context = self.run_context - chat_functions = ChatFunctions(self) functions = [chat_functions.list_routines, chat_functions.run_routine] config.commands = functions @@ -184,10 +192,6 @@ def register_skills(self, skills: list[Skill]) -> None: that an assistant uses at the same time so dependencies can be loaded in the correct order.""" self.skill_registry.register_all_skills(skills) - if self.chat_driver: - for skill in skills: - self.chat_driver.register_functions(skill.get_chat_functions()) - self.chat_driver.register_commands(skill.get_chat_commands()) # def list_actions(self, context: Context) -> list[str]: # """Lists all the actions the assistant is able to perform.""" @@ -217,11 +221,11 @@ class ChatFunctions: def __init__(self, assistant: Assistant) -> None: self.assistant = assistant - def list_routines(self, context: RunContext) -> list[str]: + def list_routines(self) -> list[str]: """Lists all the routines available in the assistant.""" return self.assistant.list_routines() - async def run_routine(self, context: RunContext, name: str, vars: dict[str, Any] | None = None) -> Any: + async def run_routine(self, name: str, vars: dict[str, Any] | None = None) -> Any: """ Run an assistant routine. """ diff --git a/libraries/python/skills/skill-library/skill_library/run_context.py b/libraries/python/skills/skill-library/skill_library/run_context.py index e8e7e390..4c14fbff 100644 --- a/libraries/python/skills/skill-library/skill_library/run_context.py +++ b/libraries/python/skills/skill-library/skill_library/run_context.py @@ -25,7 +25,7 @@ def __init__( assistant_drive: Drive, emit: Callable[[EventProtocol], None], run_routine: Callable[["RunContext", str, Optional[dict[str, Any]]], Coroutine[Any, Any, Any]], - drive_root: PathLike | None = None, + metadata_drive_root: PathLike | None = None, ) -> None: # A session id is useful for maintaining consistent session state across all # consumers of this context. For example, a session id can be set in an @@ -53,7 +53,7 @@ def __init__( # needs to be persisted across different calls to the assistant. self.metadrive: Drive = Drive( DriveConfig( - root=drive_root or f".data/{session_id}/.assistant", + root=metadata_drive_root or f".data/{session_id}/.assistant", default_if_exists_behavior=IfDriveFileExistsBehavior.OVERWRITE, ) ) diff --git a/libraries/python/skills/skill-library/skill_library/skill.py b/libraries/python/skills/skill-library/skill_library/skill.py index b1e312fb..9efc133a 100644 --- a/libraries/python/skills/skill-library/skill_library/skill.py +++ b/libraries/python/skills/skill-library/skill_library/skill.py @@ -1,12 +1,19 @@ +import logging from typing import Any, Callable -from chat_driver import TEXT_RESPONSE_FORMAT, ChatDriver, ChatDriverConfig, ContextProtocol -from events import BaseEvent -from function_registry import FunctionRegistry +from chat_driver import TEXT_RESPONSE_FORMAT, ChatDriver, ChatDriverConfig +from events import BaseEvent, EventProtocol from openai.types.chat.completion_create_params import ResponseFormat +from .actions import Actions from .routine import RoutineTypes +EmitterType = Callable[[EventProtocol], None] + + +def log_emitter(event: EventProtocol) -> None: + logging.info(event) + class Skill: """ @@ -18,10 +25,9 @@ def __init__( self, name: str, description: str, - context: ContextProtocol, - chat_driver_config: ChatDriverConfig | None = None, skill_actions: list[Callable] = [], # Functions to be registered as skill actions. routines: list[RoutineTypes] = [], + chat_driver_config: ChatDriverConfig | None = None, ) -> None: # A skill should have a short name so that user commands can be routed # to them efficiently. @@ -46,16 +52,17 @@ def __init__( self.openai_client = chat_driver_config.openai_client if chat_driver_config else None # Register all provided actions with the action registry. - self.action_registry = FunctionRegistry(context, skill_actions) + self.actions = Actions() + self.actions.add_functions(skill_actions) # Also, register any commands provided by the chat driver. All # commands will be available to the skill. if self.chat_driver: - self.action_registry.register_functions(self.chat_driver.get_commands()) + self.actions.add_functions(self.chat_driver.get_commands()) # Make actions available to be called as attributes from the skill # directly. - self.actions = self.action_registry.functions + self.actions = self.actions.functions async def respond( self, @@ -75,10 +82,10 @@ async def respond( ) def get_actions(self) -> list[Callable]: - return [function.fn for function in self.action_registry.get_functions()] + return [function.fn for function in self.actions.get_actions()] def list_actions(self) -> list[str]: - return self.action_registry.list_functions() + return [action.name for action in self.actions.get_actions()] def add_routine(self, routine: RoutineTypes) -> None: """ @@ -98,18 +105,6 @@ def list_routines(self) -> list[str]: def has_routine(self, name: str) -> bool: return name in self.routines - # Convenience methods for getting the chat driver's functions and commands. - - def get_chat_functions(self) -> list[Callable]: - if not self.chat_driver: - return [] - return self.chat_driver.get_functions() - - def get_chat_commands(self) -> list[Callable]: - if not self.chat_driver: - return [] - return self.chat_driver.get_commands() - def __str__(self) -> str: return f"{self.name} - {self.description}" diff --git a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_content.py b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_content.py index 5c6b39ad..558607da 100644 --- a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_content.py +++ b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_content.py @@ -1,13 +1,13 @@ -from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver import ChatDriver, ChatDriverConfig from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider -from chat_driver.message_formatter import liquid_format from openai import AsyncAzureOpenAI, AsyncOpenAI +from openai_client.messages import format_with_liquid from ..document_skill import Outline, Paper async def draft_content( - context: ContextProtocol, + session_id: str, open_ai_client: AsyncOpenAI | AsyncAzureOpenAI, chat_history: str, attachments: list, @@ -16,7 +16,7 @@ async def draft_content( user_feedback: str | None = None, decision: str | None = None, ): - history = InMemoryMessageHistoryProvider(formatter=liquid_format) + history = InMemoryMessageHistoryProvider(formatter=format_with_liquid) if decision == "[ITERATE]": history.append_system_message( @@ -68,7 +68,6 @@ async def draft_content( history.append_system_message("{{content}}", {"content": content}) config = ChatDriverConfig( - context=context, openai_client=open_ai_client, model="gpt-3.5-turbo", message_provider=history, diff --git a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_outline.py b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_outline.py index 96d7a7c5..6c8b4a40 100644 --- a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_outline.py +++ b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_outline.py @@ -1,20 +1,20 @@ -from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver import ChatDriver, ChatDriverConfig from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider -from chat_driver.message_formatter import liquid_format from openai import AsyncAzureOpenAI, AsyncOpenAI +from openai_client.messages import format_with_liquid from ..document_skill import Outline async def draft_outline( - context: ContextProtocol, + session_id: str, open_ai_client: AsyncOpenAI | AsyncAzureOpenAI, chat_history: str, attachments: list, outline_versions: list[Outline] = [], user_feedback: str | None = None, ): - history = InMemoryMessageHistoryProvider(formatter=liquid_format) + history = InMemoryMessageHistoryProvider(formatter=format_with_liquid) history.append_system_message( ( @@ -46,7 +46,6 @@ async def draft_outline( ) config = ChatDriverConfig( - context=context, openai_client=open_ai_client, model="gpt-3.5-turbo", message_provider=history, diff --git a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_outline_decision.py b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_outline_decision.py index a8ef2fa6..7b36e64b 100644 --- a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_outline_decision.py +++ b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_outline_decision.py @@ -1,13 +1,13 @@ -from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver import ChatDriver, ChatDriverConfig from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider -from chat_driver.message_formatter import liquid_format from openai import AsyncAzureOpenAI, AsyncOpenAI +from openai_client.messages import format_with_liquid from ..document_skill import Outline, Paper async def get_user_feedback_for_outline_decision( - context: ContextProtocol, + session_id: str, open_ai_client: AsyncOpenAI | AsyncAzureOpenAI, chat_history: str, outline_versions: list[Outline] = [], @@ -15,7 +15,7 @@ async def get_user_feedback_for_outline_decision( user_feedback: str | None = None, outline: bool = False, ): - history = InMemoryMessageHistoryProvider(formatter=liquid_format) + history = InMemoryMessageHistoryProvider(formatter=format_with_liquid) if outline: history.append_system_message( @@ -65,7 +65,6 @@ async def get_user_feedback_for_outline_decision( ) config = ChatDriverConfig( - context=context, openai_client=open_ai_client, model="gpt-3.5-turbo", message_provider=history, diff --git a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_page_decision.py b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_page_decision.py index 7a10e00d..364d514c 100644 --- a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_page_decision.py +++ b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_page_decision.py @@ -1,13 +1,13 @@ -from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver import ChatDriver, ChatDriverConfig from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider -from chat_driver.message_formatter import liquid_format from openai import AsyncAzureOpenAI, AsyncOpenAI +from openai_client.messages import format_with_liquid from ..document_skill import Outline, Paper async def get_user_feedback_for_page_decision( - context: ContextProtocol, + session_id: str, open_ai_client: AsyncOpenAI | AsyncAzureOpenAI, chat_history: str, outline_versions: list[Outline] = [], @@ -15,7 +15,7 @@ async def get_user_feedback_for_page_decision( user_feedback: str | None = None, outline: bool = False, ): - history = InMemoryMessageHistoryProvider(formatter=liquid_format) + history = InMemoryMessageHistoryProvider(formatter=format_with_liquid) if outline: history.append_system_message( @@ -65,7 +65,6 @@ async def get_user_feedback_for_page_decision( ) config = ChatDriverConfig( - context=context, openai_client=open_ai_client, model="gpt-3.5-turbo", message_provider=history, diff --git a/libraries/python/skills/skills/document-skill/document_skill/document_skill.py b/libraries/python/skills/skills/document-skill/document_skill/document_skill.py index 063bc5f2..ce74568a 100644 --- a/libraries/python/skills/skills/document-skill/document_skill/document_skill.py +++ b/libraries/python/skills/skills/document-skill/document_skill/document_skill.py @@ -1,10 +1,10 @@ -from chat_driver import ChatDriverConfig, ContextProtocol -from context import Context +from chat_driver import ChatDriverConfig +from openai import AsyncAzureOpenAI, AsyncOpenAI from pydantic import BaseModel # temp to have something to experiment with -from skill_library import RoutineTypes, Skill +from skill_library import EmitterType, RoutineTypes, Skill from skill_library.routine import InstructionRoutine, ProgramRoutine -from .chat_drivers import draft_content, draft_outline, get_user_feedback_decision +from .chat_drivers import draft_content, draft_outline NAME = "document_skill" DESCRIPTION = "Anything related to documents - creation, edit, translation" @@ -31,7 +31,7 @@ class Paper(BaseModel): class DocumentSkillContext: - def __init__(self, context: ContextProtocol) -> None: + def __init__(self) -> None: # TODO: Pull in all this state from a Drive. self.chat_history: str = "" self.attachments_list: list[Attachment] = [] @@ -41,14 +41,13 @@ def __init__(self, context: ContextProtocol) -> None: class DocumentSkill(Skill): def __init__( - self, - context: ContextProtocol, - chat_driver_config: ChatDriverConfig, + self, emit: EmitterType, chat_driver_config: ChatDriverConfig, openaai_client: AsyncAzureOpenAI | AsyncOpenAI ) -> None: - self.document_skill_context: DocumentSkillContext = DocumentSkillContext(context) + self.openai_client = openaai_client + self.document_skill_context: DocumentSkillContext = DocumentSkillContext() actions = [ - self.ask_user, + # self.ask_user, self.draft_content, self.draft_outline, self.get_user_feedback_decision, @@ -65,7 +64,6 @@ def __init__( super().__init__( name=NAME, description=DESCRIPTION, - context=context, chat_driver_config=chat_driver_config, skill_actions=actions, routines=routines, @@ -102,13 +100,13 @@ def template_example_routine(self) -> ProgramRoutine: ################################## async def draft_content( self, - context: ContextProtocol, + session_id: str, decision: str | None = None, user_feedback: str | None = None, ) -> str: response = await draft_content( - context=context, - open_ai_client=self.open_ai_client, + session_id=session_id, + open_ai_client=self.openai_client, chat_history=self.document_skill_context.chat_history, attachments=self.document_skill_context.attachments_list, outline_versions=self.document_skill_context.outline_versions, @@ -119,11 +117,11 @@ async def draft_content( return response.message or "" async def draft_outline( - self, context: ContextProtocol, decision: str | None = None, user_feedback: str | None = None + self, session_id: str, decision: str | None = None, user_feedback: str | None = None ) -> str: response = await draft_outline( - context=context, - open_ai_client=self.open_ai_client, + session_id=session_id, + open_ai_client=self.openai_client, chat_history=self.document_skill_context.chat_history, attachments=self.document_skill_context.attachments_list, outline_versions=self.document_skill_context.outline_versions, @@ -131,10 +129,10 @@ async def draft_outline( ) return response.message or "" - async def get_user_feedback_decision(self, context: ContextProtocol, user_feedback: str, outline: bool) -> str: + async def get_user_feedback_decision(self, session_id: str, user_feedback: str, outline: bool) -> str: response = await get_user_feedback_decision( - context=context, - open_ai_client=self.open_ai_client, + session_id=session_id, + open_ai_client=self.openai_client, chat_history=self.document_skill_context.chat_history, attachments=self.document_skill_context.attachments_list, outline_versions=self.document_skill_context.outline_versions, @@ -144,7 +142,7 @@ async def get_user_feedback_decision(self, context: ContextProtocol, user_feedba ) return response.message or "" - async def routine(self, context: ContextProtocol): + async def routine(self, session_id: str): # Define these vars here to make the following routine look more like a PROGRAM routine. document_skill = self @@ -154,20 +152,18 @@ async def ask_user(question: str) -> str: # Routine. decision = "[ITERATE]" while decision == "[ITERATE]": - await document_skill.draft_outline(context, user_feedback=user_feedback) + await document_skill.draft_outline(session_id, user_feedback=user_feedback) user_feedback = await ask_user("This look good?") - decision = await document_skill.get_user_feedback_decision(context, user_feedback, outline=True) + decision = await document_skill.get_user_feedback_decision(user_feedback, outline=True) if decision == "[QUIT]": exit() - await document_skill.draft_content(context) + await document_skill.draft_content(session_id) user_feedback = await ask_user("This look good?") - decision = await document_skill.get_user_feedback_decision(context, user_feedback, outline=False) + decision = await document_skill.get_user_feedback_decision(session_id, user_feedback, outline=False) while decision != "[QUIT]": - content = await document_skill.draft_content( - context, user_feedback=user_feedback, chat_history=[], decision=decision - ) + content = await document_skill.draft_content(session_id, user_feedback=user_feedback, decision=decision) decision, user_feedback = await document_skill.get_user_feedback_decision( - context, user_feedback, outline=False + session_id, user_feedback, outline=False ) return content diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/artifact.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/artifact.py index 44ef224f..ab978ceb 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/artifact.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/artifact.py @@ -5,11 +5,11 @@ import logging from typing import Any, Literal, TypeVar, Union, get_args, get_origin, get_type_hints +from openai import AsyncAzureOpenAI, AsyncOpenAI from pydantic import BaseModel, ValidationError, create_model from form_filler_skill.base_model_llm import BaseModelLLM - from .chat_drivers.fix_artifact_error import fix_artifact_error from .message import Conversation, ConversationMessageType, Message @@ -28,7 +28,12 @@ class Artifact: get_artifact_for_prompt, get_schema_for_prompt, and get_failed_fields. """ - def __init__(self, input_artifact: BaseModel, max_artifact_field_retries: int = 2) -> None: + def __init__( + self, + openai_client: AsyncOpenAI | AsyncAzureOpenAI, + input_artifact: BaseModel, + max_artifact_field_retries: int = 2, + ) -> None: """ Initialize the Artifact plugin with the given Pydantic base model. @@ -37,6 +42,8 @@ def __init__(self, input_artifact: BaseModel, max_artifact_field_retries: int = max_artifact_field_retries (int): The maximum number of times to retry updating a field in the artifact """ + self.openai_client = openai_client + self.max_artifact_field_retries = max_artifact_field_retries self.original_schema = input_artifact.model_json_schema() @@ -113,13 +120,8 @@ async def update_artifact(self, field_name: str, field_value: Any) -> tuple[bool try: # Check if there have been too many previous failed attempts to # update the field. - if ( - len(self.failed_artifact_fields.get(field_name, [])) - >= self.max_artifact_field_retries - ): - logger.warning( - f"Updating field {field_name} has failed too many times. Skipping." - ) + if len(self.failed_artifact_fields.get(field_name, [])) >= self.max_artifact_field_retries: + logger.warning(f"Updating field {field_name} has failed too many times. Skipping.") return False, conversation # Attempt to update the artifact. @@ -142,16 +144,12 @@ async def update_artifact(self, field_name: str, field_value: Any) -> tuple[bool logger.warning(f"Error updating field {field_name}: {e}. Retrying...") # Handle update error will increment failed_artifact_fields, once it has failed # greater than self.max_artifact_field_retries the field will be skipped and the loop will break - success, new_field_value = await self._handle_update_error( - field_name, field_value, conversation, e - ) + success, new_field_value = await self._handle_update_error(field_name, field_value, conversation, e) # The agent has successfully fixed the field. if success: if new_field_value is not None: - logger.info( - f"Agent successfully fixed field {field_name}. New value: {new_field_value}" - ) + logger.info(f"Agent successfully fixed field {field_name}. New value: {new_field_value}") field_value = new_field_value else: # This is the case where the agent has decided to resume the conversation. @@ -169,9 +167,7 @@ def get_artifact_for_prompt(self) -> str: fields artifact. Any fields that were failed are completely omitted. """ failed_fields = self.get_failed_fields() - return json.dumps({ - k: v for k, v in self.artifact.model_dump().items() if k not in failed_fields - }) + return json.dumps({k: v for k, v in self.artifact.model_dump().items() if k not in failed_fields}) def get_schema_for_prompt(self, filter_one_field: str | None = None) -> str: """Gets a clean version of the original artifact schema, optimized for use in an LLM prompt. @@ -204,17 +200,9 @@ def _clean_properties(schema: dict, failed_fields: list[str]) -> str: if filter_one_field: if not self._is_valid_field(filter_one_field): logger.error(f'Field "{filter_one_field}" is not a valid field in the artifact.') - raise ValueError( - f'Field "{filter_one_field}" is not a valid field in the artifact.' - ) - filtered_schema = { - "properties": { - filter_one_field: self.original_schema["properties"][filter_one_field] - } - } - filtered_schema.update( - (k, v) for k, v in self.original_schema.items() if k != "properties" - ) + raise ValueError(f'Field "{filter_one_field}" is not a valid field in the artifact.') + filtered_schema = {"properties": {filter_one_field: self.original_schema["properties"][filter_one_field]}} + filtered_schema.update((k, v) for k, v in self.original_schema.items() if k != "properties") schema = filtered_schema else: schema = self.original_schema @@ -263,7 +251,6 @@ def get_failed_fields(self) -> list[str]: fields.append(field) return fields - T = TypeVar("T") def _get_type_if_subtype(self, target_type: type[T], base_type: type[Any]) -> type[T] | None: @@ -340,9 +327,7 @@ def _modify_base_artifact( for name, field_info in artifact_model.model_fields.items(): # Replace original classes with modified version. if modified_classes is not None: - field_info.annotation = self._replace_type_annotations( - field_info.annotation, modified_classes - ) + field_info.annotation = self._replace_type_annotations(field_info.annotation, modified_classes) # This makes it possible to always set a field to "Unanswered". annotation = Union[field_info.annotation, Literal["Unanswered"]] @@ -408,7 +393,6 @@ async def _handle_update_error( self.failed_artifact_fields[field_name] = previous_attempts + [attempt] result = await fix_artifact_error( - self.context, self.openai_client, previous_attempts="\n".join([ f"Attempt: {attempt}\nError: {error}" for attempt, error in previous_attempts @@ -432,9 +416,7 @@ async def _handle_update_error( field_value = result.message.split("(")[1].split(")")[0] return True, field_value - logger.warning( - f"Failed to fix the artifact error due to an invalid response from the LLM: {result.message}" - ) + logger.warning(f"Failed to fix the artifact error due to an invalid response from the LLM: {result.message}") return False, None def to_json(self) -> dict: @@ -447,11 +429,12 @@ def to_json(self) -> dict: @classmethod def from_json( cls, + openai_client: AsyncOpenAI | AsyncAzureOpenAI, json_data: dict, input_artifact: BaseModel, max_artifact_field_retries: int = 2, ) -> "Artifact": - artifact = cls(input_artifact, max_artifact_field_retries) + artifact = cls(openai_client, input_artifact, max_artifact_field_retries) artifact.failed_artifact_fields = json_data["failed_fields"] diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/final_update.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/final_update.py index e92814bc..e70056d4 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/final_update.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/final_update.py @@ -2,7 +2,6 @@ from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider -from chat_driver.message_formatter import liquid_format from form_filler_skill.artifact import Artifact from form_filler_skill.definition import GCDefinition from form_filler_skill.message import Conversation @@ -63,7 +62,7 @@ async def final_update( chat_history: Conversation, artifact: Artifact, ): - history = InMemoryMessageHistoryProvider(formatter=liquid_format) + history = InMemoryMessageHistoryProvider() history.append_system_message( final_update_template, @@ -81,7 +80,6 @@ async def final_update( ) config = ChatDriverConfig( - context=context, openai_client=open_ai_client, model="gpt-3.5-turbo", message_provider=history, diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_agenda_error.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_agenda_error.py index f577b301..0eebdc5d 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_agenda_error.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_agenda_error.py @@ -2,7 +2,6 @@ from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider -from chat_driver.message_formatter import liquid_format from form_filler_skill.message import Conversation, ConversationMessageType from openai import AsyncAzureOpenAI, AsyncOpenAI @@ -30,7 +29,7 @@ async def fix_agenda_error( previous_attempts: str, conversation: Conversation, ): - history = InMemoryMessageHistoryProvider(formatter=liquid_format) + history = InMemoryMessageHistoryProvider() history.append_system_message(AGENDA_ERROR_CORRECTION_SYSTEM_TEMPLATE) history.append_user_message( @@ -47,7 +46,6 @@ async def fix_agenda_error( ) config = ChatDriverConfig( - context=context, openai_client=openai_client, model="gpt-3.5-turbo", message_provider=history, diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_artifact_error.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_artifact_error.py index cfd3b842..e73ee449 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_artifact_error.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_artifact_error.py @@ -1,8 +1,7 @@ import logging -from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver import ChatDriver, ChatDriverConfig from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider -from chat_driver.message_formatter import liquid_format from events import BaseEvent from form_filler_skill.message import Conversation, ConversationMessageType from openai import AsyncAzureOpenAI, AsyncOpenAI @@ -30,14 +29,13 @@ async def fix_artifact_error( - context: ContextProtocol, openai_client: AsyncOpenAI | AsyncAzureOpenAI, previous_attempts: str, artifact_schema: str, conversation: Conversation, field_name: str, ) -> BaseEvent: - history = InMemoryMessageHistoryProvider(formatter=liquid_format) + history = InMemoryMessageHistoryProvider() history.append_system_message(ARTIFACT_ERROR_CORRECTION_SYSTEM_TEMPLATE) history.append_user_message( ( @@ -57,7 +55,6 @@ async def fix_artifact_error( ) config = ChatDriverConfig( - context=context, openai_client=openai_client, model="gpt-3.5-turbo", message_provider=history, diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action.py index 24a2fee3..a9b04821 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action.py @@ -2,7 +2,6 @@ from chat_driver import ChatDriver, ChatDriverConfig from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider -from chat_driver.message_formatter import liquid_format from form_filler_skill.agenda import Agenda, AgendaItem from form_filler_skill.definition import GCDefinition from form_filler_skill.message import Conversation @@ -39,7 +38,9 @@ def _get_termination_instructions(resource: GCResource): # Termination condition under exact resource constraints if resource.resource_constraint.mode == ResourceConstraintMode.EXACT: - return "- You should only pick this action if the user is not cooperating so you cannot continue the conversation." + return ( + "- You should only pick this action if the user is not cooperating so you cannot continue the conversation." + ) # Termination condition under maximum resource constraints elif resource.resource_constraint.mode == ResourceConstraintMode.MAXIMUM: @@ -75,7 +76,9 @@ async def update_agenda( total_resource_str = f"does not exceed the remaining turns ({remaining_resource})." ample_time_str = "" case ResourceConstraintMode.EXACT: - total_resource_str = f"is equal to the remaining turns ({remaining_resource}). Do not leave any turns unallocated." + total_resource_str = ( + f"is equal to the remaining turns ({remaining_resource}). Do not leave any turns unallocated." + ) ample_time_str = ( "If you have many turns remaining, instead of including wrap-up items or repeating " "topics, you should include items that increase the breadth and/or depth of the conversation " @@ -88,7 +91,7 @@ async def update_agenda( total_resource_str = "" ample_time_str = "" - history = InMemoryMessageHistoryProvider(formatter=liquid_format) + history = InMemoryMessageHistoryProvider() history.append_system_message( update_agenda_template, { @@ -121,7 +124,6 @@ async def update_agenda( ) config = ChatDriverConfig( - context=context, openai_client=openai_client, model="gpt-4o", message_provider=history, @@ -153,17 +155,13 @@ async def update_agenda( except (ValidationError, ValueError) as e: # If we have reached the maximum number of retries return a failure. if len(previous_attempts) >= agenda.max_agenda_retries: - logger.warning( - f"Failed to update agenda after {agenda.max_agenda_retries} attempts." - ) + logger.warning(f"Failed to update agenda after {agenda.max_agenda_retries} attempts.") return False # Otherwise, get an error string. if isinstance(e, ValidationError): error_str = "; ".join([e.get("msg") for e in e.errors()]) - error_str = error_str.replace( - "; Input should be 'Unanswered'", " or input should be 'Unanswered'" - ) + error_str = error_str.replace("; Input should be 'Unanswered'", " or input should be 'Unanswered'") else: error_str = str(e) @@ -175,9 +173,7 @@ async def update_agenda( llm_formatted_attempts = "\n".join([ f"Attempt: {attempt}\nError: {error}" for attempt, error in previous_attempts ]) - response = await fix_agenda_error( - context, openai_client, llm_formatted_attempts, chat_history - ) + response = await fix_agenda_error(context, openai_client, llm_formatted_attempts, chat_history) # Now, update the items with the corrected agenda and try to # validate again. @@ -199,9 +195,7 @@ def check_item_constraints( violations = [] # In maximum mode, the total resources should not exceed the remaining # turns. - if (resource_constraint_mode == ResourceConstraintMode.MAXIMUM) and ( - total_resources > remaining_turns - ): + if (resource_constraint_mode == ResourceConstraintMode.MAXIMUM) and (total_resources > remaining_turns): violations.append( "The total turns allocated in the agenda " f"must not exceed the remaining amount ({remaining_turns}); " @@ -210,9 +204,7 @@ def check_item_constraints( # In exact mode if the total resources were not exactly equal to the # remaining turns. - if (resource_constraint_mode == ResourceConstraintMode.EXACT) and ( - total_resources != remaining_turns - ): + if (resource_constraint_mode == ResourceConstraintMode.EXACT) and (total_resources != remaining_turns): violations.append( "The total turns allocated in the agenda " f"must equal the remaining amount ({remaining_turns}); " @@ -241,8 +233,6 @@ def get_agenda_for_prompt(agenda: Agenda) -> str: f"{i + 1}. [{format_resource(item['resource'], ResourceConstraintUnit.TURNS)}] {item['title']}" for i, item in enumerate(agenda_items) ]) - total_resource = format_resource( - sum([item["resource"] for item in agenda_items]), ResourceConstraintUnit.TURNS - ) + total_resource = format_resource(sum([item["resource"] for item in agenda_items]), ResourceConstraintUnit.TURNS) agenda_str += f"\nTotal = {total_resource}" return agenda_str diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/execute_reasoning.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/execute_reasoning.py index 48d48750..849056f4 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/execute_reasoning.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/execute_reasoning.py @@ -2,7 +2,6 @@ from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider -from chat_driver.message_formatter import liquid_format from openai import AsyncAzureOpenAI, AsyncOpenAI logger = logging.getLogger(__name__) @@ -37,7 +36,7 @@ async def execute_reasoning( reasoning: str, artifact_schema: str, ): - history = InMemoryMessageHistoryProvider(formatter=liquid_format) + history = InMemoryMessageHistoryProvider() history.append_system_message( SYSTEM_TEMPLATE, @@ -51,7 +50,6 @@ async def execute_reasoning( ) config = ChatDriverConfig( - context=context, openai_client=open_ai_client, model="gpt-3.5-turbo", message_provider=history, diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact.py index 44b50a4d..22458ad5 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact.py @@ -2,7 +2,6 @@ from chat_driver import ChatDriver, ChatDriverConfig from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider -from chat_driver.message_formatter import liquid_format from form_filler_skill.agenda import Agenda, AgendaItem from form_filler_skill.definition import GCDefinition from form_filler_skill.message import Conversation @@ -39,7 +38,9 @@ def _get_termination_instructions(resource: GCResource): # Termination condition under exact resource constraints if resource.resource_constraint.mode == ResourceConstraintMode.EXACT: - return "- You should only pick this action if the user is not cooperating so you cannot continue the conversation." + return ( + "- You should only pick this action if the user is not cooperating so you cannot continue the conversation." + ) # Termination condition under maximum resource constraints elif resource.resource_constraint.mode == ResourceConstraintMode.MAXIMUM: @@ -65,7 +66,7 @@ async def update_agenda( ) -> bool: # STEP 1: Generate an updated agenda. - history = InMemoryMessageHistoryProvider(formatter=liquid_format) + history = InMemoryMessageHistoryProvider() history.append_system_message( update_artifact_template, { @@ -92,7 +93,6 @@ async def update_agenda( ) config = ChatDriverConfig( - context=context, openai_client=openai_client, model="gpt-4o", message_provider=history, @@ -124,17 +124,13 @@ async def update_agenda( except (ValidationError, ValueError) as e: # If we have reached the maximum number of retries return a failure. if len(previous_attempts) >= agenda.max_agenda_retries: - logger.warning( - f"Failed to update agenda after {agenda.max_agenda_retries} attempts." - ) + logger.warning(f"Failed to update agenda after {agenda.max_agenda_retries} attempts.") return False # Otherwise, get an error string. if isinstance(e, ValidationError): error_str = "; ".join([e.get("msg") for e in e.errors()]) - error_str = error_str.replace( - "; Input should be 'Unanswered'", " or input should be 'Unanswered'" - ) + error_str = error_str.replace("; Input should be 'Unanswered'", " or input should be 'Unanswered'") else: error_str = str(e) @@ -146,9 +142,7 @@ async def update_agenda( llm_formatted_attempts = "\n".join([ f"Attempt: {attempt}\nError: {error}" for attempt, error in previous_attempts ]) - response = await fix_agenda_error( - context, openai_client, llm_formatted_attempts, chat_history - ) + response = await fix_agenda_error(context, openai_client, llm_formatted_attempts, chat_history) # Now, update the items with the corrected agenda and try to # validate again. @@ -170,9 +164,7 @@ def check_item_constraints( violations = [] # In maximum mode, the total resources should not exceed the remaining # turns. - if (resource_constraint_mode == ResourceConstraintMode.MAXIMUM) and ( - total_resources > remaining_turns - ): + if (resource_constraint_mode == ResourceConstraintMode.MAXIMUM) and (total_resources > remaining_turns): violations.append( "The total turns allocated in the agenda " f"must not exceed the remaining amount ({remaining_turns}); " @@ -181,9 +173,7 @@ def check_item_constraints( # In exact mode if the total resources were not exactly equal to the # remaining turns. - if (resource_constraint_mode == ResourceConstraintMode.EXACT) and ( - total_resources != remaining_turns - ): + if (resource_constraint_mode == ResourceConstraintMode.EXACT) and (total_resources != remaining_turns): violations.append( "The total turns allocated in the agenda " f"must equal the remaining amount ({remaining_turns}); " @@ -212,8 +202,6 @@ def get_agenda_for_prompt(agenda: Agenda) -> str: f"{i + 1}. [{format_resource(item['resource'], ResourceConstraintUnit.TURNS)}] {item['title']}" for i, item in enumerate(agenda_items) ]) - total_resource = format_resource( - sum([item["resource"] for item in agenda_items]), ResourceConstraintUnit.TURNS - ) + total_resource = format_resource(sum([item["resource"] for item in agenda_items]), ResourceConstraintUnit.TURNS) agenda_str += f"\nTotal = {total_resource}" return agenda_str diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/form_filler_skill.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/form_filler_skill.py index b0c9d94e..ef2ccc33 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/form_filler_skill.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/form_filler_skill.py @@ -32,6 +32,9 @@ def __init__( chat_driver_config.commands = functions chat_driver_config.functions = functions + # TODO: change where this is from. + self.openai_client = chat_driver_config.openai_client + # Initialize the skill! super().__init__( name=NAME, diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_final_update.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_final_update.py index 33f964ba..1c594630 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_final_update.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_final_update.py @@ -2,7 +2,6 @@ from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider -from chat_driver.message_formatter import liquid_format from form_filler_skill.guided_conversation.artifact import Artifact from form_filler_skill.guided_conversation.conversation_helpers import Conversation from form_filler_skill.guided_conversation.definition import GCDefinition @@ -63,7 +62,7 @@ async def final_update( chat_history: Conversation, artifact: Artifact, ): - history = InMemoryMessageHistoryProvider(formatter=liquid_format) + history = InMemoryMessageHistoryProvider() history.append_system_message( final_update_template, @@ -76,7 +75,6 @@ async def final_update( ) config = ChatDriverConfig( - context=context, openai_client=open_ai_client, model="gpt-3.5-turbo", message_provider=history, diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_fix_agenda_error.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_fix_agenda_error.py index 2dded40a..fc6a17dd 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_fix_agenda_error.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_fix_agenda_error.py @@ -2,7 +2,6 @@ from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider -from chat_driver.message_formatter import liquid_format from form_filler_skill.guided_conversation.conversation_helpers import ( Conversation, ConversationMessageType, @@ -42,20 +41,17 @@ async def fix_agenda_error( previous_attempts: str, conversation: Conversation, ): - history = InMemoryMessageHistoryProvider(formatter=liquid_format) + history = InMemoryMessageHistoryProvider() history.append_system_message( AGENDA_ERROR_CORRECTION_SYSTEM_TEMPLATE, { - "conversation_history": conversation.get_repr_for_prompt( - exclude_types=[ConversationMessageType.REASONING] - ), + "conversation_history": conversation.get_repr_for_prompt(exclude_types=[ConversationMessageType.REASONING]), "previous_attempts": previous_attempts, }, ) config = ChatDriverConfig( - context=context, openai_client=openai_client, model="gpt-3.5-turbo", message_provider=history, diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_agenda.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_agenda.py index 65eb70b1..67389b1d 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_agenda.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_agenda.py @@ -2,7 +2,6 @@ from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider -from chat_driver.message_formatter import liquid_format from form_filler_skill.agenda import Agenda, AgendaItem from form_filler_skill.guided_conversation.definition import GCDefinition from form_filler_skill.message import Conversation @@ -45,7 +44,9 @@ def _get_termination_instructions(resource: GCResource): # Termination condition under exact resource constraints if resource.resource_constraint.mode == ResourceConstraintMode.EXACT: - return "- You should only pick this action if the user is not cooperating so you cannot continue the conversation." + return ( + "- You should only pick this action if the user is not cooperating so you cannot continue the conversation." + ) # Termination condition under maximum resource constraints elif resource.resource_constraint.mode == ResourceConstraintMode.MAXIMUM: @@ -81,7 +82,9 @@ async def update_agenda( total_resource_str = f"does not exceed the remaining turns ({remaining_resource})." ample_time_str = "" case ResourceConstraintMode.EXACT: - total_resource_str = f"is equal to the remaining turns ({remaining_resource}). Do not leave any turns unallocated." + total_resource_str = ( + f"is equal to the remaining turns ({remaining_resource}). Do not leave any turns unallocated." + ) ample_time_str = ( "If you have many turns remaining, instead of including wrap-up items or repeating " "topics, you should include items that increase the breadth and/or depth of the conversation " @@ -94,7 +97,7 @@ async def update_agenda( total_resource_str = "" ample_time_str = "" - history = InMemoryMessageHistoryProvider(formatter=liquid_format) + history = InMemoryMessageHistoryProvider() history.append_system_message( update_agenda_template, { @@ -147,17 +150,13 @@ async def update_agenda( except (ValidationError, ValueError) as e: # If we have reached the maximum number of retries return a failure. if len(previous_attempts) >= agenda.max_agenda_retries: - logger.warning( - f"Failed to update agenda after {agenda.max_agenda_retries} attempts." - ) + logger.warning(f"Failed to update agenda after {agenda.max_agenda_retries} attempts.") return False # Otherwise, get an error string. if isinstance(e, ValidationError): error_str = "; ".join([e.get("msg") for e in e.errors()]) - error_str = error_str.replace( - "; Input should be 'Unanswered'", " or input should be 'Unanswered'" - ) + error_str = error_str.replace("; Input should be 'Unanswered'", " or input should be 'Unanswered'") else: error_str = str(e) @@ -169,9 +168,7 @@ async def update_agenda( llm_formatted_attempts = "\n".join([ f"Attempt: {attempt}\nError: {error}" for attempt, error in previous_attempts ]) - response = await fix_agenda_error( - context, openai_client, llm_formatted_attempts, chat_history - ) + response = await fix_agenda_error(context, openai_client, llm_formatted_attempts, chat_history) if response is None: raise ValueError("Invalid response from the LLM.") @@ -201,9 +198,7 @@ def check_item_constraints( violations = [] # In maximum mode, the total resources should not exceed the remaining # turns. - if (resource_constraint_mode == ResourceConstraintMode.MAXIMUM) and ( - total_resources > remaining_turns - ): + if (resource_constraint_mode == ResourceConstraintMode.MAXIMUM) and (total_resources > remaining_turns): violations.append( "The total turns allocated in the agenda " f"must not exceed the remaining amount ({remaining_turns}); " @@ -212,9 +207,7 @@ def check_item_constraints( # In exact mode if the total resources were not exactly equal to the # remaining turns. - if (resource_constraint_mode == ResourceConstraintMode.EXACT) and ( - total_resources != remaining_turns - ): + if (resource_constraint_mode == ResourceConstraintMode.EXACT) and (total_resources != remaining_turns): violations.append( "The total turns allocated in the agenda " f"must equal the remaining amount ({remaining_turns}); " @@ -243,8 +236,6 @@ def get_agenda_for_prompt(agenda: Agenda) -> str: f"{i + 1}. [{format_resource(item['resource'], ResourceConstraintUnit.TURNS)}] {item['title']}" for i, item in enumerate(agenda_items) ]) - total_resource = format_resource( - sum([item["resource"] for item in agenda_items]), ResourceConstraintUnit.TURNS - ) + total_resource = format_resource(sum([item["resource"] for item in agenda_items]), ResourceConstraintUnit.TURNS) agenda_str += f"\nTotal = {total_resource}" return agenda_str diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_artifact.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_artifact.py index 4677e33a..a44372e6 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_artifact.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_artifact.py @@ -2,7 +2,6 @@ from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider -from chat_driver.message_formatter import liquid_format from openai import AsyncAzureOpenAI, AsyncOpenAI logger = logging.getLogger(__name__) @@ -40,7 +39,7 @@ async def update_artifact( reasoning: str, artifact_schema: str, ): - history = InMemoryMessageHistoryProvider(formatter=liquid_format) + history = InMemoryMessageHistoryProvider() history.append_system_message( execution_template, @@ -51,7 +50,6 @@ async def update_artifact( ) config = ChatDriverConfig( - context=context, openai_client=open_ai_client, model="gpt-3.5-turbo", message_provider=history, diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py index 7f40955e..c804558f 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py @@ -2,7 +2,7 @@ from chat_driver import ChatDriverConfig from events import BaseEvent -from skill_library import FunctionRoutine, RoutineTypes, Skill +from skill_library import EmitterType, FunctionRoutine, RoutineTypes, Skill from skill_library.run_context import RunContext from form_filler_skill.agenda import Agenda @@ -11,15 +11,13 @@ from form_filler_skill.message import Conversation from form_filler_skill.resources import GCResource -from .chat_drivers.unneeded.execute_reasoning import execute_reasoning from .chat_drivers.final_update import final_update +from .chat_drivers.unneeded.execute_reasoning import execute_reasoning from .chat_drivers.update_agenda import update_agenda NAME = "guided-conversation" CLASS_NAME = "GuidedConversationSkill" -DESCRIPTION = ( - "Walks the user through a conversation about gathering info for the creation of an artifact." -) +DESCRIPTION = "Walks the user through a conversation about gathering info for the creation of an artifact." DEFAULT_MAX_RETRIES = 3 INSTRUCTIONS = "You are an assistant." @@ -28,6 +26,7 @@ class GuidedConversationSkill(Skill): def __init__( self, chat_driver_config: ChatDriverConfig, + emit: EmitterType, agenda: Agenda, artifact: Artifact, resource: GCResource, @@ -48,6 +47,7 @@ def __init__( ] # Configure the skill's chat driver. + # TODO: change where this is from. self.openai_client = chat_driver_config.openai_client chat_driver_config.instructions = INSTRUCTIONS chat_driver_config.commands = functions @@ -82,9 +82,7 @@ def conversation_routine(self) -> FunctionRoutine: skill=self, ) - async def conversation_init_function( - self, context: RunContext, vars: dict[str, Any] | None = None - ): + async def conversation_init_function(self, context: RunContext, vars: dict[str, Any] | None = None): if vars is None: return state = {"definition": vars["definition"]} @@ -120,10 +118,10 @@ async def conversation_step_function( state["agenda"] = agenda if done: state["mode"] = "finalize" - await self.message_user(context, agenda) # generates the next message + await self.message_user(context, agenda) # generates the next message return case "finalize": - self.final_update() # Generates the final message. + self.final_update() # Generates the final message. state["state"] = "done" runner.send(message) return @@ -146,11 +144,7 @@ async def update_agenda(self, context: RunContext, definition: GCDefinition): ) async def execute_reasoning(self, context: RunContext, reasoning: str) -> BaseEvent: - return await execute_reasoning( - context, self.openai_client, reasoning, self.artifact.get_schema_for_prompt() - ) + return await execute_reasoning(context, self.openai_client, reasoning, self.artifact.get_schema_for_prompt()) async def final_update(self, context: RunContext, definition: GCDefinition): - await final_update( - context, self.openai_client, definition, self.chat_history, artifact=self.artifact - ) + await final_update(context, self.openai_client, definition, self.chat_history, artifact=self.artifact) diff --git a/libraries/python/skills/skills/posix-skill/posix_skill/posix_skill.py b/libraries/python/skills/skills/posix-skill/posix_skill/posix_skill.py index f2d82d1b..41071655 100644 --- a/libraries/python/skills/skills/posix-skill/posix_skill/posix_skill.py +++ b/libraries/python/skills/skills/posix-skill/posix_skill/posix_skill.py @@ -1,7 +1,6 @@ from pathlib import Path from chat_driver import ChatDriverConfig -from context import ContextProtocol from skill_library import InstructionRoutine, RoutineTypes, Skill from .sandbox_shell import SandboxShell @@ -16,7 +15,6 @@ class PosixSkill(Skill): def __init__( self, - context: ContextProtocol, sandbox_dir: Path, chat_driver_config: ChatDriverConfig, mount_dir: str = "/mnt/data", @@ -85,7 +83,7 @@ def make_home_dir_routine(self) -> InstructionRoutine: # Actions ################################## - def cd(self, context: ContextProtocol, directory: str) -> str: + def cd(self, directory: str) -> str: """ Change the current working directory. """ @@ -95,60 +93,60 @@ def cd(self, context: ContextProtocol, directory: str) -> str: except FileNotFoundError: return f"Directory {directory} not found." - def ls(self, context: ContextProtocol, path: str = ".") -> list[str]: + def ls(self, path: str = ".") -> list[str]: """ List directory contents. """ return self.shell.ls(path) - def touch(self, context: ContextProtocol, filename: str) -> str: + def touch(self, filename: str) -> str: """ Create an empty file. """ self.shell.touch(filename) return f"Created file {filename}." - def mkdir(self, context: ContextProtocol, dirname: str) -> str: + def mkdir(self, dirname: str) -> str: """ Create a new directory. """ self.shell.mkdir(dirname) return f"Created directory {dirname}." - def mv(self, context: ContextProtocol, src: str, dest: str) -> str: + def mv(self, src: str, dest: str) -> str: """ Move a file or directory. """ self.shell.mv(src, dest) return f"Moved {src} to {dest}." - def rm(self, context: ContextProtocol, path: str) -> str: + def rm(self, path: str) -> str: """ Remove a file or directory. """ self.shell.rm(path) return f"Removed {path}." - def pwd(self, context: ContextProtocol) -> str: + def pwd(self) -> str: """ Return the current directory. """ return self.shell.pwd() - def run_command(self, context: ContextProtocol, command: str) -> str: + def run_command(self, command: str) -> str: """ Run a shell command in the current directory. """ stdout, stderr = self.shell.run_command(command) return f"Command output:\n{stdout}\nCommand errors:\n{stderr}" - def read_file(self, context: ContextProtocol, filename: str) -> str: + def read_file(self, filename: str) -> str: """ Read the contents of a file. """ return self.shell.read_file(filename) - def write_file(self, context: ContextProtocol, filename: str, content: str) -> str: + def write_file(self, filename: str, content: str) -> str: """ Write content to a file. """ diff --git a/libraries/python/skills/skills/prospector-skill/prospector_skill/skill.py b/libraries/python/skills/skills/prospector-skill/prospector_skill/skill.py index 70c4d143..84def677 100644 --- a/libraries/python/skills/skills/prospector-skill/prospector_skill/skill.py +++ b/libraries/python/skills/skills/prospector-skill/prospector_skill/skill.py @@ -12,7 +12,6 @@ class ProspectorSkill(Skill): def __init__( self, - context: ContextProtocol, chat_driver_config: ChatDriverConfig, ) -> None: # Add some actions. @@ -32,14 +31,12 @@ def __init__( # Configure the chat driver (if using). Register all the supplied actions to it as either # commands, functions, or both. chat_driver_config.instructions = INSTRUCTIONS - chat_driver_config.context = context chat_driver_config.commands = actions chat_driver_config.functions = actions super().__init__( name=NAME, description=DESCRIPTION, - context=context, chat_driver_config=chat_driver_config, skill_actions=actions, routines=routines, diff --git a/libraries/python/skills/skills/skill-template/your_skill/skill.py b/libraries/python/skills/skills/skill-template/your_skill/skill.py index 1a7f1b22..67c47d95 100644 --- a/libraries/python/skills/skills/skill-template/your_skill/skill.py +++ b/libraries/python/skills/skills/skill-template/your_skill/skill.py @@ -12,7 +12,6 @@ class YourSkill(Skill): def __init__( self, - context: ContextProtocol, chat_driver_config: ChatDriverConfig, ) -> None: # Add some actions. @@ -29,14 +28,12 @@ def __init__( # Configure the chat driver (if using). Register all the supplied actions to it as either # commands, functions, or both. chat_driver_config.instructions = INSTRUCTIONS - chat_driver_config.context = context chat_driver_config.commands = actions chat_driver_config.functions = actions super().__init__( name=NAME, description=DESCRIPTION, - context=context, chat_driver_config=chat_driver_config, skill_actions=actions, routines=routines, diff --git a/semantic-workbench.code-workspace b/semantic-workbench.code-workspace index a3839015..545f9f4a 100644 --- a/semantic-workbench.code-workspace +++ b/semantic-workbench.code-workspace @@ -91,10 +91,6 @@ "name": "libraries:events", "path": "libraries/python/events" }, - { - "name": "libraries:function-registry", - "path": "libraries/python/function-registry" - }, { "name": "libraries:guided-conversation", "path": "libraries/python/guided-conversation" @@ -150,13 +146,9 @@ { "name": ".github", "path": ".github" - }, - { - "name": "root", - "path": "." } ], "settings": { "markdown.validate.enabled": true } -} +} \ No newline at end of file From 50e7b50c46c7c101b26efda9bdb5754324010cff Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Tue, 12 Nov 2024 19:16:03 +0000 Subject: [PATCH 11/14] Hides skill errors. This is a WIP, but don't want to keep the branch out any longer. --- .../skills/skills/document-skill/README.md | 5 +++ .../document_skill/document_skill.py | 9 +++-- .../skills/skills/form-filler-skill/README.md | 7 ++-- .../chat_drivers/final_update.py | 3 +- .../chat_drivers/fix_agenda_error.py | 3 +- .../chat_drivers/unneeded/choose_action.py | 2 +- .../chat_drivers/update_agenda.py | 32 +++++------------ .../chat_drivers/update_artifact.py | 4 +-- .../form_filler_skill/form_filler_skill.py | 20 ++++++----- .../chat_drivers/gc_update_agenda.py | 26 +++++++------- .../guided_conversation_skill.py | 34 +++++++++++-------- 11 files changed, 71 insertions(+), 74 deletions(-) diff --git a/libraries/python/skills/skills/document-skill/README.md b/libraries/python/skills/skills/document-skill/README.md index e69de29b..cb86b9a0 100644 --- a/libraries/python/skills/skills/document-skill/README.md +++ b/libraries/python/skills/skills/document-skill/README.md @@ -0,0 +1,5 @@ +# Document Skill + +## _IMPORTANT!_ + +This skill is not yet functional. It is a WIP as we figure out patterns for skill routines! diff --git a/libraries/python/skills/skills/document-skill/document_skill/document_skill.py b/libraries/python/skills/skills/document-skill/document_skill/document_skill.py index ce74568a..9e58e35c 100644 --- a/libraries/python/skills/skills/document-skill/document_skill/document_skill.py +++ b/libraries/python/skills/skills/document-skill/document_skill/document_skill.py @@ -1,3 +1,6 @@ +# flake8: noqa +# ruff: noqa + from chat_driver import ChatDriverConfig from openai import AsyncAzureOpenAI, AsyncOpenAI from pydantic import BaseModel # temp to have something to experiment with @@ -5,6 +8,7 @@ from skill_library.routine import InstructionRoutine, ProgramRoutine from .chat_drivers import draft_content, draft_outline +from .chat_drivers.get_user_feedback_for_outline_decision import get_user_feedback_for_outline_decision NAME = "document_skill" DESCRIPTION = "Anything related to documents - creation, edit, translation" @@ -130,11 +134,10 @@ async def draft_outline( return response.message or "" async def get_user_feedback_decision(self, session_id: str, user_feedback: str, outline: bool) -> str: - response = await get_user_feedback_decision( + response = await get_user_feedback_for_outline_decision( session_id=session_id, open_ai_client=self.openai_client, chat_history=self.document_skill_context.chat_history, - attachments=self.document_skill_context.attachments_list, outline_versions=self.document_skill_context.outline_versions, paper_versions=self.document_skill_context.paper_versions, user_feedback=user_feedback, @@ -154,7 +157,7 @@ async def ask_user(question: str) -> str: while decision == "[ITERATE]": await document_skill.draft_outline(session_id, user_feedback=user_feedback) user_feedback = await ask_user("This look good?") - decision = await document_skill.get_user_feedback_decision(user_feedback, outline=True) + decision = await document_skill.get_user_feedback_decision(session_id, user_feedback, outline=True) if decision == "[QUIT]": exit() await document_skill.draft_content(session_id) diff --git a/libraries/python/skills/skills/form-filler-skill/README.md b/libraries/python/skills/skills/form-filler-skill/README.md index 5e19c5bd..0e81e0de 100644 --- a/libraries/python/skills/skills/form-filler-skill/README.md +++ b/libraries/python/skills/skills/form-filler-skill/README.md @@ -1,7 +1,6 @@ -# Posix Skill +# Form Filler Skill -This is a skill that can be registered to an assistant in the [Skill Library](../../skill-library/README.md). +## _IMPORTANT!_ -This skill has been primarily created for demonstration purposes and you can see it in action in [this notebook](../../notebooks/notebooks/skills.ipynb). +Nothing works here. This is a WIP as we figure out routine running patterns. -This skill gives your assistant the capability for running posix-style actions and routines to manage a filesystem. diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/final_update.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/final_update.py index e70056d4..1e4b4cb6 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/final_update.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/final_update.py @@ -1,6 +1,6 @@ import logging -from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver import ChatDriver, ChatDriverConfig from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider from form_filler_skill.artifact import Artifact from form_filler_skill.definition import GCDefinition @@ -56,7 +56,6 @@ async def final_update( - context: ContextProtocol, open_ai_client: AsyncOpenAI | AsyncAzureOpenAI, definition: GCDefinition, chat_history: Conversation, diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_agenda_error.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_agenda_error.py index 0eebdc5d..dbe26739 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_agenda_error.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_agenda_error.py @@ -1,6 +1,6 @@ import logging -from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol +from chat_driver import ChatDriver, ChatDriverConfig from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider from form_filler_skill.message import Conversation, ConversationMessageType from openai import AsyncAzureOpenAI, AsyncOpenAI @@ -24,7 +24,6 @@ async def fix_agenda_error( - context: ContextProtocol, openai_client: AsyncOpenAI | AsyncAzureOpenAI, previous_attempts: str, conversation: Conversation, diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action.py index a9b04821..804e59b8 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action.py @@ -173,7 +173,7 @@ async def update_agenda( llm_formatted_attempts = "\n".join([ f"Attempt: {attempt}\nError: {error}" for attempt, error in previous_attempts ]) - response = await fix_agenda_error(context, openai_client, llm_formatted_attempts, chat_history) + response = await fix_agenda_error(openai_client, llm_formatted_attempts, chat_history) # Now, update the items with the corrected agenda and try to # validate again. diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_agenda.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_agenda.py index 2f99a17b..22cafa50 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_agenda.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_agenda.py @@ -10,7 +10,6 @@ ) from openai import AsyncAzureOpenAI, AsyncOpenAI from pydantic import ValidationError -from skill_library.run_context import RunContext from .fix_agenda_error import fix_agenda_error @@ -18,13 +17,12 @@ async def update_agenda( - context: RunContext, openai_client: AsyncOpenAI | AsyncAzureOpenAI, items: str, chat_history: Conversation, agenda: Agenda, resource: GCResource, -) -> bool: +) -> tuple[Agenda, bool]: previous_attempts = [] while True: try: @@ -40,22 +38,18 @@ async def update_agenda( ) logger.info(f"Agenda updated successfully: {get_agenda_for_prompt(agenda)}") - return True + return (agenda, True) except (ValidationError, ValueError) as e: # If we have reached the maximum number of retries return a failure. if len(previous_attempts) >= agenda.max_agenda_retries: - logger.warning( - f"Failed to update agenda after {agenda.max_agenda_retries} attempts." - ) - return False + logger.warning(f"Failed to update agenda after {agenda.max_agenda_retries} attempts.") + return (agenda, False) # Otherwise, get an error string. if isinstance(e, ValidationError): error_str = "; ".join([e.get("msg") for e in e.errors()]) - error_str = error_str.replace( - "; Input should be 'Unanswered'", " or input should be 'Unanswered'" - ) + error_str = error_str.replace("; Input should be 'Unanswered'", " or input should be 'Unanswered'") else: error_str = str(e) @@ -67,9 +61,7 @@ async def update_agenda( llm_formatted_attempts = "\n".join([ f"Attempt: {attempt}\nError: {error}" for attempt, error in previous_attempts ]) - response = await fix_agenda_error( - context, openai_client, llm_formatted_attempts, chat_history - ) + response = await fix_agenda_error(openai_client, llm_formatted_attempts, chat_history) # Now, update the items with the corrected agenda and try to # validate again. @@ -91,9 +83,7 @@ def check_item_constraints( violations = [] # In maximum mode, the total resources should not exceed the remaining # turns. - if (resource_constraint_mode == ResourceConstraintMode.MAXIMUM) and ( - total_resources > remaining_turns - ): + if (resource_constraint_mode == ResourceConstraintMode.MAXIMUM) and (total_resources > remaining_turns): violations.append( "The total turns allocated in the agenda " f"must not exceed the remaining amount ({remaining_turns}); " @@ -102,9 +92,7 @@ def check_item_constraints( # In exact mode if the total resources were not exactly equal to the # remaining turns. - if (resource_constraint_mode == ResourceConstraintMode.EXACT) and ( - total_resources != remaining_turns - ): + if (resource_constraint_mode == ResourceConstraintMode.EXACT) and (total_resources != remaining_turns): violations.append( "The total turns allocated in the agenda " f"must equal the remaining amount ({remaining_turns}); " @@ -133,8 +121,6 @@ def get_agenda_for_prompt(agenda: Agenda) -> str: f"{i + 1}. [{format_resource(item['resource'], ResourceConstraintUnit.TURNS)}] {item['title']}" for i, item in enumerate(agenda_items) ]) - total_resource = format_resource( - sum([item["resource"] for item in agenda_items]), ResourceConstraintUnit.TURNS - ) + total_resource = format_resource(sum([item["resource"] for item in agenda_items]), ResourceConstraintUnit.TURNS) agenda_str += f"\nTotal = {total_resource}" return agenda_str diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact.py index 22458ad5..2598180a 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact.py @@ -13,7 +13,6 @@ ) from openai import AsyncAzureOpenAI, AsyncOpenAI from pydantic import ValidationError -from skill_library.run_context import RunContext from ..artifact import Artifact from .fix_agenda_error import fix_agenda_error @@ -56,7 +55,6 @@ def _get_termination_instructions(resource: GCResource): async def update_agenda( - context: RunContext, openai_client: AsyncOpenAI | AsyncAzureOpenAI, definition: GCDefinition, chat_history: Conversation, @@ -142,7 +140,7 @@ async def update_agenda( llm_formatted_attempts = "\n".join([ f"Attempt: {attempt}\nError: {error}" for attempt, error in previous_attempts ]) - response = await fix_agenda_error(context, openai_client, llm_formatted_attempts, chat_history) + response = await fix_agenda_error(openai_client, llm_formatted_attempts, chat_history) # Now, update the items with the corrected agenda and try to # validate again. diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/form_filler_skill.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/form_filler_skill.py index ef2ccc33..85133997 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/form_filler_skill.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/form_filler_skill.py @@ -1,3 +1,6 @@ +# flake8: noqa +# ruff: noqa + from typing import Any, Optional from chat_driver import ChatDriverConfig @@ -85,12 +88,13 @@ async def form_fill_step( context, "guided_conversation.doc_upload", guided_conversation_vars ) state["gc_id"] = gc_id - artifact = GuidedConversation.run(state["gce_id"], message) - if artifact: - state["artifact"] = artifact - else: - await context.update_state(state) - return + # FIXME: This is not implemented yet. + # artifact = GuidedConversation.run(state["gce_id"], message) + # if artifact: + # state["artifact"] = artifact + # else: + # await context.update_state(state) + # return agenda, is_done = FormFiller.update_agenda(context) state["agenda"] = agenda @@ -98,7 +102,7 @@ async def form_fill_step( state["mode"] = "done" state["mode"] = "conversation" await context.update_state(state) - return agenda.last_message + return agenda case "conversation": state["form"] = FormFiller.update_form(context) agenda, is_done = FormFiller.update_agenda(context) @@ -106,7 +110,7 @@ async def form_fill_step( if is_done: state["mode"] = "finalize" await context.update_state(state) - return agenda.last_message + return agenda case "finalize": message = FormFiller.generate_filled_form(context) state["mode"] = "done" diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_agenda.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_agenda.py index 67389b1d..42f72860 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_agenda.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_agenda.py @@ -14,9 +14,9 @@ from openai import AsyncAzureOpenAI, AsyncOpenAI from pydantic import ValidationError -from ..guided_conversation.artifact import Artifact -from .fix_agenda_error import fix_agenda_error -from .update_agenda_template import update_agenda_template +from ...artifact import Artifact +from ...chat_drivers.fix_agenda_error import fix_agenda_error +from ...chat_drivers.update_agenda_template import update_agenda_template logger = logging.getLogger(__name__) @@ -118,7 +118,6 @@ async def update_agenda( ) config = ChatDriverConfig( - context=context, openai_client=openai_client, model="gpt-4o", message_provider=history, @@ -168,19 +167,20 @@ async def update_agenda( llm_formatted_attempts = "\n".join([ f"Attempt: {attempt}\nError: {error}" for attempt, error in previous_attempts ]) - response = await fix_agenda_error(context, openai_client, llm_formatted_attempts, chat_history) + response = await fix_agenda_error(openai_client, llm_formatted_attempts, chat_history) if response is None: raise ValueError("Invalid response from the LLM.") - if response["validation_result"] != ToolValidationResult.SUCCESS: - logger.warning( - f"Failed to fix the agenda error due to a failure in the LLM tool call: {response['validation_result']}" - ) - return False - else: - # Use the result of the first tool call to try the update again - items = response + # if response["validation_result"] != "success": # ToolValidationResult.SUCCESS: + # logger.warning( + # f"Failed to fix the agenda error due to a failure in the LLM tool call: {response['validation_result']}" + # ) + # return False + # else: + # # Use the result of the first tool call to try the update again + # items = response + items = response def check_item_constraints( diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py index c804558f..819df19d 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py @@ -1,7 +1,10 @@ +# flake8: noqa +# ruff: noqa + from typing import Any, Optional from chat_driver import ChatDriverConfig -from events import BaseEvent +from events import BaseEvent, MessageEvent from skill_library import EmitterType, FunctionRoutine, RoutineTypes, Skill from skill_library.run_context import RunContext @@ -60,6 +63,8 @@ def __init__( self.resource = resource self.chat_history = Conversation() + self.emit = emit + # Initialize the skill! super().__init__( name=NAME, @@ -95,6 +100,7 @@ async def conversation_step_function( message: Optional[str] = None, ): # TODO: Where is this conversation maintained? + # FIXME: None of this works. WIP. frame = await context.routine_stack.peek() state = frame.state if frame else {} definition = GCDefinition(**state["definition"]) @@ -104,26 +110,26 @@ async def conversation_step_function( state["mode"] = "init" case "init": state["chat_history"] = [] - message, done = await self.update_agenda(context, definition) + agenda, done = await self.update_agenda("") if done: state["mode"] = "finalize" state["mode"] = "conversation" - context.emit(message) + self.emit(MessageEvent(message="Agenda updated")) return case "conversation": state["chat_history"] += message - state["artifact"] = self.update_artifact(context) - agenda, done = self.update_agenda() + # state["artifact"] = self.update_artifact(context) + agenda, done = await self.update_agenda("") if agenda: state["agenda"] = agenda if done: state["mode"] = "finalize" - await self.message_user(context, agenda) # generates the next message + # await self.message_user(context, agenda) # generates the next message return case "finalize": - self.final_update() # Generates the final message. + # self.final_update() # Generates the final message. state["state"] = "done" - runner.send(message) + # runner.send(message) return case "done": return state["artifact"] @@ -132,19 +138,17 @@ async def conversation_step_function( # Actions ################################## - async def update_agenda(self, context: RunContext, definition: GCDefinition): + async def update_agenda(self, items: str) -> tuple[Agenda, bool]: return await update_agenda( - context, self.openai_client, - definition, + items, self.chat_history, - agenda=self.agenda, - artifact=self.artifact, - resource=self.resource, + self.agenda, + self.resource, ) async def execute_reasoning(self, context: RunContext, reasoning: str) -> BaseEvent: return await execute_reasoning(context, self.openai_client, reasoning, self.artifact.get_schema_for_prompt()) async def final_update(self, context: RunContext, definition: GCDefinition): - await final_update(context, self.openai_client, definition, self.chat_history, artifact=self.artifact) + await final_update(self.openai_client, definition, self.chat_history, self.artifact) From 2c1160a22b4a4541a0e7eef231e1f494cc7ff459 Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Tue, 12 Nov 2024 19:40:23 +0000 Subject: [PATCH 12/14] Removes the function registry library. --- assistants/explorer-assistant/uv.lock | 36 --- .../guided-conversation-assistant/uv.lock | 65 ------ assistants/prospector-assistant/uv.lock | 40 ---- assistants/skill-assistant/uv.lock | 59 ----- .../python/python-02-simple-chatbot/uv.lock | 65 ------ .../python-03-multimodel-chatbot/uv.lock | 65 ------ libraries/python/chat-driver/README.md | 16 +- libraries/python/chat-driver/pyproject.toml | 2 - libraries/python/chat-driver/uv.lock | 38 --- .../function_registry/__init__.py | 3 - .../function_registry/function.py | 122 ---------- .../function_registry/function_registry.py | 217 ------------------ libraries/python/openai-client/pyproject.toml | 2 - .../tests/test_command_parsing.py | 15 +- libraries/python/openai-client/uv.lock | 65 ------ .../notebooks/notebooks/chat_driver.ipynb | 7 +- .../python/skills/notebooks/pyproject.toml | 2 - libraries/python/skills/notebooks/uv.lock | 42 ---- .../skills/skill-library/pyproject.toml | 2 - libraries/python/skills/skill-library/uv.lock | 40 ---- .../skills/skills/document-skill/uv.lock | 40 ---- .../skills/skills/form-filler-skill/uv.lock | 40 ---- .../python/skills/skills/posix-skill/uv.lock | 40 ---- .../skills/skills/prospector-skill/uv.lock | 40 ---- .../skills/skills/skill-template/uv.lock | 40 ---- 25 files changed, 15 insertions(+), 1088 deletions(-) delete mode 100644 libraries/python/function-registry/function_registry/__init__.py delete mode 100644 libraries/python/function-registry/function_registry/function.py delete mode 100644 libraries/python/function-registry/function_registry/function_registry.py rename libraries/python/{function-registry/function_registry => openai-client}/tests/test_command_parsing.py (86%) diff --git a/assistants/explorer-assistant/uv.lock b/assistants/explorer-assistant/uv.lock index 4886e895..05aa8d41 100644 --- a/assistants/explorer-assistant/uv.lock +++ b/assistants/explorer-assistant/uv.lock @@ -605,40 +605,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/83/10/466fe96dae1bff622021ee687f68e5524d6392b0a2f80d05001cd3a451ba/frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7", size = 11552 }, ] -[[package]] -name = "function-registry" -version = "0.1.0" -source = { editable = "../../libraries/python/function-registry" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "openai" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../libraries/python/context" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - [[package]] name = "h11" version = "0.14.0" @@ -1047,7 +1013,6 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, - { name = "function-registry" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -1060,7 +1025,6 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "function-registry", editable = "../../libraries/python/function-registry" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, diff --git a/assistants/guided-conversation-assistant/uv.lock b/assistants/guided-conversation-assistant/uv.lock index 160db72f..8df34ce7 100644 --- a/assistants/guided-conversation-assistant/uv.lock +++ b/assistants/guided-conversation-assistant/uv.lock @@ -367,24 +367,6 @@ requires-dist = [ { name = "semantic-workbench-assistant", editable = "../../libraries/python/semantic-workbench-assistant" }, ] -[[package]] -name = "context" -version = "0.1.0" -source = { editable = "../../libraries/python/context" } -dependencies = [ - { name = "events" }, -] - -[package.metadata] -requires-dist = [{ name = "events", editable = "../../libraries/python/events" }] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - [[package]] name = "cryptography" version = "43.0.1" @@ -481,17 +463,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521 }, ] -[[package]] -name = "events" -version = "0.1.0" -source = { editable = "../../libraries/python/events" } -dependencies = [ - { name = "pydantic" }, -] - -[package.metadata] -requires-dist = [{ name = "pydantic", specifier = ">=2.6.1" }] - [[package]] name = "fastapi" version = "0.115.0" @@ -573,40 +544,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/83/10/466fe96dae1bff622021ee687f68e5524d6392b0a2f80d05001cd3a451ba/frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7", size = 11552 }, ] -[[package]] -name = "function-registry" -version = "0.1.0" -source = { editable = "../../libraries/python/function-registry" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "openai" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../libraries/python/context" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - [[package]] name = "guided-conversation" version = "0.1.0" @@ -1131,7 +1068,6 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, - { name = "function-registry" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -1144,7 +1080,6 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "function-registry", editable = "../../libraries/python/function-registry" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, diff --git a/assistants/prospector-assistant/uv.lock b/assistants/prospector-assistant/uv.lock index 7bf660ca..f4166b52 100644 --- a/assistants/prospector-assistant/uv.lock +++ b/assistants/prospector-assistant/uv.lock @@ -391,7 +391,6 @@ dependencies = [ { name = "azure-identity" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "openai" }, { name = "openai-client" }, { name = "pydantic" }, @@ -406,7 +405,6 @@ requires-dist = [ { name = "azure-identity", specifier = ">=1.17.1" }, { name = "context", editable = "../../libraries/python/context" }, { name = "events", editable = "../../libraries/python/events" }, - { name = "function-registry", editable = "../../libraries/python/function-registry" }, { name = "openai", specifier = ">=1.16.1" }, { name = "openai-client", editable = "../../libraries/python/openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, @@ -683,40 +681,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/83/10/466fe96dae1bff622021ee687f68e5524d6392b0a2f80d05001cd3a451ba/frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7", size = 11552 }, ] -[[package]] -name = "function-registry" -version = "0.1.0" -source = { editable = "../../libraries/python/function-registry" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "openai" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../libraries/python/context" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - [[package]] name = "guided-conversation" version = "0.1.0" @@ -1241,7 +1205,6 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, - { name = "function-registry" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -1254,7 +1217,6 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "function-registry", editable = "../../libraries/python/function-registry" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, @@ -2068,7 +2030,6 @@ dependencies = [ { name = "chat-driver" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "openai" }, { name = "pydantic" }, { name = "pydantic-settings" }, @@ -2083,7 +2044,6 @@ requires-dist = [ { name = "chat-driver", editable = "../../libraries/python/chat-driver" }, { name = "context", editable = "../../libraries/python/context" }, { name = "events", editable = "../../libraries/python/events" }, - { name = "function-registry", editable = "../../libraries/python/function-registry" }, { name = "openai", specifier = ">=1.16.1" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, diff --git a/assistants/skill-assistant/uv.lock b/assistants/skill-assistant/uv.lock index 6049b682..d85ce7d2 100644 --- a/assistants/skill-assistant/uv.lock +++ b/assistants/skill-assistant/uv.lock @@ -360,7 +360,6 @@ dependencies = [ { name = "azure-identity" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "openai" }, { name = "openai-client" }, { name = "pydantic" }, @@ -375,7 +374,6 @@ requires-dist = [ { name = "azure-identity", specifier = ">=1.17.1" }, { name = "context", editable = "../../libraries/python/context" }, { name = "events", editable = "../../libraries/python/events" }, - { name = "function-registry", editable = "../../libraries/python/function-registry" }, { name = "openai", specifier = ">=1.16.1" }, { name = "openai-client", editable = "../../libraries/python/openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, @@ -501,25 +499,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632 }, ] -[[package]] -name = "document-skill" -version = "0.1.0" -source = { editable = "../../libraries/python/skills/skills/document-skill" } -dependencies = [ - { name = "chat-driver" }, - { name = "context" }, - { name = "events" }, - { name = "skill-library" }, -] - -[package.metadata] -requires-dist = [ - { name = "chat-driver", editable = "../../libraries/python/chat-driver" }, - { name = "context", editable = "../../libraries/python/context" }, - { name = "events", editable = "../../libraries/python/events" }, - { name = "skill-library", editable = "../../libraries/python/skills/skill-library" }, -] - [[package]] name = "email-validator" version = "2.2.0" @@ -661,40 +640,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 }, ] -[[package]] -name = "function-registry" -version = "0.1.0" -source = { editable = "../../libraries/python/function-registry" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "openai" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../libraries/python/context" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - [[package]] name = "h11" version = "0.14.0" @@ -1022,7 +967,6 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, - { name = "function-registry" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -1035,7 +979,6 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "function-registry", editable = "../../libraries/python/function-registry" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, @@ -1560,7 +1503,6 @@ dependencies = [ { name = "chat-driver" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "openai" }, { name = "pydantic" }, { name = "pydantic-settings" }, @@ -1575,7 +1517,6 @@ requires-dist = [ { name = "chat-driver", editable = "../../libraries/python/chat-driver" }, { name = "context", editable = "../../libraries/python/context" }, { name = "events", editable = "../../libraries/python/events" }, - { name = "function-registry", editable = "../../libraries/python/function-registry" }, { name = "openai", specifier = ">=1.16.1" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, diff --git a/examples/python/python-02-simple-chatbot/uv.lock b/examples/python/python-02-simple-chatbot/uv.lock index fc0755a8..4290ccf4 100644 --- a/examples/python/python-02-simple-chatbot/uv.lock +++ b/examples/python/python-02-simple-chatbot/uv.lock @@ -343,24 +343,6 @@ requires-dist = [ { name = "semantic-workbench-assistant", editable = "../../../libraries/python/semantic-workbench-assistant" }, ] -[[package]] -name = "context" -version = "0.1.0" -source = { editable = "../../../libraries/python/context" } -dependencies = [ - { name = "events" }, -] - -[package.metadata] -requires-dist = [{ name = "events", editable = "../../../libraries/python/events" }] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - [[package]] name = "cryptography" version = "43.0.1" @@ -430,17 +412,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521 }, ] -[[package]] -name = "events" -version = "0.1.0" -source = { editable = "../../../libraries/python/events" } -dependencies = [ - { name = "pydantic" }, -] - -[package.metadata] -requires-dist = [{ name = "pydantic", specifier = ">=2.6.1" }] - [[package]] name = "fastapi" version = "0.115.0" @@ -522,40 +493,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/83/10/466fe96dae1bff622021ee687f68e5524d6392b0a2f80d05001cd3a451ba/frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7", size = 11552 }, ] -[[package]] -name = "function-registry" -version = "0.1.0" -source = { editable = "../../../libraries/python/function-registry" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "openai" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../../libraries/python/context" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - [[package]] name = "h11" version = "0.14.0" @@ -847,7 +784,6 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, - { name = "function-registry" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -860,7 +796,6 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "function-registry", editable = "../../../libraries/python/function-registry" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, diff --git a/examples/python/python-03-multimodel-chatbot/uv.lock b/examples/python/python-03-multimodel-chatbot/uv.lock index fe7e3750..b467eb95 100644 --- a/examples/python/python-03-multimodel-chatbot/uv.lock +++ b/examples/python/python-03-multimodel-chatbot/uv.lock @@ -375,24 +375,6 @@ requires-dist = [ { name = "semantic-workbench-assistant", editable = "../../../libraries/python/semantic-workbench-assistant" }, ] -[[package]] -name = "context" -version = "0.1.0" -source = { editable = "../../../libraries/python/context" } -dependencies = [ - { name = "events" }, -] - -[package.metadata] -requires-dist = [{ name = "events", editable = "../../../libraries/python/events" }] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - [[package]] name = "cryptography" version = "43.0.1" @@ -462,17 +444,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521 }, ] -[[package]] -name = "events" -version = "0.1.0" -source = { editable = "../../../libraries/python/events" } -dependencies = [ - { name = "pydantic" }, -] - -[package.metadata] -requires-dist = [{ name = "pydantic", specifier = ">=2.6.1" }] - [[package]] name = "fastapi" version = "0.115.0" @@ -572,40 +543,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1d/a0/6aaea0c2fbea2f89bfd5db25fb1e3481896a423002ebe4e55288907a97a3/fsspec-2024.9.0-py3-none-any.whl", hash = "sha256:a0947d552d8a6efa72cc2c730b12c41d043509156966cca4fb157b0f2a0c574b", size = 179253 }, ] -[[package]] -name = "function-registry" -version = "0.1.0" -source = { editable = "../../../libraries/python/function-registry" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "openai" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../../libraries/python/context" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - [[package]] name = "google-ai-generativelanguage" version = "0.6.10" @@ -1086,7 +1023,6 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, - { name = "function-registry" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -1099,7 +1035,6 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "function-registry", editable = "../../../libraries/python/function-registry" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, diff --git a/libraries/python/chat-driver/README.md b/libraries/python/chat-driver/README.md index f39272e9..3a554056 100644 --- a/libraries/python/chat-driver/README.md +++ b/libraries/python/chat-driver/README.md @@ -7,21 +7,15 @@ You can register functions to be used as either _commands_ (allowing the user to issue them with a `/` message) or _tool functions_ (allowing the assistant to optionally call them as it generates a response) or both. -Session state and chat history are maintained for you. +Chat history is maintained for you in-memory. We also provide a local message +provider that will store chat history in a file, or you can implement your own +message provider. -All interactions with the OpenAI service can be logged. +All interactions with the OpenAI are saved as "metadata" on the request allowing +you to do whatever you'd like with it. It is logged for you. For users of the Semantic Workbench, an additional module is provided to make it simple to create an AsyncClient from Workbench-type config. See [this notebook](../skills/notebooks/notebooks/chat_driver.ipynb) for usage examples. - -## Future Work - -- This chat driver does not yet support json_schema nicely. The - ChatCompletionAPI recently added a TypeChat-like capability to ensure the - responses are valid JSON of the type specified in the request. Adding that - here would make a lot of sense. -- This chat driver does not yet support OpenAI-like "File search" or Claude-like - "artifacts". Adding something like that here would make a lot of sense. diff --git a/libraries/python/chat-driver/pyproject.toml b/libraries/python/chat-driver/pyproject.toml index 4a8832b1..760baa3d 100644 --- a/libraries/python/chat-driver/pyproject.toml +++ b/libraries/python/chat-driver/pyproject.toml @@ -9,7 +9,6 @@ dependencies = [ "azure-identity>=1.17.1", "context>=0.1.0", "events>=0.1.0", - "function-registry>=0.1.0", "openai>=1.16.1", "openai-client>=0.1.0", "pydantic-settings>=2.3.4", @@ -25,7 +24,6 @@ package = true [tool.uv.sources] context = { path = "../context", editable = true } events = { path = "../events", editable = true } -function-registry = { path = "../function-registry", editable = true } openai-client = { path = "../openai-client", editable = true } [build-system] diff --git a/libraries/python/chat-driver/uv.lock b/libraries/python/chat-driver/uv.lock index 267c97d7..46beaee0 100644 --- a/libraries/python/chat-driver/uv.lock +++ b/libraries/python/chat-driver/uv.lock @@ -304,7 +304,6 @@ dependencies = [ { name = "azure-identity" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "openai" }, { name = "openai-client" }, { name = "pydantic" }, @@ -319,7 +318,6 @@ requires-dist = [ { name = "azure-identity", specifier = ">=1.17.1" }, { name = "context", editable = "../context" }, { name = "events", editable = "../events" }, - { name = "function-registry", editable = "../function-registry" }, { name = "openai", specifier = ">=1.16.1" }, { name = "openai-client", editable = "../openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, @@ -544,40 +542,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 }, ] -[[package]] -name = "function-registry" -version = "0.1.0" -source = { editable = "../function-registry" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "openai" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../context" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - [[package]] name = "h11" version = "0.14.0" @@ -905,7 +869,6 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, - { name = "function-registry" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -918,7 +881,6 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "function-registry", editable = "../function-registry" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, diff --git a/libraries/python/function-registry/function_registry/__init__.py b/libraries/python/function-registry/function_registry/__init__.py deleted file mode 100644 index 78f6e4a1..00000000 --- a/libraries/python/function-registry/function_registry/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .function_registry import FunctionRegistry - -__all__ = ["FunctionRegistry"] diff --git a/libraries/python/function-registry/function_registry/function.py b/libraries/python/function-registry/function_registry/function.py deleted file mode 100644 index 39bdbbb7..00000000 --- a/libraries/python/function-registry/function_registry/function.py +++ /dev/null @@ -1,122 +0,0 @@ -import inspect -from dataclasses import dataclass -from typing import Any, Callable - -from context.context import ContextProtocol -from pydantic import create_model -from pydantic.fields import FieldInfo - - -@dataclass -class Parameter: - name: str - type: Any - description: str | None - default_value: Any | None = None - - -class Function: - def __init__( - self, name: str, description: str | None, parameters: list[Parameter], fn: Callable, strict_schema: bool = False - ) -> None: - self.name = name - self.description = description or name.replace("_", " ").title() - self.parameters = parameters - self.fn = fn - self.schema: dict[str, Any] = self._generate_schema(strict=strict_schema) - self.usage: str = self._generate_usage() - - async def execute(self, context: ContextProtocol, *args, **kwargs) -> Any: - result = self.fn(context, *args, **kwargs) - if inspect.iscoroutine(result): - return await result - return result - - def _generate_usage(self) -> str: - """A usage string for this function.""" - name = self.name - param_usages = [] - for param in self.parameters: - param_type = param.type - try: - param_type = param.type.__name__ - except AttributeError: - param_type = param.type - usage = f"{param.name}: {param_type}" - if param.default_value is not inspect.Parameter.empty: - if isinstance(param.default_value, str): - usage += f' = "{param.default_value}"' - else: - usage += f" = {param.default_value}" - param_usages.append(usage) - - description = self.description - return f"{name}({', '.join(param_usages)}): {description}" - - def _generate_schema(self, strict: bool = True) -> dict[str, Any]: - """ - Generate a JSON schema for a function based on its signature. - """ - - # Create the Pydantic model using create_model. - - model_name = self.fn.__name__.title().replace("_", "") - fields = {} - for parameter in self.parameters: - field_info = FieldInfo(description=parameter.description) - if parameter.default_value is not inspect.Parameter.empty: - field_info.default = parameter.default_value - fields[parameter.name] = ( - parameter.type, - field_info, - ) - pydantic_model = create_model(model_name, **fields) - # pydantic_model.model_config = {"field_title_generator": lambda _, _: None} - - # Generate the JSON schema from the Pydantic model. - parameters_schema = pydantic_model.model_json_schema(mode="serialization") - - # Remove title attribute from all properties. - properties = parameters_schema["properties"] - for property_key in properties.keys(): - if "title" in properties[property_key]: - del properties[property_key]["title"] - - # And from the top-level object. - if "title" in parameters_schema: - del parameters_schema["title"] - - name = self.fn.__name__ - description = inspect.getdoc(self.fn) or name.replace("_", " ").title() - - # Output a schema that matches OpenAI's "tool" format. - # e.g., https://platform.openai.com/docs/guides/function-calling - # We use this because they trained GPT on it. - schema = { - # "$schema": "http://json-schema.org/draft-07/schema#", - # "$id": f"urn:jsonschema:{name}", - "name": name, - "description": description, - "strict": strict, - "parameters": { - "type": "object", - "properties": parameters_schema["properties"], - }, - } - - # If this is a strict schema requirement, OpenAI requires - # additionalProperties to be False. - # if strict: - schema["parameters"]["additionalProperties"] = False - - # Add required fields. - if "required" in parameters_schema: - schema["parameters"]["required"] = parameters_schema["required"] - - # Add definitions. - if "$defs" in parameters_schema: - schema["parameters"]["$defs"] = parameters_schema["$defs"] - for key in schema["parameters"]["$defs"]: - schema["parameters"]["$defs"][key]["additionalProperties"] = False - - return schema diff --git a/libraries/python/function-registry/function_registry/function_registry.py b/libraries/python/function-registry/function_registry/function_registry.py deleted file mode 100644 index 91459938..00000000 --- a/libraries/python/function-registry/function_registry/function_registry.py +++ /dev/null @@ -1,217 +0,0 @@ -import ast -import inspect -import json -import logging -from typing import Any, Callable - -from context.context import ContextProtocol -from pydantic import BaseModel - -from .function import Function, Parameter - - -class FunctionHandler: - def __init__(self, registry: "FunctionRegistry"): - self.registry = registry - - def __getattr__(self, name: str) -> Callable: - """Makes registered functions accessible as attributes of the functions object.""" - if name not in self.registry.function_map: - raise AttributeError(f"'FunctionHandler' object has no attribute '{name}'") - - async def wrapper(*args, **kwargs) -> Any: - return await self.registry.execute_function(name, args, kwargs) - - return wrapper - - -class FunctionRegistry: - """A function registry helps manage a collection of functions that can be - executed. Functions can be supplied on initialization or registered later. - Additional utilities are provided, such as generating JSON schemas and - returning results as strings.""" - - def __init__(self, context: ContextProtocol, functions: list[Callable] = []) -> None: - self.context = context - - self.function_map: dict[str, Function] = {} - - # By default, every registry has a help function. - self.register_function(self.help, strict_schema=True) - - # But the help function can be overridden if you give it another one. - self.register_functions(functions, strict_schema=True) - - # This allows actions to be called as attributes. - self.functions = FunctionHandler(self) - - def help(self, context: ContextProtocol) -> str: - """Return this help message.""" - return "Commands:\n" + "\n".join([f"{command.usage}" for command in self.function_map.values()]) - - def get_function(self, name: str) -> Function | None: - return self.function_map.get(name) - - def list_functions(self) -> list[str]: - return list(self.function_map.keys()) - - def get_functions(self) -> list[Function]: - return [function for function in self.function_map.values()] - - def has_function(self, name: str) -> bool: - if name == "help": - return True - return name in self.function_map - - def register_function(self, function: Callable, strict_schema: bool = True) -> None: - # Ensure the first argument of the function is the context. - if not inspect.signature(function).parameters: - raise ValueError(f"Function {function.__name__} must have at least one parameter (context: Context).") - if list(inspect.signature(function).parameters.keys())[0] != "context": - raise ValueError(f"Function `{function.__name__}` must have `context` as its first parameter.") - - # Get the function's parameters and their default values. - parameters = dict(inspect.signature(function).parameters) - if "context" in parameters: - del parameters["context"] - params = [ - Parameter( - name=param_name, - type=param.annotation, - description=None, # param.annotation.description, - default_value=param.default, - ) - for param_name, param in parameters.items() - ] - - self.function_map[function.__name__] = Function( - name=function.__name__, - description=inspect.getdoc(function) or function.__name__.replace("_", " ").title(), - fn=function, - parameters=params, - strict_schema=strict_schema, - ) - - def register_functions(self, functions: list[Callable], strict_schema: bool = True) -> None: - for function in functions: - if function.__name__ in self.function_map: - logging.warning(f"Function {function.__name__} already registered.") - continue - if not callable(function): - raise ValueError(f"Function {function} is not callable.") - self.register_function(function, strict_schema=strict_schema) - - async def execute_function(self, name: str, args: tuple, kwargs: dict[str, Any]) -> Any: - """Run a registered function by name. Passes the context as the first argument.""" - function = self.get_function(name) - if not function: - raise ValueError(f"Function {name} not found in registry.") - return await function.execute(self.context, *args, **kwargs) - - async def execute_function_with_string_response(self, name: str, args: tuple, kwargs: dict[str, Any]) -> str: - """Run a registered function by name and return a string response.""" - try: - result = await self.execute_function(name, args, kwargs) - return __class__.to_string_response(result) - except Exception as e: - return f"Error running function {name}: {e}" - - async def execute_function_string(self, function_string: str) -> Any: - """Parse a function string and execute the function.""" - try: - function, args, kwargs = self.parse_function_string(function_string) - except ValueError as e: - raise ValueError(f"{e}. Type: `/help` for more information.") - if not function: - raise ValueError("Function not found in registry. Type: `/help` for more information.") - return await function.execute(self.context, *args, **kwargs) - - async def execute_function_string_with_string_response(self, function_string: str) -> str: - """Parse a function string and execute the function, returning a string response.""" - try: - result = await self.execute_function_string(function_string) - return __class__.to_string_response(result) - except Exception as e: - return f"Error running function: {e}" - - def parse_function_string(self, function_string) -> tuple[Function | None, list[Any], dict[str, Any]]: - """Parse a function call string into a function and its arguments.""" - # As a convenience, remove any leading slashes. - function_string = function_string.lstrip("/") - - # As a convenience, add parentheses if they are missing. - if " " not in function_string and "(" not in function_string: - function_string += "()" - - # Parse the string into an AST (Abstract Syntax Tree) - try: - tree = ast.parse(function_string) - except SyntaxError: - raise ValueError("Invalid function call. Please check your syntax.") - - # Ensure the tree contains exactly one expression (the function call) - if not (isinstance(tree, ast.Module) and len(tree.body) == 1 and isinstance(tree.body[0], ast.Expr)): - raise ValueError("Expected a single function call.") - - # The function call is stored as a `Call` node within the expression - call_node = tree.body[0].value - if not isinstance(call_node, ast.Call): - raise ValueError("Invalid function call. Please check your syntax.") - - # Extract the function name - if isinstance(call_node.func, ast.Name): - function_name = call_node.func.id - else: - raise ValueError("Unsupported function format. Please check your syntax.") - - # Helper function to evaluate AST nodes to their Python equivalent - def eval_node(node): - if isinstance(node, ast.Constant): - return node.value - elif isinstance(node, ast.List): - return [eval_node(elem) for elem in node.elts] - elif isinstance(node, ast.Tuple): - return tuple(eval_node(elem) for elem in node.elts) - elif isinstance(node, ast.Dict): - return {eval_node(key): eval_node(value) for key, value in zip(node.keys, node.values)} - elif isinstance(node, ast.Name): - return node.id # This can return variable names, but we assume they're constants - elif isinstance(node, ast.BinOp): # Handling arithmetic expressions - return eval(compile(ast.Expression(node), filename="", mode="eval")) - elif isinstance(node, ast.Call): - raise ValueError("Nested function calls are not supported.") - else: - raise ValueError(f"Unsupported AST node type: {type(node).__name__}") - - # Extract positional arguments - args = [eval_node(arg) for arg in call_node.args] - - # Extract keyword arguments - kwargs = {} - for kw in call_node.keywords: - kwargs[kw.arg] = eval_node(kw.value) - - function = self.get_function(function_name) - if not function: - return None, [], {} - - return function, args, kwargs - - @staticmethod - def to_string_response(result: Any) -> str: - if result is None: - return "Function executed successfully." - elif isinstance(result, str): - return result - elif isinstance(result, (int, float)): - return str(result) - elif isinstance(result, dict): - return json.dumps(result) - elif isinstance(result, list): - return json.dumps(result, indent=2) - elif isinstance(result, tuple): - return json.dumps(result) - elif isinstance(result, BaseModel): - return result.model_dump_json(indent=2) - else: - return str(result) diff --git a/libraries/python/openai-client/pyproject.toml b/libraries/python/openai-client/pyproject.toml index 9ad6c499..65ebde11 100644 --- a/libraries/python/openai-client/pyproject.toml +++ b/libraries/python/openai-client/pyproject.toml @@ -9,7 +9,6 @@ dependencies = [ "azure-ai-contentsafety>=1.0.0", "azure-core[aio]>=1.30.0", "azure-identity>=1.17.1", - "function-registry>=0.1.0", "openai>=1.3.9", "pillow>=11.0.0", "python-liquid>=1.12.1", @@ -23,7 +22,6 @@ dev-dependencies = ["pytest>=8.3.3"] [tool.uv.sources] semantic-workbench-assistant = { path = "../semantic-workbench-assistant", editable = true } -function-registry = { path = "../function-registry", editable = true } [build-system] requires = ["hatchling"] diff --git a/libraries/python/function-registry/function_registry/tests/test_command_parsing.py b/libraries/python/openai-client/tests/test_command_parsing.py similarity index 86% rename from libraries/python/function-registry/function_registry/tests/test_command_parsing.py rename to libraries/python/openai-client/tests/test_command_parsing.py index ded4b454..e1d3ba22 100644 --- a/libraries/python/function-registry/function_registry/tests/test_command_parsing.py +++ b/libraries/python/openai-client/tests/test_command_parsing.py @@ -1,15 +1,14 @@ from typing import Any, Callable import pytest -from context.context import Context -from function_registry.function_registry import FunctionRegistry +from openai_client.tools import ToolFunctions -def no_op(context: Context) -> None: +def no_op() -> None: pass -def echo(context: Context, value: Any) -> str: +def echo(value: Any) -> str: match value: case str(): return value @@ -23,9 +22,11 @@ def echo(context: Context, value: Any) -> str: return str(value) -context = Context() +# Create tool functions. functions = [echo, no_op] -register = FunctionRegistry(context, functions) +tf = ToolFunctions() +for func in functions: + tf.add_function(func) @pytest.mark.parametrize( @@ -63,7 +64,7 @@ def test_command_parsing_pythonic( expected_error: Any, ): try: - command, args, kwargs = register.parse_function_string(command_string) + command, args, kwargs = tf.parse_function_string(command_string) except Exception as e: assert expected_error is not None assert isinstance(e, expected_error) diff --git a/libraries/python/openai-client/uv.lock b/libraries/python/openai-client/uv.lock index 17124e1a..bb3f757a 100644 --- a/libraries/python/openai-client/uv.lock +++ b/libraries/python/openai-client/uv.lock @@ -301,24 +301,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, ] -[[package]] -name = "context" -version = "0.1.0" -source = { editable = "../context" } -dependencies = [ - { name = "events" }, -] - -[package.metadata] -requires-dist = [{ name = "events", editable = "../events" }] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - [[package]] name = "cryptography" version = "43.0.1" @@ -388,17 +370,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521 }, ] -[[package]] -name = "events" -version = "0.1.0" -source = { editable = "../events" } -dependencies = [ - { name = "pydantic" }, -] - -[package.metadata] -requires-dist = [{ name = "pydantic", specifier = ">=2.6.1" }] - [[package]] name = "fastapi" version = "0.115.0" @@ -480,40 +451,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/83/10/466fe96dae1bff622021ee687f68e5524d6392b0a2f80d05001cd3a451ba/frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7", size = 11552 }, ] -[[package]] -name = "function-registry" -version = "0.1.0" -source = { editable = "../function-registry" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "openai" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../context" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - [[package]] name = "h11" version = "0.14.0" @@ -814,7 +751,6 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, - { name = "function-registry" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -832,7 +768,6 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "function-registry", editable = "../function-registry" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, diff --git a/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb b/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb index 15711770..61a62d3f 100644 --- a/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb +++ b/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb @@ -799,11 +799,8 @@ "\n", "Our chat driver provides:\n", "\n", - "- The ability to almost magically register functions to the function tool using a `FunctionRegistry`.\n", - "- Tracking of message history.\n", - "- Management of a `Context` object that can be used for session management and supply additional context to functions.\n", - "- Some prompt creation helpers.\n", - "- Other utilities... this is just meant to be an interface you can use to forget about all the api complexities." + "- The ability to almost magically register functions to the function tool.\n", + "- Tracking of message history using in-memory, local, or custom message providers.\n" ] }, { diff --git a/libraries/python/skills/notebooks/pyproject.toml b/libraries/python/skills/notebooks/pyproject.toml index 7525eca9..8017bf15 100644 --- a/libraries/python/skills/notebooks/pyproject.toml +++ b/libraries/python/skills/notebooks/pyproject.toml @@ -10,7 +10,6 @@ dependencies = [ "chat-driver>=0.1.0", "context>=0.1.0", "events>=0.1.0", - "function-registry>=0.1.0", "nest-asyncio>=1.6.0", "openai>=1.16.1", "openai-client>=0.1.0", @@ -29,7 +28,6 @@ assistant-drive = { path = "../../assistant-drive", editable = true } chat-driver = { path = "../../chat-driver", editable = true } context = { path = "../../context", editable = true } events = { path = "../../events", editable = true } -function-registry = { path = "../../function-registry", editable = true } posix-skill = { path = "../skills/posix-skill", editable = true } skill-library = { path = "../skill-library/", editable = true } openai-client = { path = "../../openai-client", editable = true } diff --git a/libraries/python/skills/notebooks/uv.lock b/libraries/python/skills/notebooks/uv.lock index 2d936f1f..c673a319 100644 --- a/libraries/python/skills/notebooks/uv.lock +++ b/libraries/python/skills/notebooks/uv.lock @@ -334,7 +334,6 @@ dependencies = [ { name = "azure-identity" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "openai" }, { name = "openai-client" }, { name = "pydantic" }, @@ -349,7 +348,6 @@ requires-dist = [ { name = "azure-identity", specifier = ">=1.17.1" }, { name = "context", editable = "../../context" }, { name = "events", editable = "../../events" }, - { name = "function-registry", editable = "../../function-registry" }, { name = "openai", specifier = ">=1.16.1" }, { name = "openai-client", editable = "../../openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, @@ -606,40 +604,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/83/10/466fe96dae1bff622021ee687f68e5524d6392b0a2f80d05001cd3a451ba/frozenlist-1.4.1-py3-none-any.whl", hash = "sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7", size = 11552 }, ] -[[package]] -name = "function-registry" -version = "0.1.0" -source = { editable = "../../function-registry" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "openai" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../context" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - [[package]] name = "h11" version = "0.14.0" @@ -1056,7 +1020,6 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, - { name = "function-registry" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -1069,7 +1032,6 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "function-registry", editable = "../../function-registry" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, @@ -1722,7 +1684,6 @@ dependencies = [ { name = "chat-driver" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "openai" }, { name = "pydantic" }, { name = "pydantic-settings" }, @@ -1737,7 +1698,6 @@ requires-dist = [ { name = "chat-driver", editable = "../../chat-driver" }, { name = "context", editable = "../../context" }, { name = "events", editable = "../../events" }, - { name = "function-registry", editable = "../../function-registry" }, { name = "openai", specifier = ">=1.16.1" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, @@ -1763,7 +1723,6 @@ dependencies = [ { name = "chat-driver" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "nest-asyncio" }, { name = "openai" }, { name = "openai-client" }, @@ -1784,7 +1743,6 @@ requires-dist = [ { name = "chat-driver", editable = "../../chat-driver" }, { name = "context", editable = "../../context" }, { name = "events", editable = "../../events" }, - { name = "function-registry", editable = "../../function-registry" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, { name = "openai", specifier = ">=1.16.1" }, { name = "openai-client", editable = "../../openai-client" }, diff --git a/libraries/python/skills/skill-library/pyproject.toml b/libraries/python/skills/skill-library/pyproject.toml index d3db0f91..c947f856 100644 --- a/libraries/python/skills/skill-library/pyproject.toml +++ b/libraries/python/skills/skill-library/pyproject.toml @@ -10,7 +10,6 @@ dependencies = [ "chat-driver>=0.1.0", "context>=0.1.0", "events>=0.1.0", - "function-registry>=0.1.0", "openai>=1.16.1", "pydantic-settings>=2.3.4", "pydantic>=2.6.1", @@ -32,7 +31,6 @@ assistant-drive = { path = "../../assistant-drive", editable = true } chat-driver = { path = "../../chat-driver", editable = true } context = { path = "../../context", editable = true } events = { path = "../../events", editable = true } -function-registry = { path = "../../function-registry", editable = true } [build-system] requires = ["hatchling"] diff --git a/libraries/python/skills/skill-library/uv.lock b/libraries/python/skills/skill-library/uv.lock index e8482832..a4808eae 100644 --- a/libraries/python/skills/skill-library/uv.lock +++ b/libraries/python/skills/skill-library/uv.lock @@ -329,7 +329,6 @@ dependencies = [ { name = "azure-identity" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "openai" }, { name = "openai-client" }, { name = "pydantic" }, @@ -344,7 +343,6 @@ requires-dist = [ { name = "azure-identity", specifier = ">=1.17.1" }, { name = "context", editable = "../../context" }, { name = "events", editable = "../../events" }, - { name = "function-registry", editable = "../../function-registry" }, { name = "openai", specifier = ">=1.16.1" }, { name = "openai-client", editable = "../../openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, @@ -569,40 +567,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 }, ] -[[package]] -name = "function-registry" -version = "0.1.0" -source = { editable = "../../function-registry" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "openai" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../context" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - [[package]] name = "h11" version = "0.14.0" @@ -939,7 +903,6 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, - { name = "function-registry" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -952,7 +915,6 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "function-registry", editable = "../../function-registry" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, @@ -1506,7 +1468,6 @@ dependencies = [ { name = "chat-driver" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "openai" }, { name = "pydantic" }, { name = "pydantic-settings" }, @@ -1528,7 +1489,6 @@ requires-dist = [ { name = "chat-driver", editable = "../../chat-driver" }, { name = "context", editable = "../../context" }, { name = "events", editable = "../../events" }, - { name = "function-registry", editable = "../../function-registry" }, { name = "openai", specifier = ">=1.16.1" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, diff --git a/libraries/python/skills/skills/document-skill/uv.lock b/libraries/python/skills/skills/document-skill/uv.lock index 2a8ddd7d..17bb2657 100644 --- a/libraries/python/skills/skills/document-skill/uv.lock +++ b/libraries/python/skills/skills/document-skill/uv.lock @@ -314,7 +314,6 @@ dependencies = [ { name = "azure-identity" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "openai" }, { name = "openai-client" }, { name = "pydantic" }, @@ -329,7 +328,6 @@ requires-dist = [ { name = "azure-identity", specifier = ">=1.17.1" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, - { name = "function-registry", editable = "../../../function-registry" }, { name = "openai", specifier = ">=1.16.1" }, { name = "openai-client", editable = "../../../openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, @@ -573,40 +571,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 }, ] -[[package]] -name = "function-registry" -version = "0.1.0" -source = { editable = "../../../function-registry" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "openai" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../../context" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - [[package]] name = "h11" version = "0.14.0" @@ -922,7 +886,6 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, - { name = "function-registry" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -935,7 +898,6 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "function-registry", editable = "../../../function-registry" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, @@ -1438,7 +1400,6 @@ dependencies = [ { name = "chat-driver" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "openai" }, { name = "pydantic" }, { name = "pydantic-settings" }, @@ -1453,7 +1414,6 @@ requires-dist = [ { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, - { name = "function-registry", editable = "../../../function-registry" }, { name = "openai", specifier = ">=1.16.1" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, diff --git a/libraries/python/skills/skills/form-filler-skill/uv.lock b/libraries/python/skills/skills/form-filler-skill/uv.lock index 7b5e6c93..61609fd5 100644 --- a/libraries/python/skills/skills/form-filler-skill/uv.lock +++ b/libraries/python/skills/skills/form-filler-skill/uv.lock @@ -314,7 +314,6 @@ dependencies = [ { name = "azure-identity" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "openai" }, { name = "openai-client" }, { name = "pydantic" }, @@ -329,7 +328,6 @@ requires-dist = [ { name = "azure-identity", specifier = ">=1.17.1" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, - { name = "function-registry", editable = "../../../function-registry" }, { name = "openai", specifier = ">=1.16.1" }, { name = "openai-client", editable = "../../../openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, @@ -575,40 +573,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 }, ] -[[package]] -name = "function-registry" -version = "0.1.0" -source = { editable = "../../../function-registry" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "openai" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../../context" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - [[package]] name = "h11" version = "0.14.0" @@ -924,7 +888,6 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, - { name = "function-registry" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -937,7 +900,6 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "function-registry", editable = "../../../function-registry" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, @@ -1440,7 +1402,6 @@ dependencies = [ { name = "chat-driver" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "openai" }, { name = "pydantic" }, { name = "pydantic-settings" }, @@ -1455,7 +1416,6 @@ requires-dist = [ { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, - { name = "function-registry", editable = "../../../function-registry" }, { name = "openai", specifier = ">=1.16.1" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, diff --git a/libraries/python/skills/skills/posix-skill/uv.lock b/libraries/python/skills/skills/posix-skill/uv.lock index ae772499..f3305ad5 100644 --- a/libraries/python/skills/skills/posix-skill/uv.lock +++ b/libraries/python/skills/skills/posix-skill/uv.lock @@ -314,7 +314,6 @@ dependencies = [ { name = "azure-identity" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "openai" }, { name = "openai-client" }, { name = "pydantic" }, @@ -329,7 +328,6 @@ requires-dist = [ { name = "azure-identity", specifier = ">=1.17.1" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, - { name = "function-registry", editable = "../../../function-registry" }, { name = "openai", specifier = ">=1.16.1" }, { name = "openai-client", editable = "../../../openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, @@ -554,40 +552,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 }, ] -[[package]] -name = "function-registry" -version = "0.1.0" -source = { editable = "../../../function-registry" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "openai" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../../context" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - [[package]] name = "h11" version = "0.14.0" @@ -903,7 +867,6 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, - { name = "function-registry" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -916,7 +879,6 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "function-registry", editable = "../../../function-registry" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, @@ -1438,7 +1400,6 @@ dependencies = [ { name = "chat-driver" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "openai" }, { name = "pydantic" }, { name = "pydantic-settings" }, @@ -1453,7 +1414,6 @@ requires-dist = [ { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, - { name = "function-registry", editable = "../../../function-registry" }, { name = "openai", specifier = ">=1.16.1" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, diff --git a/libraries/python/skills/skills/prospector-skill/uv.lock b/libraries/python/skills/skills/prospector-skill/uv.lock index fb7c57c0..d5405071 100644 --- a/libraries/python/skills/skills/prospector-skill/uv.lock +++ b/libraries/python/skills/skills/prospector-skill/uv.lock @@ -314,7 +314,6 @@ dependencies = [ { name = "azure-identity" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "openai" }, { name = "openai-client" }, { name = "pydantic" }, @@ -329,7 +328,6 @@ requires-dist = [ { name = "azure-identity", specifier = ">=1.17.1" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, - { name = "function-registry", editable = "../../../function-registry" }, { name = "openai", specifier = ">=1.16.1" }, { name = "openai-client", editable = "../../../openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, @@ -554,40 +552,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 }, ] -[[package]] -name = "function-registry" -version = "0.1.0" -source = { editable = "../../../function-registry" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "openai" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../../context" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - [[package]] name = "h11" version = "0.14.0" @@ -903,7 +867,6 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, - { name = "function-registry" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -916,7 +879,6 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "function-registry", editable = "../../../function-registry" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, @@ -1438,7 +1400,6 @@ dependencies = [ { name = "chat-driver" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "openai" }, { name = "pydantic" }, { name = "pydantic-settings" }, @@ -1453,7 +1414,6 @@ requires-dist = [ { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, - { name = "function-registry", editable = "../../../function-registry" }, { name = "openai", specifier = ">=1.16.1" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, diff --git a/libraries/python/skills/skills/skill-template/uv.lock b/libraries/python/skills/skills/skill-template/uv.lock index bf6c6414..16119c5b 100644 --- a/libraries/python/skills/skills/skill-template/uv.lock +++ b/libraries/python/skills/skills/skill-template/uv.lock @@ -314,7 +314,6 @@ dependencies = [ { name = "azure-identity" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "openai" }, { name = "openai-client" }, { name = "pydantic" }, @@ -329,7 +328,6 @@ requires-dist = [ { name = "azure-identity", specifier = ">=1.17.1" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, - { name = "function-registry", editable = "../../../function-registry" }, { name = "openai", specifier = ">=1.16.1" }, { name = "openai-client", editable = "../../../openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, @@ -554,40 +552,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 }, ] -[[package]] -name = "function-registry" -version = "0.1.0" -source = { editable = "../../../function-registry" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "openai" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../../context" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - [[package]] name = "h11" version = "0.14.0" @@ -903,7 +867,6 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, - { name = "function-registry" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -916,7 +879,6 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "function-registry", editable = "../../../function-registry" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, @@ -1419,7 +1381,6 @@ dependencies = [ { name = "chat-driver" }, { name = "context" }, { name = "events" }, - { name = "function-registry" }, { name = "openai" }, { name = "pydantic" }, { name = "pydantic-settings" }, @@ -1434,7 +1395,6 @@ requires-dist = [ { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, - { name = "function-registry", editable = "../../../function-registry" }, { name = "openai", specifier = ">=1.16.1" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, From ac9082814e37ca0c098dcc34e1ae65098991d6c6 Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Tue, 12 Nov 2024 21:49:34 +0000 Subject: [PATCH 13/14] Removes ChatDriver library. Adds to openai-client. --- assistants/explorer-assistant/uv.lock | 2 + .../guided-conversation-assistant/uv.lock | 13 + .../prospector-assistant/pyproject.toml | 24 +- assistants/prospector-assistant/uv.lock | 51 +- assistants/skill-assistant/README.md | 2 +- .../assistant/assistant_registry.py | 2 +- .../skill-assistant/assistant/config.py | 11 +- .../assistant/skill_assistant.py | 2 +- assistants/skill-assistant/uv.lock | 43 +- .../python/python-02-simple-chatbot/uv.lock | 13 + .../python-03-multimodel-chatbot/uv.lock | 13 + .../python/chat-driver/.vscode/settings.json | 56 - libraries/python/chat-driver/Makefile | 2 - .../chat-driver/chat_driver/__init__.py | 30 - .../tests/formatted_instructions_test.py | 62 - libraries/python/chat-driver/pyproject.toml | 31 - libraries/python/chat-driver/uv.lock | 1677 ----------------- libraries/python/context/README.md | 1 - .../openai_client/chat_driver}/README.md | 0 .../openai_client/chat_driver/__init__.py | 19 + .../openai_client}/chat_driver/chat_driver.py | 21 +- .../message_history_providers/__init__.py | 13 + .../in_memory_message_history_provider.py | 0 .../local_message_history_provider.py | 0 .../message_history_provider.py | 0 .../tests/formatted_instructions_test.py | 6 +- .../openai-client/openai_client/messages.py | 30 +- libraries/python/openai-client/pyproject.toml | 2 + .../tests/test_formatted_messages.py | 48 + libraries/python/openai-client/uv.lock | 13 + .../notebooks/notebooks/chat_driver.ipynb | 100 +- .../skills/notebooks/notebooks/skills.ipynb | 72 +- .../python/skills/notebooks/pyproject.toml | 4 +- libraries/python/skills/notebooks/uv.lock | 43 +- .../python/skills/skill-library/README.md | 7 +- .../skills/skill-library/pyproject.toml | 5 +- .../skill-library/skill_library/actions.py | 13 +- .../skill-library/skill_library/assistant.py | 19 +- .../skill-library/skill_library/skill.py | 15 +- libraries/python/skills/skill-library/uv.lock | 37 +- .../chat_drivers/draft_content.py | 3 +- .../chat_drivers/draft_outline.py | 3 +- .../get_user_feedback_for_outline_decision.py | 3 +- .../get_user_feedback_for_page_decision.py | 3 +- .../document_skill/document_skill.py | 2 +- .../skills/document-skill/pyproject.toml | 8 +- .../skills/skills/document-skill/uv.lock | 41 +- .../chat_drivers/final_update.py | 3 +- .../chat_drivers/fix_agenda_error.py | 3 +- .../chat_drivers/fix_artifact_error.py | 3 +- .../chat_drivers/unneeded/choose_action.py | 3 +- .../unneeded/execute_reasoning.py | 4 +- .../chat_drivers/update_artifact.py | 3 +- .../form_filler_skill/form_filler_skill.py | 2 +- .../chat_drivers/gc_final_update.py | 4 +- .../chat_drivers/gc_fix_agenda_error.py | 4 +- .../chat_drivers/gc_update_agenda.py | 4 +- .../chat_drivers/gc_update_artifact.py | 4 +- .../guided_conversation_skill.py | 4 +- .../skills/form-filler-skill/pyproject.toml | 2 - .../skills/skills/form-filler-skill/uv.lock | 39 +- .../posix-skill/posix_skill/posix_skill.py | 2 +- .../skills/skills/posix-skill/pyproject.toml | 7 +- .../python/skills/skills/posix-skill/uv.lock | 41 +- .../prospector_skill/skill.py | 2 +- .../skills/prospector-skill/pyproject.toml | 9 +- .../skills/skills/prospector-skill/uv.lock | 41 +- .../skills/skill-template/pyproject.toml | 8 +- .../skills/skills/skill-template/uv.lock | 41 +- .../skills/skill-template/your_skill/skill.py | 2 +- semantic-workbench.code-workspace | 4 - 71 files changed, 414 insertions(+), 2390 deletions(-) delete mode 100644 libraries/python/chat-driver/.vscode/settings.json delete mode 100644 libraries/python/chat-driver/Makefile delete mode 100644 libraries/python/chat-driver/chat_driver/__init__.py delete mode 100644 libraries/python/chat-driver/chat_driver/tests/formatted_instructions_test.py delete mode 100644 libraries/python/chat-driver/pyproject.toml delete mode 100644 libraries/python/chat-driver/uv.lock rename libraries/python/{chat-driver => openai-client/openai_client/chat_driver}/README.md (100%) create mode 100644 libraries/python/openai-client/openai_client/chat_driver/__init__.py rename libraries/python/{chat-driver => openai-client/openai_client}/chat_driver/chat_driver.py (93%) create mode 100644 libraries/python/openai-client/openai_client/chat_driver/message_history_providers/__init__.py rename libraries/python/{chat-driver/chat_driver => openai-client/openai_client/chat_driver/message_history_providers}/in_memory_message_history_provider.py (100%) rename libraries/python/{chat-driver/chat_driver => openai-client/openai_client/chat_driver/message_history_providers}/local_message_history_provider.py (100%) rename libraries/python/{chat-driver/chat_driver => openai-client/openai_client/chat_driver/message_history_providers}/message_history_provider.py (100%) rename libraries/python/{chat-driver => openai-client/openai_client/chat_driver/message_history_providers}/tests/formatted_instructions_test.py (95%) create mode 100644 libraries/python/openai-client/tests/test_formatted_messages.py diff --git a/assistants/explorer-assistant/uv.lock b/assistants/explorer-assistant/uv.lock index 05aa8d41..f301090d 100644 --- a/assistants/explorer-assistant/uv.lock +++ b/assistants/explorer-assistant/uv.lock @@ -1013,6 +1013,7 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, + { name = "events" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -1025,6 +1026,7 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "events", editable = "../../libraries/python/events" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, diff --git a/assistants/guided-conversation-assistant/uv.lock b/assistants/guided-conversation-assistant/uv.lock index 8df34ce7..beef0051 100644 --- a/assistants/guided-conversation-assistant/uv.lock +++ b/assistants/guided-conversation-assistant/uv.lock @@ -463,6 +463,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521 }, ] +[[package]] +name = "events" +version = "0.1.0" +source = { editable = "../../libraries/python/events" } +dependencies = [ + { name = "pydantic" }, +] + +[package.metadata] +requires-dist = [{ name = "pydantic", specifier = ">=2.6.1" }] + [[package]] name = "fastapi" version = "0.115.0" @@ -1068,6 +1079,7 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, + { name = "events" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -1080,6 +1092,7 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "events", editable = "../../libraries/python/events" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, diff --git a/assistants/prospector-assistant/pyproject.toml b/assistants/prospector-assistant/pyproject.toml index c07d5b03..12c817bc 100644 --- a/assistants/prospector-assistant/pyproject.toml +++ b/assistants/prospector-assistant/pyproject.toml @@ -6,35 +6,33 @@ authors = [{ name = "Semantic Workbench Team" }] readme = "README.md" requires-python = ">=3.11" dependencies = [ + "assistant-extensions[attachments]>=0.1.0", + "content-safety>=0.1.0", "deepmerge>=2.0", + "document-skill>=0.1.0", + "guided-conversation>=0.1.0", "html2docx>=1.6.0", "markdown>=3.6", + "openai-client>=0.1.0", "openai>=1.3.9", - "content-safety>=0.1.0", - "chat-driver>=0.1.0", - "skill-library>=0.1.0", "posix-skill>=0.1.0", "prospector-skill>=0.1.0", - "document-skill>=0.1.0", - "guided-conversation>=0.1.0", - "openai-client>=0.1.0", - "assistant-extensions[attachments]>=0.1.0", + "skill-library>=0.1.0", ] [tool.uv] package = true [tool.uv.sources] +assistant-drive = { path = "../../libraries/python/assistant-drive", editable = true } +assistant-extensions = { path = "../../libraries/python/assistant-extensions", editable = true } content-safety = { path = "../../libraries/python/content-safety/", editable = true } +document-skill = { path = "../../libraries/python/skills/skills/document-skill", editable = true } guided-conversation = { path = "../../libraries/python/guided-conversation", editable = true } -chat-driver = { path = "../../libraries/python/chat-driver", editable = true } -skill-library = { path = "../../libraries/python/skills/skill-library", editable = true } +openai-client = { path = "../../libraries/python/openai-client", editable = true } posix-skill = { path = "../../libraries/python/skills/skills/posix-skill", editable = true } prospector-skill = { path = "../../libraries/python/skills/skills/prospector-skill", editable = true } -document-skill = { path = "../../libraries/python/skills/skills/document-skill", editable = true } -openai-client = { path = "../../libraries/python/openai-client", editable = true } -assistant-drive = { path = "../../libraries/python/assistant-drive", editable = true } -assistant-extensions = { path = "../../libraries/python/assistant-extensions", editable = true } +skill-library = { path = "../../libraries/python/skills/skill-library", editable = true } [build-system] requires = ["hatchling"] diff --git a/assistants/prospector-assistant/uv.lock b/assistants/prospector-assistant/uv.lock index f4166b52..03f50c61 100644 --- a/assistants/prospector-assistant/uv.lock +++ b/assistants/prospector-assistant/uv.lock @@ -128,7 +128,6 @@ version = "0.1.0" source = { editable = "." } dependencies = [ { name = "assistant-extensions", extra = ["attachments"] }, - { name = "chat-driver" }, { name = "content-safety" }, { name = "deepmerge" }, { name = "document-skill" }, @@ -145,7 +144,6 @@ dependencies = [ [package.metadata] requires-dist = [ { name = "assistant-extensions", extras = ["attachments"], editable = "../../libraries/python/assistant-extensions" }, - { name = "chat-driver", editable = "../../libraries/python/chat-driver" }, { name = "content-safety", editable = "../../libraries/python/content-safety" }, { name = "deepmerge", specifier = ">=2.0" }, { name = "document-skill", editable = "../../libraries/python/skills/skills/document-skill" }, @@ -383,37 +381,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/28/76/e6222113b83e3622caa4bb41032d0b1bf785250607392e1b778aca0b8a7d/charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", size = 48543 }, ] -[[package]] -name = "chat-driver" -version = "0.1.0" -source = { editable = "../../libraries/python/chat-driver" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "events" }, - { name = "openai" }, - { name = "openai-client" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../libraries/python/context" }, - { name = "events", editable = "../../libraries/python/events" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "openai-client", editable = "../../libraries/python/openai-client" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - [[package]] name = "click" version = "8.1.7" @@ -556,17 +523,17 @@ name = "document-skill" version = "0.1.0" source = { editable = "../../libraries/python/skills/skills/document-skill" } dependencies = [ - { name = "chat-driver" }, { name = "context" }, { name = "events" }, + { name = "openai-client" }, { name = "skill-library" }, ] [package.metadata] requires-dist = [ - { name = "chat-driver", editable = "../../libraries/python/chat-driver" }, { name = "context", editable = "../../libraries/python/context" }, { name = "events", editable = "../../libraries/python/events" }, + { name = "openai-client", editable = "../../libraries/python/openai-client" }, { name = "skill-library", editable = "../../libraries/python/skills/skill-library" }, ] @@ -1205,6 +1172,7 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, + { name = "events" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -1217,6 +1185,7 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "events", editable = "../../libraries/python/events" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, @@ -1435,17 +1404,17 @@ name = "posix-skill" version = "0.1.0" source = { editable = "../../libraries/python/skills/skills/posix-skill" } dependencies = [ - { name = "chat-driver" }, { name = "context" }, { name = "events" }, + { name = "openai-client" }, { name = "skill-library" }, ] [package.metadata] requires-dist = [ - { name = "chat-driver", editable = "../../libraries/python/chat-driver" }, { name = "context", editable = "../../libraries/python/context" }, { name = "events", editable = "../../libraries/python/events" }, + { name = "openai-client", editable = "../../libraries/python/openai-client" }, { name = "skill-library", editable = "../../libraries/python/skills/skill-library" }, ] @@ -1470,17 +1439,17 @@ name = "prospector-skill" version = "0.1.0" source = { editable = "../../libraries/python/skills/skills/prospector-skill" } dependencies = [ - { name = "chat-driver" }, { name = "context" }, { name = "events" }, + { name = "openai-client" }, { name = "skill-library" }, ] [package.metadata] requires-dist = [ - { name = "chat-driver", editable = "../../libraries/python/chat-driver" }, { name = "context", editable = "../../libraries/python/context" }, { name = "events", editable = "../../libraries/python/events" }, + { name = "openai-client", editable = "../../libraries/python/openai-client" }, { name = "skill-library", editable = "../../libraries/python/skills/skill-library" }, ] @@ -2027,10 +1996,10 @@ version = "0.1.0" source = { editable = "../../libraries/python/skills/skill-library" } dependencies = [ { name = "assistant-drive" }, - { name = "chat-driver" }, { name = "context" }, { name = "events" }, { name = "openai" }, + { name = "openai-client" }, { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, @@ -2041,10 +2010,10 @@ dependencies = [ [package.metadata] requires-dist = [ { name = "assistant-drive", editable = "../../libraries/python/assistant-drive" }, - { name = "chat-driver", editable = "../../libraries/python/chat-driver" }, { name = "context", editable = "../../libraries/python/context" }, { name = "events", editable = "../../libraries/python/events" }, { name = "openai", specifier = ">=1.16.1" }, + { name = "openai-client", editable = "../../libraries/python/openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, diff --git a/assistants/skill-assistant/README.md b/assistants/skill-assistant/README.md index 106b36fc..214eb44a 100644 --- a/assistants/skill-assistant/README.md +++ b/assistants/skill-assistant/README.md @@ -1,6 +1,6 @@ # Skill Assistant -The Skill Assistant serves as a demonstration of integrating the Skill Library within an Assistant in the Semantic Workbench. Specifically, this assistant showcases the Posix skill and the chat driver. The [Posix skill](../../libraries/python/skills/skills/posix-skill/README.md) demonstrates file system management by allowing the assistant to perform posix-style actions. The [chat driver](../../libraries/python/chat-driver/README.md) handles conversations and interacts with underlying AI models like OpenAI and Azure OpenAI. +The Skill Assistant serves as a demonstration of integrating the Skill Library within an Assistant in the Semantic Workbench. Specifically, this assistant showcases the Posix skill and the chat driver. The [Posix skill](../../libraries/python/skills/skills/posix-skill/README.md) demonstrates file system management by allowing the assistant to perform posix-style actions. The [chat driver](../../libraries/python/openai-client/openai_client/chat_driver/README.md) handles conversations and interacts with underlying AI models like OpenAI and Azure OpenAI. ## Overview diff --git a/assistants/skill-assistant/assistant/assistant_registry.py b/assistants/skill-assistant/assistant/assistant_registry.py index a4503b54..473646ef 100644 --- a/assistants/skill-assistant/assistant/assistant_registry.py +++ b/assistants/skill-assistant/assistant/assistant_registry.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import List -from chat_driver import ChatDriverConfig +from openai_client.chat_driver import ChatDriverConfig from skill_library import Assistant, Skill from assistant.skill_event_mapper import SkillEventMapperProtocol diff --git a/assistants/skill-assistant/assistant/config.py b/assistants/skill-assistant/assistant/config.py index 4c66a065..0fc15331 100644 --- a/assistants/skill-assistant/assistant/config.py +++ b/assistants/skill-assistant/assistant/config.py @@ -86,7 +86,8 @@ class ChatDriverConfig(BaseModel): ] = "gpt-4o" -# the workbench app builds dynamic forms based on the configuration model and UI schema +# The workbench app builds dynamic forms based on the configuration model and UI +# schema. class AssistantConfigModel(BaseModel): guardrails_prompt: Annotated[ str, @@ -129,6 +130,14 @@ class AssistantConfigModel(BaseModel): UISchema(widget="radio"), ] = CombinedContentSafetyEvaluatorConfig() + metadata_path: Annotated[ + str, + Field( + title="Metadata Path", + description="The path for assistant metadata.", + ), + ] = ".data" + # add any additional configuration fields diff --git a/assistants/skill-assistant/assistant/skill_assistant.py b/assistants/skill-assistant/assistant/skill_assistant.py index 6a36376d..bd59aad4 100644 --- a/assistants/skill-assistant/assistant/skill_assistant.py +++ b/assistants/skill-assistant/assistant/skill_assistant.py @@ -11,8 +11,8 @@ from pathlib import Path import openai_client -from chat_driver import ChatDriverConfig from content_safety.evaluators import CombinedContentSafetyEvaluator +from openai_client.chat_driver import ChatDriverConfig # from form_filler_skill import FormFillerSkill from posix_skill import PosixSkill diff --git a/assistants/skill-assistant/uv.lock b/assistants/skill-assistant/uv.lock index d85ce7d2..b684af43 100644 --- a/assistants/skill-assistant/uv.lock +++ b/assistants/skill-assistant/uv.lock @@ -352,37 +352,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", size = 49446 }, ] -[[package]] -name = "chat-driver" -version = "0.1.0" -source = { editable = "../../libraries/python/chat-driver" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "events" }, - { name = "openai" }, - { name = "openai-client" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../libraries/python/context" }, - { name = "events", editable = "../../libraries/python/events" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "openai-client", editable = "../../libraries/python/openai-client" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - [[package]] name = "click" version = "8.1.7" @@ -570,7 +539,6 @@ name = "form-filler-skill" version = "0.1.0" source = { editable = "../../libraries/python/skills/skills/form-filler-skill" } dependencies = [ - { name = "chat-driver" }, { name = "context" }, { name = "events" }, { name = "openai-client" }, @@ -579,7 +547,6 @@ dependencies = [ [package.metadata] requires-dist = [ - { name = "chat-driver", editable = "../../libraries/python/chat-driver" }, { name = "context", editable = "../../libraries/python/context" }, { name = "events", editable = "../../libraries/python/events" }, { name = "openai-client", editable = "../../libraries/python/openai-client" }, @@ -967,6 +934,7 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, + { name = "events" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -979,6 +947,7 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "events", editable = "../../libraries/python/events" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, @@ -1064,17 +1033,17 @@ name = "posix-skill" version = "0.1.0" source = { editable = "../../libraries/python/skills/skills/posix-skill" } dependencies = [ - { name = "chat-driver" }, { name = "context" }, { name = "events" }, + { name = "openai-client" }, { name = "skill-library" }, ] [package.metadata] requires-dist = [ - { name = "chat-driver", editable = "../../libraries/python/chat-driver" }, { name = "context", editable = "../../libraries/python/context" }, { name = "events", editable = "../../libraries/python/events" }, + { name = "openai-client", editable = "../../libraries/python/openai-client" }, { name = "skill-library", editable = "../../libraries/python/skills/skill-library" }, ] @@ -1500,10 +1469,10 @@ version = "0.1.0" source = { editable = "../../libraries/python/skills/skill-library" } dependencies = [ { name = "assistant-drive" }, - { name = "chat-driver" }, { name = "context" }, { name = "events" }, { name = "openai" }, + { name = "openai-client" }, { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, @@ -1514,10 +1483,10 @@ dependencies = [ [package.metadata] requires-dist = [ { name = "assistant-drive", editable = "../../libraries/python/assistant-drive" }, - { name = "chat-driver", editable = "../../libraries/python/chat-driver" }, { name = "context", editable = "../../libraries/python/context" }, { name = "events", editable = "../../libraries/python/events" }, { name = "openai", specifier = ">=1.16.1" }, + { name = "openai-client", editable = "../../libraries/python/openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, diff --git a/examples/python/python-02-simple-chatbot/uv.lock b/examples/python/python-02-simple-chatbot/uv.lock index 4290ccf4..dff9cd38 100644 --- a/examples/python/python-02-simple-chatbot/uv.lock +++ b/examples/python/python-02-simple-chatbot/uv.lock @@ -412,6 +412,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521 }, ] +[[package]] +name = "events" +version = "0.1.0" +source = { editable = "../../../libraries/python/events" } +dependencies = [ + { name = "pydantic" }, +] + +[package.metadata] +requires-dist = [{ name = "pydantic", specifier = ">=2.6.1" }] + [[package]] name = "fastapi" version = "0.115.0" @@ -784,6 +795,7 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, + { name = "events" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -796,6 +808,7 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "events", editable = "../../../libraries/python/events" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, diff --git a/examples/python/python-03-multimodel-chatbot/uv.lock b/examples/python/python-03-multimodel-chatbot/uv.lock index b467eb95..b7bc1098 100644 --- a/examples/python/python-03-multimodel-chatbot/uv.lock +++ b/examples/python/python-03-multimodel-chatbot/uv.lock @@ -444,6 +444,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521 }, ] +[[package]] +name = "events" +version = "0.1.0" +source = { editable = "../../../libraries/python/events" } +dependencies = [ + { name = "pydantic" }, +] + +[package.metadata] +requires-dist = [{ name = "pydantic", specifier = ">=2.6.1" }] + [[package]] name = "fastapi" version = "0.115.0" @@ -1023,6 +1034,7 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, + { name = "events" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -1035,6 +1047,7 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "events", editable = "../../../libraries/python/events" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, diff --git a/libraries/python/chat-driver/.vscode/settings.json b/libraries/python/chat-driver/.vscode/settings.json deleted file mode 100644 index d02aad67..00000000 --- a/libraries/python/chat-driver/.vscode/settings.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "editor.bracketPairColorization.enabled": true, - "editor.codeActionsOnSave": { - "source.fixAll": "always", - "source.organizeImports": "always" - }, - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnPaste": true, - "editor.formatOnSave": true, - "editor.formatOnType": true, - "editor.guides.bracketPairs": "active", - "files.eol": "\n", - "files.trimTrailingWhitespace": true, - "flake8.ignorePatterns": ["**/*.py"], // disable flake8 in favor of ruff - "jupyter.debugJustMyCode": false, - "python.analysis.autoFormatStrings": true, - "python.analysis.autoImportCompletions": true, - "python.analysis.diagnosticMode": "workspace", - "python.analysis.fixAll": ["source.unusedImports"], - "python.analysis.inlayHints.functionReturnTypes": true, - "python.analysis.typeCheckingMode": "basic", - "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python", - "python.testing.cwd": "${workspaceFolder}", - "search.exclude": { - "**/.venv": true, - "**/data": true - }, - "[json]": { - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true - }, - "[jsonc]": { - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true - }, - "[python]": { - "editor.defaultFormatter": "charliermarsh.ruff", - "editor.formatOnSave": true, - "editor.codeActionsOnSave": { - "source.fixAll": "explicit", - "source.unusedImports": "explicit", - "source.organizeImports": "explicit", - "source.formatDocument": "explicit" - } - }, - "ruff.nativeServer": "on", - "cSpell.words": [ - "dotenv", - "httpx", - "openai", - "pydantic", - "pypdf", - "runtimes", - "tiktoken" - ] -} diff --git a/libraries/python/chat-driver/Makefile b/libraries/python/chat-driver/Makefile deleted file mode 100644 index 1ad4520a..00000000 --- a/libraries/python/chat-driver/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -repo_root = $(shell git rev-parse --show-toplevel) -include $(repo_root)/tools/makefiles/python.mk diff --git a/libraries/python/chat-driver/chat_driver/__init__.py b/libraries/python/chat-driver/chat_driver/__init__.py deleted file mode 100644 index 4950ad56..00000000 --- a/libraries/python/chat-driver/chat_driver/__init__.py +++ /dev/null @@ -1,30 +0,0 @@ -# As a convenience, allow users to import the Context and ContextProtocol from -# the chat_driver package. -import logging - -from context import Context, ContextProtocol -from openai_client.completion import JSON_OBJECT_RESPONSE_FORMAT, TEXT_RESPONSE_FORMAT - -from .chat_driver import ( - ChatDriver, - ChatDriverConfig, -) -from .local_message_history_provider import LocalMessageHistoryProvider, LocalMessageHistoryProviderConfig -from .message_history_provider import MessageHistoryProviderProtocol - -logger = logging.getLogger(__name__) - -logger = logging.getLogger(__name__) - -__all__ = [ - "ChatDriver", - "ChatDriverConfig", - "Context", - "ContextProtocol", - "JSON_OBJECT_RESPONSE_FORMAT", - "JSON_OBJECT_RESPONSE_FORMAT", - "LocalMessageHistoryProvider", - "LocalMessageHistoryProviderConfig", - "MessageHistoryProviderProtocol", - "TEXT_RESPONSE_FORMAT", -] diff --git a/libraries/python/chat-driver/chat_driver/tests/formatted_instructions_test.py b/libraries/python/chat-driver/chat_driver/tests/formatted_instructions_test.py deleted file mode 100644 index c79ef24c..00000000 --- a/libraries/python/chat-driver/chat_driver/tests/formatted_instructions_test.py +++ /dev/null @@ -1,62 +0,0 @@ -from chat_driver.chat_driver import ChatDriver -from openai_client.messages import format_with_dict - - -def test_formatted_instructions() -> None: - # Set instructions. - instructions = [ - ( - "Generate an outline for the document, including title. The outline should include the key points that will" - " be covered in the document. Consider the attachments, the rationale for why they were uploaded, and the" - " conversation that has taken place. The outline should be a hierarchical structure with multiple levels of" - " detail, and it should be clear and easy to understand. The outline should be generated in a way that is" - " consistent with the document that will be generated from it." - ), - "{{chat_history}}", - "{% for attachment in attachments %}{{attachment.filename}}{{attachment.content}}{% endfor %}", - "{{outline_versions.last}}", - "{{user_feedback}}", - ] - - # Set vars. - attachments = [ - {"filename": "filename1", "content": "content1"}, - {"filename": "filename2", "content": "content2"}, - ] - outline_versions = ["outline1", "outline2"] - user_feedback = "feedback" - chat_history = "history" - formatted_instructions = ChatDriver.format_instructions( - instructions=instructions, - vars={ - "attachments": attachments, - "outline_versions": outline_versions, - "user_feedback": user_feedback, - "chat_history": chat_history, - }, - formatter=format_with_dict, - ) - - expected = [ - { - "role": "system", - "content": "Generate an outline for the document, including title. The outline should include the key points that will be covered in the document. Consider the attachments, the rationale for why they were uploaded, and the conversation that has taken place. The outline should be a hierarchical structure with multiple levels of detail, and it should be clear and easy to understand. The outline should be generated in a way that is consistent with the document that will be generated from it.", - }, - {"role": "system", "content": "history"}, - # { - # "role": "system", - # "content": "filename1content1", - # }, - # { - # "role": "system", - # "content": "filename2content2", - # }, - { - "role": "system", - "content": "filename1content1filename2content2", - }, - {"role": "system", "content": "outline2"}, - {"role": "system", "content": "feedback"}, - ] - - assert formatted_instructions == expected diff --git a/libraries/python/chat-driver/pyproject.toml b/libraries/python/chat-driver/pyproject.toml deleted file mode 100644 index 760baa3d..00000000 --- a/libraries/python/chat-driver/pyproject.toml +++ /dev/null @@ -1,31 +0,0 @@ -[project] -name = "chat-driver" -version = "0.1.0" -description = "MADE:Exploration Chat Driver" -authors = [{name="MADE:Explorers"}] -readme = "README.md" -requires-python = ">=3.11" -dependencies = [ - "azure-identity>=1.17.1", - "context>=0.1.0", - "events>=0.1.0", - "openai>=1.16.1", - "openai-client>=0.1.0", - "pydantic-settings>=2.3.4", - "pydantic>=2.6.1", - "python-dotenv>=1.0.1", - "requests>=2.32.0", - "tiktoken>=0.7.0", -] - -[tool.uv] -package = true - -[tool.uv.sources] -context = { path = "../context", editable = true } -events = { path = "../events", editable = true } -openai-client = { path = "../openai-client", editable = true } - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" diff --git a/libraries/python/chat-driver/uv.lock b/libraries/python/chat-driver/uv.lock deleted file mode 100644 index 46beaee0..00000000 --- a/libraries/python/chat-driver/uv.lock +++ /dev/null @@ -1,1677 +0,0 @@ -version = 1 -requires-python = ">=3.11" -resolution-markers = [ - "python_full_version < '3.13'", - "python_full_version >= '3.13'", -] - -[[package]] -name = "aiohappyeyeballs" -version = "2.4.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bc/69/2f6d5a019bd02e920a3417689a89887b39ad1e350b562f9955693d900c40/aiohappyeyeballs-2.4.3.tar.gz", hash = "sha256:75cf88a15106a5002a8eb1dab212525c00d1f4c0fa96e551c9fbe6f09a621586", size = 21809 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/d8/120cd0fe3e8530df0539e71ba9683eade12cae103dd7543e50d15f737917/aiohappyeyeballs-2.4.3-py3-none-any.whl", hash = "sha256:8a7a83727b2756f394ab2895ea0765a0a8c475e3c71e98d43d76f22b4b435572", size = 14742 }, -] - -[[package]] -name = "aiohttp" -version = "3.10.10" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohappyeyeballs" }, - { name = "aiosignal" }, - { name = "attrs" }, - { name = "frozenlist" }, - { name = "multidict" }, - { name = "yarl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/17/7e/16e57e6cf20eb62481a2f9ce8674328407187950ccc602ad07c685279141/aiohttp-3.10.10.tar.gz", hash = "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a", size = 7542993 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/72/31/3c351d17596194e5a38ef169a4da76458952b2497b4b54645b9d483cbbb0/aiohttp-3.10.10-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c30a0eafc89d28e7f959281b58198a9fa5e99405f716c0289b7892ca345fe45f", size = 586501 }, - { url = "https://files.pythonhosted.org/packages/a4/a8/a559d09eb08478cdead6b7ce05b0c4a133ba27fcdfa91e05d2e62867300d/aiohttp-3.10.10-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:258c5dd01afc10015866114e210fb7365f0d02d9d059c3c3415382ab633fcbcb", size = 398993 }, - { url = "https://files.pythonhosted.org/packages/c5/47/7736d4174613feef61d25332c3bd1a4f8ff5591fbd7331988238a7299485/aiohttp-3.10.10-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:15ecd889a709b0080f02721255b3f80bb261c2293d3c748151274dfea93ac871", size = 390647 }, - { url = "https://files.pythonhosted.org/packages/27/21/e9ba192a04b7160f5a8952c98a1de7cf8072ad150fa3abd454ead1ab1d7f/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3935f82f6f4a3820270842e90456ebad3af15810cf65932bd24da4463bc0a4c", size = 1306481 }, - { url = "https://files.pythonhosted.org/packages/cf/50/f364c01c8d0def1dc34747b2470969e216f5a37c7ece00fe558810f37013/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:413251f6fcf552a33c981c4709a6bba37b12710982fec8e558ae944bfb2abd38", size = 1344652 }, - { url = "https://files.pythonhosted.org/packages/1d/c2/74f608e984e9b585649e2e83883facad6fa3fc1d021de87b20cc67e8e5ae/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1720b4f14c78a3089562b8875b53e36b51c97c51adc53325a69b79b4b48ebcb", size = 1378498 }, - { url = "https://files.pythonhosted.org/packages/9f/a7/05a48c7c0a7a80a5591b1203bf1b64ca2ed6a2050af918d09c05852dc42b/aiohttp-3.10.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:679abe5d3858b33c2cf74faec299fda60ea9de62916e8b67e625d65bf069a3b7", size = 1292718 }, - { url = "https://files.pythonhosted.org/packages/7d/78/a925655018747e9790350180330032e27d6e0d7ed30bde545fae42f8c49c/aiohttp-3.10.10-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79019094f87c9fb44f8d769e41dbb664d6e8fcfd62f665ccce36762deaa0e911", size = 1251776 }, - { url = "https://files.pythonhosted.org/packages/47/9d/85c6b69f702351d1236594745a4fdc042fc43f494c247a98dac17e004026/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe2fb38c2ed905a2582948e2de560675e9dfbee94c6d5ccdb1301c6d0a5bf092", size = 1271716 }, - { url = "https://files.pythonhosted.org/packages/7f/a7/55fc805ff9b14af818903882ece08e2235b12b73b867b521b92994c52b14/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:a3f00003de6eba42d6e94fabb4125600d6e484846dbf90ea8e48a800430cc142", size = 1266263 }, - { url = "https://files.pythonhosted.org/packages/1f/ec/d2be2ca7b063e4f91519d550dbc9c1cb43040174a322470deed90b3d3333/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1bbb122c557a16fafc10354b9d99ebf2f2808a660d78202f10ba9d50786384b9", size = 1321617 }, - { url = "https://files.pythonhosted.org/packages/c9/a3/b29f7920e1cd0a9a68a45dd3eb16140074d2efb1518d2e1f3e140357dc37/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:30ca7c3b94708a9d7ae76ff281b2f47d8eaf2579cd05971b5dc681db8caac6e1", size = 1339227 }, - { url = "https://files.pythonhosted.org/packages/8a/81/34b67235c47e232d807b4bbc42ba9b927c7ce9476872372fddcfd1e41b3d/aiohttp-3.10.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:df9270660711670e68803107d55c2b5949c2e0f2e4896da176e1ecfc068b974a", size = 1299068 }, - { url = "https://files.pythonhosted.org/packages/04/1f/26a7fe11b6ad3184f214733428353c89ae9fe3e4f605a657f5245c5e720c/aiohttp-3.10.10-cp311-cp311-win32.whl", hash = "sha256:aafc8ee9b742ce75044ae9a4d3e60e3d918d15a4c2e08a6c3c3e38fa59b92d94", size = 362223 }, - { url = "https://files.pythonhosted.org/packages/10/91/85dcd93f64011434359ce2666bece981f08d31bc49df33261e625b28595d/aiohttp-3.10.10-cp311-cp311-win_amd64.whl", hash = "sha256:362f641f9071e5f3ee6f8e7d37d5ed0d95aae656adf4ef578313ee585b585959", size = 381576 }, - { url = "https://files.pythonhosted.org/packages/ae/99/4c5aefe5ad06a1baf206aed6598c7cdcbc7c044c46801cd0d1ecb758cae3/aiohttp-3.10.10-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9294bbb581f92770e6ed5c19559e1e99255e4ca604a22c5c6397b2f9dd3ee42c", size = 583536 }, - { url = "https://files.pythonhosted.org/packages/a9/36/8b3bc49b49cb6d2da40ee61ff15dbcc44fd345a3e6ab5bb20844df929821/aiohttp-3.10.10-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a8fa23fe62c436ccf23ff930149c047f060c7126eae3ccea005f0483f27b2e28", size = 395693 }, - { url = "https://files.pythonhosted.org/packages/e1/77/0aa8660dcf11fa65d61712dbb458c4989de220a844bd69778dff25f2d50b/aiohttp-3.10.10-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5c6a5b8c7926ba5d8545c7dd22961a107526562da31a7a32fa2456baf040939f", size = 390898 }, - { url = "https://files.pythonhosted.org/packages/38/d2/b833d95deb48c75db85bf6646de0a697e7fb5d87bd27cbade4f9746b48b1/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:007ec22fbc573e5eb2fb7dec4198ef8f6bf2fe4ce20020798b2eb5d0abda6138", size = 1312060 }, - { url = "https://files.pythonhosted.org/packages/aa/5f/29fd5113165a0893de8efedf9b4737e0ba92dfcd791415a528f947d10299/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9627cc1a10c8c409b5822a92d57a77f383b554463d1884008e051c32ab1b3742", size = 1350553 }, - { url = "https://files.pythonhosted.org/packages/ad/cc/f835f74b7d344428469200105236d44606cfa448be1e7c95ca52880d9bac/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:50edbcad60d8f0e3eccc68da67f37268b5144ecc34d59f27a02f9611c1d4eec7", size = 1392646 }, - { url = "https://files.pythonhosted.org/packages/bf/fe/1332409d845ca601893bbf2d76935e0b93d41686e5f333841c7d7a4a770d/aiohttp-3.10.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a45d85cf20b5e0d0aa5a8dca27cce8eddef3292bc29d72dcad1641f4ed50aa16", size = 1306310 }, - { url = "https://files.pythonhosted.org/packages/e4/a1/25a7633a5a513278a9892e333501e2e69c83e50be4b57a62285fb7a008c3/aiohttp-3.10.10-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b00807e2605f16e1e198f33a53ce3c4523114059b0c09c337209ae55e3823a8", size = 1260255 }, - { url = "https://files.pythonhosted.org/packages/f2/39/30eafe89e0e2a06c25e4762844c8214c0c0cd0fd9ffc3471694a7986f421/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f2d4324a98062be0525d16f768a03e0bbb3b9fe301ceee99611dc9a7953124e6", size = 1271141 }, - { url = "https://files.pythonhosted.org/packages/5b/fc/33125df728b48391ef1fcb512dfb02072158cc10d041414fb79803463020/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:438cd072f75bb6612f2aca29f8bd7cdf6e35e8f160bc312e49fbecab77c99e3a", size = 1280244 }, - { url = "https://files.pythonhosted.org/packages/3b/61/e42bf2c2934b5caa4e2ec0b5e5fd86989adb022b5ee60c2572a9d77cf6fe/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:baa42524a82f75303f714108fea528ccacf0386af429b69fff141ffef1c534f9", size = 1316805 }, - { url = "https://files.pythonhosted.org/packages/18/32/f52a5e2ae9ad3bba10e026a63a7a23abfa37c7d97aeeb9004eaa98df3ce3/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a7d8d14fe962153fc681f6366bdec33d4356f98a3e3567782aac1b6e0e40109a", size = 1343930 }, - { url = "https://files.pythonhosted.org/packages/05/be/6a403b464dcab3631fe8e27b0f1d906d9e45c5e92aca97ee007e5a895560/aiohttp-3.10.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c1277cd707c465cd09572a774559a3cc7c7a28802eb3a2a9472588f062097205", size = 1306186 }, - { url = "https://files.pythonhosted.org/packages/8e/fd/bb50fe781068a736a02bf5c7ad5f3ab53e39f1d1e63110da6d30f7605edc/aiohttp-3.10.10-cp312-cp312-win32.whl", hash = "sha256:59bb3c54aa420521dc4ce3cc2c3fe2ad82adf7b09403fa1f48ae45c0cbde6628", size = 359289 }, - { url = "https://files.pythonhosted.org/packages/70/9e/5add7e240f77ef67c275c82cc1d08afbca57b77593118c1f6e920ae8ad3f/aiohttp-3.10.10-cp312-cp312-win_amd64.whl", hash = "sha256:0e1b370d8007c4ae31ee6db7f9a2fe801a42b146cec80a86766e7ad5c4a259cf", size = 379313 }, - { url = "https://files.pythonhosted.org/packages/b1/eb/618b1b76c7fe8082a71c9d62e3fe84c5b9af6703078caa9ec57850a12080/aiohttp-3.10.10-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ad7593bb24b2ab09e65e8a1d385606f0f47c65b5a2ae6c551db67d6653e78c28", size = 576114 }, - { url = "https://files.pythonhosted.org/packages/aa/37/3126995d7869f8b30d05381b81a2d4fb4ec6ad313db788e009bc6d39c211/aiohttp-3.10.10-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1eb89d3d29adaf533588f209768a9c02e44e4baf832b08118749c5fad191781d", size = 391901 }, - { url = "https://files.pythonhosted.org/packages/3e/f2/8fdfc845be1f811c31ceb797968523813f8e1263ee3e9120d61253f6848f/aiohttp-3.10.10-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3fe407bf93533a6fa82dece0e74dbcaaf5d684e5a51862887f9eaebe6372cd79", size = 387418 }, - { url = "https://files.pythonhosted.org/packages/60/d5/33d2061d36bf07e80286e04b7e0a4de37ce04b5ebfed72dba67659a05250/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50aed5155f819873d23520919e16703fc8925e509abbb1a1491b0087d1cd969e", size = 1287073 }, - { url = "https://files.pythonhosted.org/packages/00/52/affb55be16a4747740bd630b4c002dac6c5eac42f9bb64202fc3cf3f1930/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f05e9727ce409358baa615dbeb9b969db94324a79b5a5cea45d39bdb01d82e6", size = 1323612 }, - { url = "https://files.pythonhosted.org/packages/94/f2/cddb69b975387daa2182a8442566971d6410b8a0179bb4540d81c97b1611/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dffb610a30d643983aeb185ce134f97f290f8935f0abccdd32c77bed9388b42", size = 1368406 }, - { url = "https://files.pythonhosted.org/packages/c1/e4/afba7327da4d932da8c6e29aecaf855f9d52dace53ac15bfc8030a246f1b/aiohttp-3.10.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa6658732517ddabe22c9036479eabce6036655ba87a0224c612e1ae6af2087e", size = 1282761 }, - { url = "https://files.pythonhosted.org/packages/9f/6b/364856faa0c9031ea76e24ef0f7fef79cddd9fa8e7dba9a1771c6acc56b5/aiohttp-3.10.10-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:741a46d58677d8c733175d7e5aa618d277cd9d880301a380fd296975a9cdd7bc", size = 1236518 }, - { url = "https://files.pythonhosted.org/packages/46/af/c382846f8356fe64a7b5908bb9b477457aa23b71be7ed551013b7b7d4d87/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e00e3505cd80440f6c98c6d69269dcc2a119f86ad0a9fd70bccc59504bebd68a", size = 1250344 }, - { url = "https://files.pythonhosted.org/packages/87/53/294f87fc086fd0772d0ab82497beb9df67f0f27a8b3dd5742a2656db2bc6/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ffe595f10566f8276b76dc3a11ae4bb7eba1aac8ddd75811736a15b0d5311414", size = 1248956 }, - { url = "https://files.pythonhosted.org/packages/86/30/7d746717fe11bdfefb88bb6c09c5fc985d85c4632da8bb6018e273899254/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdfcf6443637c148c4e1a20c48c566aa694fa5e288d34b20fcdc58507882fed3", size = 1293379 }, - { url = "https://files.pythonhosted.org/packages/48/b9/45d670a834458db67a24258e9139ba61fa3bd7d69b98ecf3650c22806f8f/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d183cf9c797a5291e8301790ed6d053480ed94070637bfaad914dd38b0981f67", size = 1320108 }, - { url = "https://files.pythonhosted.org/packages/72/8c/804bb2e837a175635d2000a0659eafc15b2e9d92d3d81c8f69e141ecd0b0/aiohttp-3.10.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:77abf6665ae54000b98b3c742bc6ea1d1fb31c394bcabf8b5d2c1ac3ebfe7f3b", size = 1281546 }, - { url = "https://files.pythonhosted.org/packages/89/c0/862e6a9de3d6eeb126cd9d9ea388243b70df9b871ce1a42b193b7a4a77fc/aiohttp-3.10.10-cp313-cp313-win32.whl", hash = "sha256:4470c73c12cd9109db8277287d11f9dd98f77fc54155fc71a7738a83ffcc8ea8", size = 357516 }, - { url = "https://files.pythonhosted.org/packages/ae/63/3e1aee3e554263f3f1011cca50d78a4894ae16ce99bf78101ac3a2f0ef74/aiohttp-3.10.10-cp313-cp313-win_amd64.whl", hash = "sha256:486f7aabfa292719a2753c016cc3a8f8172965cabb3ea2e7f7436c7f5a22a151", size = 376785 }, -] - -[[package]] -name = "aiosignal" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "frozenlist" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ae/67/0952ed97a9793b4958e5736f6d2b346b414a2cd63e82d05940032f45b32f/aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc", size = 19422 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/ac/a7305707cb852b7e16ff80eaf5692309bde30e2b1100a1fcacdc8f731d97/aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17", size = 7617 }, -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, -] - -[[package]] -name = "anyio" -version = "4.6.2.post1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "sniffio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9f/09/45b9b7a6d4e45c6bcb5bf61d19e3ab87df68e0601fa8c5293de3542546cc/anyio-4.6.2.post1.tar.gz", hash = "sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c", size = 173422 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e4/f5/f2b75d2fc6f1a260f340f0e7c6a060f4dd2961cc16884ed851b0d18da06a/anyio-4.6.2.post1-py3-none-any.whl", hash = "sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d", size = 90377 }, -] - -[[package]] -name = "asgi-correlation-id" -version = "4.3.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "packaging" }, - { name = "starlette" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/ff/a6538245ac1eaa7733ec6740774e9d5add019e2c63caa29e758c16c0afdd/asgi_correlation_id-4.3.4.tar.gz", hash = "sha256:ea6bc310380373cb9f731dc2e8b2b6fb978a76afe33f7a2384f697b8d6cd811d", size = 20075 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/ab/6936e2663c47a926e0659437b9333ad87d1ff49b1375d239026e0a268eba/asgi_correlation_id-4.3.4-py3-none-any.whl", hash = "sha256:36ce69b06c7d96b4acb89c7556a4c4f01a972463d3d49c675026cbbd08e9a0a2", size = 15262 }, -] - -[[package]] -name = "attrs" -version = "24.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fc/0f/aafca9af9315aee06a89ffde799a10a582fe8de76c563ee80bbcdc08b3fb/attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", size = 792678 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2", size = 63001 }, -] - -[[package]] -name = "azure-ai-contentsafety" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "azure-core" }, - { name = "isodate" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/08/e9/c069efade0e4976d96208306f1cf0803838cdb0b60e00a2a96bd20806bff/azure-ai-contentsafety-1.0.0.tar.gz", hash = "sha256:052731bd1419a720fa00910f46bf3428c4e5bd05280da7393d0c8106d46cc6d7", size = 63806 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/36/39/cbb3ff28ad09434a1be7803b2846077bc3b23a8232beb489962fc818fe21/azure_ai_contentsafety-1.0.0-py3-none-any.whl", hash = "sha256:e1c5574a541f9290fdd071d23535e14b1f463af231a6f0ac0f917e125f0463cf", size = 61328 }, -] - -[[package]] -name = "azure-core" -version = "1.32.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "requests" }, - { name = "six" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/cc/ee/668328306a9e963a5ad9f152cd98c7adad86c822729fd1d2a01613ad1e67/azure_core-1.32.0.tar.gz", hash = "sha256:22b3c35d6b2dae14990f6c1be2912bf23ffe50b220e708a28ab1bb92b1c730e5", size = 279128 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/39/83/325bf5e02504dbd8b4faa98197a44cdf8a325ef259b48326a2b6f17f8383/azure_core-1.32.0-py3-none-any.whl", hash = "sha256:eac191a0efb23bfa83fddf321b27b122b4ec847befa3091fa736a5c32c50d7b4", size = 198855 }, -] - -[package.optional-dependencies] -aio = [ - { name = "aiohttp" }, -] - -[[package]] -name = "azure-identity" -version = "1.19.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "azure-core" }, - { name = "cryptography" }, - { name = "msal" }, - { name = "msal-extensions" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/aa/91/cbaeff9eb0b838f0d35b4607ac1c6195c735c8eb17db235f8f60e622934c/azure_identity-1.19.0.tar.gz", hash = "sha256:500144dc18197d7019b81501165d4fa92225f03778f17d7ca8a2a180129a9c83", size = 263058 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f0/d5/3995ed12f941f4a41a273d9b1709282e825ef87ed8eab3833038fee54d59/azure_identity-1.19.0-py3-none-any.whl", hash = "sha256:e3f6558c181692d7509f09de10cca527c7dce426776454fb97df512a46527e81", size = 187587 }, -] - -[[package]] -name = "backoff" -version = "2.2.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/47/d7/5bbeb12c44d7c4f2fb5b56abce497eb5ed9f34d85701de869acedd602619/backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba", size = 17001 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/df/73/b6e24bd22e6720ca8ee9a85a0c4a2971af8497d8f3193fa05390cbd46e09/backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8", size = 15148 }, -] - -[[package]] -name = "certifi" -version = "2024.8.30" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/ee/9b19140fe824b367c04c5e1b369942dd754c4c5462d5674002f75c4dedc1/certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9", size = 168507 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", size = 167321 }, -] - -[[package]] -name = "cffi" -version = "1.17.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pycparser" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264 }, - { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651 }, - { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259 }, - { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200 }, - { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235 }, - { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721 }, - { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242 }, - { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999 }, - { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242 }, - { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604 }, - { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727 }, - { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400 }, - { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178 }, - { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840 }, - { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803 }, - { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850 }, - { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729 }, - { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256 }, - { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424 }, - { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568 }, - { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 }, - { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 }, - { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 }, - { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 }, - { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 }, - { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 }, - { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 }, - { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 }, - { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 }, - { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 }, - { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 }, - { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 }, - { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 }, - { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 }, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f2/4f/e1808dc01273379acc506d18f1504eb2d299bd4131743b9fc54d7be4df1e/charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e", size = 106620 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9c/61/73589dcc7a719582bf56aae309b6103d2762b526bffe189d635a7fcfd998/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c", size = 193339 }, - { url = "https://files.pythonhosted.org/packages/77/d5/8c982d58144de49f59571f940e329ad6e8615e1e82ef84584c5eeb5e1d72/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944", size = 124366 }, - { url = "https://files.pythonhosted.org/packages/bf/19/411a64f01ee971bed3231111b69eb56f9331a769072de479eae7de52296d/charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee", size = 118874 }, - { url = "https://files.pythonhosted.org/packages/4c/92/97509850f0d00e9f14a46bc751daabd0ad7765cff29cdfb66c68b6dad57f/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c", size = 138243 }, - { url = "https://files.pythonhosted.org/packages/e2/29/d227805bff72ed6d6cb1ce08eec707f7cfbd9868044893617eb331f16295/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6", size = 148676 }, - { url = "https://files.pythonhosted.org/packages/13/bc/87c2c9f2c144bedfa62f894c3007cd4530ba4b5351acb10dc786428a50f0/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea", size = 141289 }, - { url = "https://files.pythonhosted.org/packages/eb/5b/6f10bad0f6461fa272bfbbdf5d0023b5fb9bc6217c92bf068fa5a99820f5/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc", size = 142585 }, - { url = "https://files.pythonhosted.org/packages/3b/a0/a68980ab8a1f45a36d9745d35049c1af57d27255eff8c907e3add84cf68f/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5", size = 144408 }, - { url = "https://files.pythonhosted.org/packages/d7/a1/493919799446464ed0299c8eef3c3fad0daf1c3cd48bff9263c731b0d9e2/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594", size = 139076 }, - { url = "https://files.pythonhosted.org/packages/fb/9d/9c13753a5a6e0db4a0a6edb1cef7aee39859177b64e1a1e748a6e3ba62c2/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c", size = 146874 }, - { url = "https://files.pythonhosted.org/packages/75/d2/0ab54463d3410709c09266dfb416d032a08f97fd7d60e94b8c6ef54ae14b/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365", size = 150871 }, - { url = "https://files.pythonhosted.org/packages/8d/c9/27e41d481557be53d51e60750b85aa40eaf52b841946b3cdeff363105737/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129", size = 148546 }, - { url = "https://files.pythonhosted.org/packages/ee/44/4f62042ca8cdc0cabf87c0fc00ae27cd8b53ab68be3605ba6d071f742ad3/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236", size = 143048 }, - { url = "https://files.pythonhosted.org/packages/01/f8/38842422988b795220eb8038745d27a675ce066e2ada79516c118f291f07/charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99", size = 94389 }, - { url = "https://files.pythonhosted.org/packages/0b/6e/b13bd47fa9023b3699e94abf565b5a2f0b0be6e9ddac9812182596ee62e4/charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27", size = 101752 }, - { url = "https://files.pythonhosted.org/packages/d3/0b/4b7a70987abf9b8196845806198975b6aab4ce016632f817ad758a5aa056/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6", size = 194445 }, - { url = "https://files.pythonhosted.org/packages/50/89/354cc56cf4dd2449715bc9a0f54f3aef3dc700d2d62d1fa5bbea53b13426/charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf", size = 125275 }, - { url = "https://files.pythonhosted.org/packages/fa/44/b730e2a2580110ced837ac083d8ad222343c96bb6b66e9e4e706e4d0b6df/charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db", size = 119020 }, - { url = "https://files.pythonhosted.org/packages/9d/e4/9263b8240ed9472a2ae7ddc3e516e71ef46617fe40eaa51221ccd4ad9a27/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1", size = 139128 }, - { url = "https://files.pythonhosted.org/packages/6b/e3/9f73e779315a54334240353eaea75854a9a690f3f580e4bd85d977cb2204/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03", size = 149277 }, - { url = "https://files.pythonhosted.org/packages/1a/cf/f1f50c2f295312edb8a548d3fa56a5c923b146cd3f24114d5adb7e7be558/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284", size = 142174 }, - { url = "https://files.pythonhosted.org/packages/16/92/92a76dc2ff3a12e69ba94e7e05168d37d0345fa08c87e1fe24d0c2a42223/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15", size = 143838 }, - { url = "https://files.pythonhosted.org/packages/a4/01/2117ff2b1dfc61695daf2babe4a874bca328489afa85952440b59819e9d7/charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8", size = 146149 }, - { url = "https://files.pythonhosted.org/packages/f6/9b/93a332b8d25b347f6839ca0a61b7f0287b0930216994e8bf67a75d050255/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2", size = 140043 }, - { url = "https://files.pythonhosted.org/packages/ab/f6/7ac4a01adcdecbc7a7587767c776d53d369b8b971382b91211489535acf0/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719", size = 148229 }, - { url = "https://files.pythonhosted.org/packages/9d/be/5708ad18161dee7dc6a0f7e6cf3a88ea6279c3e8484844c0590e50e803ef/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631", size = 151556 }, - { url = "https://files.pythonhosted.org/packages/5a/bb/3d8bc22bacb9eb89785e83e6723f9888265f3a0de3b9ce724d66bd49884e/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b", size = 149772 }, - { url = "https://files.pythonhosted.org/packages/f7/fa/d3fc622de05a86f30beea5fc4e9ac46aead4731e73fd9055496732bcc0a4/charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565", size = 144800 }, - { url = "https://files.pythonhosted.org/packages/9a/65/bdb9bc496d7d190d725e96816e20e2ae3a6fa42a5cac99c3c3d6ff884118/charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7", size = 94836 }, - { url = "https://files.pythonhosted.org/packages/3e/67/7b72b69d25b89c0b3cea583ee372c43aa24df15f0e0f8d3982c57804984b/charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9", size = 102187 }, - { url = "https://files.pythonhosted.org/packages/f3/89/68a4c86f1a0002810a27f12e9a7b22feb198c59b2f05231349fbce5c06f4/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114", size = 194617 }, - { url = "https://files.pythonhosted.org/packages/4f/cd/8947fe425e2ab0aa57aceb7807af13a0e4162cd21eee42ef5b053447edf5/charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed", size = 125310 }, - { url = "https://files.pythonhosted.org/packages/5b/f0/b5263e8668a4ee9becc2b451ed909e9c27058337fda5b8c49588183c267a/charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250", size = 119126 }, - { url = "https://files.pythonhosted.org/packages/ff/6e/e445afe4f7fda27a533f3234b627b3e515a1b9429bc981c9a5e2aa5d97b6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920", size = 139342 }, - { url = "https://files.pythonhosted.org/packages/a1/b2/4af9993b532d93270538ad4926c8e37dc29f2111c36f9c629840c57cd9b3/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64", size = 149383 }, - { url = "https://files.pythonhosted.org/packages/fb/6f/4e78c3b97686b871db9be6f31d64e9264e889f8c9d7ab33c771f847f79b7/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23", size = 142214 }, - { url = "https://files.pythonhosted.org/packages/2b/c9/1c8fe3ce05d30c87eff498592c89015b19fade13df42850aafae09e94f35/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc", size = 144104 }, - { url = "https://files.pythonhosted.org/packages/ee/68/efad5dcb306bf37db7db338338e7bb8ebd8cf38ee5bbd5ceaaaa46f257e6/charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d", size = 146255 }, - { url = "https://files.pythonhosted.org/packages/0c/75/1ed813c3ffd200b1f3e71121c95da3f79e6d2a96120163443b3ad1057505/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88", size = 140251 }, - { url = "https://files.pythonhosted.org/packages/7d/0d/6f32255c1979653b448d3c709583557a4d24ff97ac4f3a5be156b2e6a210/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90", size = 148474 }, - { url = "https://files.pythonhosted.org/packages/ac/a0/c1b5298de4670d997101fef95b97ac440e8c8d8b4efa5a4d1ef44af82f0d/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b", size = 151849 }, - { url = "https://files.pythonhosted.org/packages/04/4f/b3961ba0c664989ba63e30595a3ed0875d6790ff26671e2aae2fdc28a399/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d", size = 149781 }, - { url = "https://files.pythonhosted.org/packages/d8/90/6af4cd042066a4adad58ae25648a12c09c879efa4849c705719ba1b23d8c/charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482", size = 144970 }, - { url = "https://files.pythonhosted.org/packages/cc/67/e5e7e0cbfefc4ca79025238b43cdf8a2037854195b37d6417f3d0895c4c2/charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67", size = 94973 }, - { url = "https://files.pythonhosted.org/packages/65/97/fc9bbc54ee13d33dc54a7fcf17b26368b18505500fc01e228c27b5222d80/charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b", size = 102308 }, - { url = "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", size = 49446 }, -] - -[[package]] -name = "chat-driver" -version = "0.1.0" -source = { editable = "." } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "events" }, - { name = "openai" }, - { name = "openai-client" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../context" }, - { name = "events", editable = "../events" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "openai-client", editable = "../openai-client" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[[package]] -name = "click" -version = "8.1.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "platform_system == 'Windows'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/96/d3/f04c7bfcf5c1862a2a5b845c6b2b360488cf47af55dfa79c98f6a6bf98b5/click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de", size = 336121 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", size = 97941 }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, -] - -[[package]] -name = "context" -version = "0.1.0" -source = { editable = "../context" } -dependencies = [ - { name = "events" }, -] - -[package.metadata] -requires-dist = [{ name = "events", editable = "../events" }] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - -[[package]] -name = "cryptography" -version = "43.0.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0d/05/07b55d1fa21ac18c3a8c79f764e2514e6f6a9698f1be44994f5adf0d29db/cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805", size = 686989 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/f3/01fdf26701a26f4b4dbc337a26883ad5bccaa6f1bbbdd29cd89e22f18a1c/cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e", size = 6225303 }, - { url = "https://files.pythonhosted.org/packages/a3/01/4896f3d1b392025d4fcbecf40fdea92d3df8662123f6835d0af828d148fd/cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e", size = 3760905 }, - { url = "https://files.pythonhosted.org/packages/0a/be/f9a1f673f0ed4b7f6c643164e513dbad28dd4f2dcdf5715004f172ef24b6/cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f", size = 3977271 }, - { url = "https://files.pythonhosted.org/packages/4e/49/80c3a7b5514d1b416d7350830e8c422a4d667b6d9b16a9392ebfd4a5388a/cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6", size = 3746606 }, - { url = "https://files.pythonhosted.org/packages/0e/16/a28ddf78ac6e7e3f25ebcef69ab15c2c6be5ff9743dd0709a69a4f968472/cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18", size = 3986484 }, - { url = "https://files.pythonhosted.org/packages/01/f5/69ae8da70c19864a32b0315049866c4d411cce423ec169993d0434218762/cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd", size = 3852131 }, - { url = "https://files.pythonhosted.org/packages/fd/db/e74911d95c040f9afd3612b1f732e52b3e517cb80de8bf183be0b7d413c6/cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73", size = 4075647 }, - { url = "https://files.pythonhosted.org/packages/56/48/7b6b190f1462818b324e674fa20d1d5ef3e24f2328675b9b16189cbf0b3c/cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2", size = 2623873 }, - { url = "https://files.pythonhosted.org/packages/eb/b1/0ebff61a004f7f89e7b65ca95f2f2375679d43d0290672f7713ee3162aff/cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd", size = 3068039 }, - { url = "https://files.pythonhosted.org/packages/30/d5/c8b32c047e2e81dd172138f772e81d852c51f0f2ad2ae8a24f1122e9e9a7/cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984", size = 6222984 }, - { url = "https://files.pythonhosted.org/packages/2f/78/55356eb9075d0be6e81b59f45c7b48df87f76a20e73893872170471f3ee8/cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5", size = 3762968 }, - { url = "https://files.pythonhosted.org/packages/2a/2c/488776a3dc843f95f86d2f957ca0fc3407d0242b50bede7fad1e339be03f/cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4", size = 3977754 }, - { url = "https://files.pythonhosted.org/packages/7c/04/2345ca92f7a22f601a9c62961741ef7dd0127c39f7310dffa0041c80f16f/cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7", size = 3749458 }, - { url = "https://files.pythonhosted.org/packages/ac/25/e715fa0bc24ac2114ed69da33adf451a38abb6f3f24ec207908112e9ba53/cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405", size = 3988220 }, - { url = "https://files.pythonhosted.org/packages/21/ce/b9c9ff56c7164d8e2edfb6c9305045fbc0df4508ccfdb13ee66eb8c95b0e/cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16", size = 3853898 }, - { url = "https://files.pythonhosted.org/packages/2a/33/b3682992ab2e9476b9c81fff22f02c8b0a1e6e1d49ee1750a67d85fd7ed2/cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73", size = 4076592 }, - { url = "https://files.pythonhosted.org/packages/81/1e/ffcc41b3cebd64ca90b28fd58141c5f68c83d48563c88333ab660e002cd3/cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995", size = 2623145 }, - { url = "https://files.pythonhosted.org/packages/87/5c/3dab83cc4aba1f4b0e733e3f0c3e7d4386440d660ba5b1e3ff995feb734d/cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362", size = 3068026 }, -] - -[[package]] -name = "deepmerge" -version = "2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a8/3a/b0ba594708f1ad0bc735884b3ad854d3ca3bdc1d741e56e40bbda6263499/deepmerge-2.0.tar.gz", hash = "sha256:5c3d86081fbebd04dd5de03626a0607b809a98fb6ccba5770b62466fe940ff20", size = 19890 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/82/e5d2c1c67d19841e9edc74954c827444ae826978499bde3dfc1d007c8c11/deepmerge-2.0-py3-none-any.whl", hash = "sha256:6de9ce507115cff0bed95ff0ce9ecc31088ef50cbdf09bc90a09349a318b3d00", size = 13475 }, -] - -[[package]] -name = "distro" -version = "1.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277 }, -] - -[[package]] -name = "dnspython" -version = "2.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632 }, -] - -[[package]] -name = "email-validator" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "dnspython" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521 }, -] - -[[package]] -name = "events" -version = "0.1.0" -source = { editable = "../events" } -dependencies = [ - { name = "pydantic" }, -] - -[package.metadata] -requires-dist = [{ name = "pydantic", specifier = ">=2.6.1" }] - -[[package]] -name = "fastapi" -version = "0.115.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "starlette" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a9/db/5781f19bd30745885e0737ff3fdd4e63e7bc691710f9da691128bb0dc73b/fastapi-0.115.4.tar.gz", hash = "sha256:db653475586b091cb8b2fec2ac54a680ac6a158e07406e1abae31679e8826349", size = 300737 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/f6/af0d1f58f86002be0cf1e2665cdd6f7a4a71cdc8a7a9438cdc9e3b5375fe/fastapi-0.115.4-py3-none-any.whl", hash = "sha256:0b504a063ffb3cf96a5e27dc1bc32c80ca743a2528574f9cdc77daa2d31b4742", size = 94732 }, -] - -[package.optional-dependencies] -standard = [ - { name = "email-validator" }, - { name = "fastapi-cli", extra = ["standard"] }, - { name = "httpx" }, - { name = "jinja2" }, - { name = "python-multipart" }, - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "fastapi-cli" -version = "0.0.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typer" }, - { name = "uvicorn", extra = ["standard"] }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c5/f8/1ad5ce32d029aeb9117e9a5a9b3e314a8477525d60c12a9b7730a3c186ec/fastapi_cli-0.0.5.tar.gz", hash = "sha256:d30e1239c6f46fcb95e606f02cdda59a1e2fa778a54b64686b3ff27f6211ff9f", size = 15571 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/24/ea/4b5011012ac925fe2f83b19d0e09cee9d324141ec7bf5e78bb2817f96513/fastapi_cli-0.0.5-py3-none-any.whl", hash = "sha256:e94d847524648c748a5350673546bbf9bcaeb086b33c24f2e82e021436866a46", size = 9489 }, -] - -[package.optional-dependencies] -standard = [ - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "frozenlist" -version = "1.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8f/ed/0f4cec13a93c02c47ec32d81d11c0c1efbadf4a471e3f3ce7cad366cbbd3/frozenlist-1.5.0.tar.gz", hash = "sha256:81d5af29e61b9c8348e876d442253723928dce6433e0e76cd925cd83f1b4b817", size = 39930 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/43/0bed28bf5eb1c9e4301003b74453b8e7aa85fb293b31dde352aac528dafc/frozenlist-1.5.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fd74520371c3c4175142d02a976aee0b4cb4a7cc912a60586ffd8d5929979b30", size = 94987 }, - { url = "https://files.pythonhosted.org/packages/bb/bf/b74e38f09a246e8abbe1e90eb65787ed745ccab6eaa58b9c9308e052323d/frozenlist-1.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2f3f7a0fbc219fb4455264cae4d9f01ad41ae6ee8524500f381de64ffaa077d5", size = 54584 }, - { url = "https://files.pythonhosted.org/packages/2c/31/ab01375682f14f7613a1ade30149f684c84f9b8823a4391ed950c8285656/frozenlist-1.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f47c9c9028f55a04ac254346e92977bf0f166c483c74b4232bee19a6697e4778", size = 52499 }, - { url = "https://files.pythonhosted.org/packages/98/a8/d0ac0b9276e1404f58fec3ab6e90a4f76b778a49373ccaf6a563f100dfbc/frozenlist-1.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0996c66760924da6e88922756d99b47512a71cfd45215f3570bf1e0b694c206a", size = 276357 }, - { url = "https://files.pythonhosted.org/packages/ad/c9/c7761084fa822f07dac38ac29f841d4587570dd211e2262544aa0b791d21/frozenlist-1.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a2fe128eb4edeabe11896cb6af88fca5346059f6c8d807e3b910069f39157869", size = 287516 }, - { url = "https://files.pythonhosted.org/packages/a1/ff/cd7479e703c39df7bdab431798cef89dc75010d8aa0ca2514c5b9321db27/frozenlist-1.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a8ea951bbb6cacd492e3948b8da8c502a3f814f5d20935aae74b5df2b19cf3d", size = 283131 }, - { url = "https://files.pythonhosted.org/packages/59/a0/370941beb47d237eca4fbf27e4e91389fd68699e6f4b0ebcc95da463835b/frozenlist-1.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:de537c11e4aa01d37db0d403b57bd6f0546e71a82347a97c6a9f0dcc532b3a45", size = 261320 }, - { url = "https://files.pythonhosted.org/packages/b8/5f/c10123e8d64867bc9b4f2f510a32042a306ff5fcd7e2e09e5ae5100ee333/frozenlist-1.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c2623347b933fcb9095841f1cc5d4ff0b278addd743e0e966cb3d460278840d", size = 274877 }, - { url = "https://files.pythonhosted.org/packages/fa/79/38c505601ae29d4348f21706c5d89755ceded02a745016ba2f58bd5f1ea6/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cee6798eaf8b1416ef6909b06f7dc04b60755206bddc599f52232606e18179d3", size = 269592 }, - { url = "https://files.pythonhosted.org/packages/19/e2/39f3a53191b8204ba9f0bb574b926b73dd2efba2a2b9d2d730517e8f7622/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f5f9da7f5dbc00a604fe74aa02ae7c98bcede8a3b8b9666f9f86fc13993bc71a", size = 265934 }, - { url = "https://files.pythonhosted.org/packages/d5/c9/3075eb7f7f3a91f1a6b00284af4de0a65a9ae47084930916f5528144c9dd/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:90646abbc7a5d5c7c19461d2e3eeb76eb0b204919e6ece342feb6032c9325ae9", size = 283859 }, - { url = "https://files.pythonhosted.org/packages/05/f5/549f44d314c29408b962fa2b0e69a1a67c59379fb143b92a0a065ffd1f0f/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:bdac3c7d9b705d253b2ce370fde941836a5f8b3c5c2b8fd70940a3ea3af7f4f2", size = 287560 }, - { url = "https://files.pythonhosted.org/packages/9d/f8/cb09b3c24a3eac02c4c07a9558e11e9e244fb02bf62c85ac2106d1eb0c0b/frozenlist-1.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:03d33c2ddbc1816237a67f66336616416e2bbb6beb306e5f890f2eb22b959cdf", size = 277150 }, - { url = "https://files.pythonhosted.org/packages/37/48/38c2db3f54d1501e692d6fe058f45b6ad1b358d82cd19436efab80cfc965/frozenlist-1.5.0-cp311-cp311-win32.whl", hash = "sha256:237f6b23ee0f44066219dae14c70ae38a63f0440ce6750f868ee08775073f942", size = 45244 }, - { url = "https://files.pythonhosted.org/packages/ca/8c/2ddffeb8b60a4bce3b196c32fcc30d8830d4615e7b492ec2071da801b8ad/frozenlist-1.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:0cc974cc93d32c42e7b0f6cf242a6bd941c57c61b618e78b6c0a96cb72788c1d", size = 51634 }, - { url = "https://files.pythonhosted.org/packages/79/73/fa6d1a96ab7fd6e6d1c3500700963eab46813847f01ef0ccbaa726181dd5/frozenlist-1.5.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:31115ba75889723431aa9a4e77d5f398f5cf976eea3bdf61749731f62d4a4a21", size = 94026 }, - { url = "https://files.pythonhosted.org/packages/ab/04/ea8bf62c8868b8eada363f20ff1b647cf2e93377a7b284d36062d21d81d1/frozenlist-1.5.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7437601c4d89d070eac8323f121fcf25f88674627505334654fd027b091db09d", size = 54150 }, - { url = "https://files.pythonhosted.org/packages/d0/9a/8e479b482a6f2070b26bda572c5e6889bb3ba48977e81beea35b5ae13ece/frozenlist-1.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7948140d9f8ece1745be806f2bfdf390127cf1a763b925c4a805c603df5e697e", size = 51927 }, - { url = "https://files.pythonhosted.org/packages/e3/12/2aad87deb08a4e7ccfb33600871bbe8f0e08cb6d8224371387f3303654d7/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:feeb64bc9bcc6b45c6311c9e9b99406660a9c05ca8a5b30d14a78555088b0b3a", size = 282647 }, - { url = "https://files.pythonhosted.org/packages/77/f2/07f06b05d8a427ea0060a9cef6e63405ea9e0d761846b95ef3fb3be57111/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:683173d371daad49cffb8309779e886e59c2f369430ad28fe715f66d08d4ab1a", size = 289052 }, - { url = "https://files.pythonhosted.org/packages/bd/9f/8bf45a2f1cd4aa401acd271b077989c9267ae8463e7c8b1eb0d3f561b65e/frozenlist-1.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7d57d8f702221405a9d9b40f9da8ac2e4a1a8b5285aac6100f3393675f0a85ee", size = 291719 }, - { url = "https://files.pythonhosted.org/packages/41/d1/1f20fd05a6c42d3868709b7604c9f15538a29e4f734c694c6bcfc3d3b935/frozenlist-1.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:30c72000fbcc35b129cb09956836c7d7abf78ab5416595e4857d1cae8d6251a6", size = 267433 }, - { url = "https://files.pythonhosted.org/packages/af/f2/64b73a9bb86f5a89fb55450e97cd5c1f84a862d4ff90d9fd1a73ab0f64a5/frozenlist-1.5.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:000a77d6034fbad9b6bb880f7ec073027908f1b40254b5d6f26210d2dab1240e", size = 283591 }, - { url = "https://files.pythonhosted.org/packages/29/e2/ffbb1fae55a791fd6c2938dd9ea779509c977435ba3940b9f2e8dc9d5316/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5d7f5a50342475962eb18b740f3beecc685a15b52c91f7d975257e13e029eca9", size = 273249 }, - { url = "https://files.pythonhosted.org/packages/2e/6e/008136a30798bb63618a114b9321b5971172a5abddff44a100c7edc5ad4f/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:87f724d055eb4785d9be84e9ebf0f24e392ddfad00b3fe036e43f489fafc9039", size = 271075 }, - { url = "https://files.pythonhosted.org/packages/ae/f0/4e71e54a026b06724cec9b6c54f0b13a4e9e298cc8db0f82ec70e151f5ce/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6e9080bb2fb195a046e5177f10d9d82b8a204c0736a97a153c2466127de87784", size = 285398 }, - { url = "https://files.pythonhosted.org/packages/4d/36/70ec246851478b1c0b59f11ef8ade9c482ff447c1363c2bd5fad45098b12/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9b93d7aaa36c966fa42efcaf716e6b3900438632a626fb09c049f6a2f09fc631", size = 294445 }, - { url = "https://files.pythonhosted.org/packages/37/e0/47f87544055b3349b633a03c4d94b405956cf2437f4ab46d0928b74b7526/frozenlist-1.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:52ef692a4bc60a6dd57f507429636c2af8b6046db8b31b18dac02cbc8f507f7f", size = 280569 }, - { url = "https://files.pythonhosted.org/packages/f9/7c/490133c160fb6b84ed374c266f42800e33b50c3bbab1652764e6e1fc498a/frozenlist-1.5.0-cp312-cp312-win32.whl", hash = "sha256:29d94c256679247b33a3dc96cce0f93cbc69c23bf75ff715919332fdbb6a32b8", size = 44721 }, - { url = "https://files.pythonhosted.org/packages/b1/56/4e45136ffc6bdbfa68c29ca56ef53783ef4c2fd395f7cbf99a2624aa9aaa/frozenlist-1.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:8969190d709e7c48ea386db202d708eb94bdb29207a1f269bab1196ce0dcca1f", size = 51329 }, - { url = "https://files.pythonhosted.org/packages/da/3b/915f0bca8a7ea04483622e84a9bd90033bab54bdf485479556c74fd5eaf5/frozenlist-1.5.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:7a1a048f9215c90973402e26c01d1cff8a209e1f1b53f72b95c13db61b00f953", size = 91538 }, - { url = "https://files.pythonhosted.org/packages/c7/d1/a7c98aad7e44afe5306a2b068434a5830f1470675f0e715abb86eb15f15b/frozenlist-1.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:dd47a5181ce5fcb463b5d9e17ecfdb02b678cca31280639255ce9d0e5aa67af0", size = 52849 }, - { url = "https://files.pythonhosted.org/packages/3a/c8/76f23bf9ab15d5f760eb48701909645f686f9c64fbb8982674c241fbef14/frozenlist-1.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1431d60b36d15cda188ea222033eec8e0eab488f39a272461f2e6d9e1a8e63c2", size = 50583 }, - { url = "https://files.pythonhosted.org/packages/1f/22/462a3dd093d11df623179d7754a3b3269de3b42de2808cddef50ee0f4f48/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6482a5851f5d72767fbd0e507e80737f9c8646ae7fd303def99bfe813f76cf7f", size = 265636 }, - { url = "https://files.pythonhosted.org/packages/80/cf/e075e407fc2ae7328155a1cd7e22f932773c8073c1fc78016607d19cc3e5/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44c49271a937625619e862baacbd037a7ef86dd1ee215afc298a417ff3270608", size = 270214 }, - { url = "https://files.pythonhosted.org/packages/a1/58/0642d061d5de779f39c50cbb00df49682832923f3d2ebfb0fedf02d05f7f/frozenlist-1.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:12f78f98c2f1c2429d42e6a485f433722b0061d5c0b0139efa64f396efb5886b", size = 273905 }, - { url = "https://files.pythonhosted.org/packages/ab/66/3fe0f5f8f2add5b4ab7aa4e199f767fd3b55da26e3ca4ce2cc36698e50c4/frozenlist-1.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce3aa154c452d2467487765e3adc730a8c153af77ad84096bc19ce19a2400840", size = 250542 }, - { url = "https://files.pythonhosted.org/packages/f6/b8/260791bde9198c87a465224e0e2bb62c4e716f5d198fc3a1dacc4895dbd1/frozenlist-1.5.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b7dc0c4338e6b8b091e8faf0db3168a37101943e687f373dce00959583f7439", size = 267026 }, - { url = "https://files.pythonhosted.org/packages/2e/a4/3d24f88c527f08f8d44ade24eaee83b2627793fa62fa07cbb7ff7a2f7d42/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:45e0896250900b5aa25180f9aec243e84e92ac84bd4a74d9ad4138ef3f5c97de", size = 257690 }, - { url = "https://files.pythonhosted.org/packages/de/9a/d311d660420b2beeff3459b6626f2ab4fb236d07afbdac034a4371fe696e/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:561eb1c9579d495fddb6da8959fd2a1fca2c6d060d4113f5844b433fc02f2641", size = 253893 }, - { url = "https://files.pythonhosted.org/packages/c6/23/e491aadc25b56eabd0f18c53bb19f3cdc6de30b2129ee0bc39cd387cd560/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:df6e2f325bfee1f49f81aaac97d2aa757c7646534a06f8f577ce184afe2f0a9e", size = 267006 }, - { url = "https://files.pythonhosted.org/packages/08/c4/ab918ce636a35fb974d13d666dcbe03969592aeca6c3ab3835acff01f79c/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:140228863501b44b809fb39ec56b5d4071f4d0aa6d216c19cbb08b8c5a7eadb9", size = 276157 }, - { url = "https://files.pythonhosted.org/packages/c0/29/3b7a0bbbbe5a34833ba26f686aabfe982924adbdcafdc294a7a129c31688/frozenlist-1.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7707a25d6a77f5d27ea7dc7d1fc608aa0a478193823f88511ef5e6b8a48f9d03", size = 264642 }, - { url = "https://files.pythonhosted.org/packages/ab/42/0595b3dbffc2e82d7fe658c12d5a5bafcd7516c6bf2d1d1feb5387caa9c1/frozenlist-1.5.0-cp313-cp313-win32.whl", hash = "sha256:31a9ac2b38ab9b5a8933b693db4939764ad3f299fcaa931a3e605bc3460e693c", size = 44914 }, - { url = "https://files.pythonhosted.org/packages/17/c4/b7db1206a3fea44bf3b838ca61deb6f74424a8a5db1dd53ecb21da669be6/frozenlist-1.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:11aabdd62b8b9c4b84081a3c246506d1cddd2dd93ff0ad53ede5defec7886b28", size = 51167 }, - { url = "https://files.pythonhosted.org/packages/c6/c8/a5be5b7550c10858fcf9b0ea054baccab474da77d37f1e828ce043a3a5d4/frozenlist-1.5.0-py3-none-any.whl", hash = "sha256:d994863bba198a4a518b467bb971c56e1db3f180a25c6cf7bb1949c267f748c3", size = 11901 }, -] - -[[package]] -name = "h11" -version = "0.14.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 }, -] - -[[package]] -name = "httpcore" -version = "1.0.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b6/44/ed0fa6a17845fb033bd885c03e842f08c1b9406c86a2e60ac1ae1b9206a6/httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f", size = 85180 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/06/89/b161908e2f51be56568184aeb4a880fd287178d176fd1c860d2217f41106/httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f", size = 78011 }, -] - -[[package]] -name = "httptools" -version = "0.6.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/26/bb526d4d14c2774fe07113ca1db7255737ffbb119315839af2065abfdac3/httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069", size = 199029 }, - { url = "https://files.pythonhosted.org/packages/a6/17/3e0d3e9b901c732987a45f4f94d4e2c62b89a041d93db89eafb262afd8d5/httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a", size = 103492 }, - { url = "https://files.pythonhosted.org/packages/b7/24/0fe235d7b69c42423c7698d086d4db96475f9b50b6ad26a718ef27a0bce6/httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975", size = 462891 }, - { url = "https://files.pythonhosted.org/packages/b1/2f/205d1f2a190b72da6ffb5f41a3736c26d6fa7871101212b15e9b5cd8f61d/httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636", size = 459788 }, - { url = "https://files.pythonhosted.org/packages/6e/4c/d09ce0eff09057a206a74575ae8f1e1e2f0364d20e2442224f9e6612c8b9/httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721", size = 433214 }, - { url = "https://files.pythonhosted.org/packages/3e/d2/84c9e23edbccc4a4c6f96a1b8d99dfd2350289e94f00e9ccc7aadde26fb5/httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988", size = 434120 }, - { url = "https://files.pythonhosted.org/packages/d0/46/4d8e7ba9581416de1c425b8264e2cadd201eb709ec1584c381f3e98f51c1/httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17", size = 88565 }, - { url = "https://files.pythonhosted.org/packages/bb/0e/d0b71465c66b9185f90a091ab36389a7352985fe857e352801c39d6127c8/httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2", size = 200683 }, - { url = "https://files.pythonhosted.org/packages/e2/b8/412a9bb28d0a8988de3296e01efa0bd62068b33856cdda47fe1b5e890954/httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44", size = 104337 }, - { url = "https://files.pythonhosted.org/packages/9b/01/6fb20be3196ffdc8eeec4e653bc2a275eca7f36634c86302242c4fbb2760/httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1", size = 508796 }, - { url = "https://files.pythonhosted.org/packages/f7/d8/b644c44acc1368938317d76ac991c9bba1166311880bcc0ac297cb9d6bd7/httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2", size = 510837 }, - { url = "https://files.pythonhosted.org/packages/52/d8/254d16a31d543073a0e57f1c329ca7378d8924e7e292eda72d0064987486/httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81", size = 485289 }, - { url = "https://files.pythonhosted.org/packages/5f/3c/4aee161b4b7a971660b8be71a92c24d6c64372c1ab3ae7f366b3680df20f/httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", size = 489779 }, - { url = "https://files.pythonhosted.org/packages/12/b7/5cae71a8868e555f3f67a50ee7f673ce36eac970f029c0c5e9d584352961/httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970", size = 88634 }, - { url = "https://files.pythonhosted.org/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214 }, - { url = "https://files.pythonhosted.org/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431 }, - { url = "https://files.pythonhosted.org/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121 }, - { url = "https://files.pythonhosted.org/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071", size = 473805 }, - { url = "https://files.pythonhosted.org/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858 }, - { url = "https://files.pythonhosted.org/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042 }, - { url = "https://files.pythonhosted.org/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682 }, -] - -[[package]] -name = "httpx" -version = "0.27.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, - { name = "sniffio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/78/82/08f8c936781f67d9e6b9eeb8a0c8b4e406136ea4c3d1f89a5db71d42e0e6/httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2", size = 144189 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0", size = 76395 }, -] - -[[package]] -name = "idna" -version = "3.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, -] - -[[package]] -name = "importlib-resources" -version = "6.4.5" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/be/f3e8c6081b684f176b761e6a2fef02a0be939740ed6f54109a2951d806f3/importlib_resources-6.4.5.tar.gz", hash = "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065", size = 43372 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e1/6a/4604f9ae2fa62ef47b9de2fa5ad599589d28c9fd1d335f32759813dfa91e/importlib_resources-6.4.5-py3-none-any.whl", hash = "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717", size = 36115 }, -] - -[[package]] -name = "isodate" -version = "0.7.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/4d/e940025e2ce31a8ce1202635910747e5a87cc3a6a6bb2d00973375014749/isodate-0.7.2.tar.gz", hash = "sha256:4cd1aa0f43ca76f4a6c6c0292a85f40b35ec2e43e315b59f06e6d32171a953e6", size = 29705 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/15/aa/0aca39a37d3c7eb941ba736ede56d689e7be91cab5d9ca846bde3999eba6/isodate-0.7.2-py3-none-any.whl", hash = "sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15", size = 22320 }, -] - -[[package]] -name = "jinja2" -version = "3.1.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ed/55/39036716d19cab0747a5020fc7e907f362fbf48c984b14e62127f7e68e5d/jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", size = 240245 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/31/80/3a54838c3fb461f6fec263ebf3a3a41771bd05190238de3486aae8540c36/jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d", size = 133271 }, -] - -[[package]] -name = "jiter" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ac/3d/4ca1c6b8d1d15ea747da474891f9879c0f0777e2e44e87c0be81657ed016/jiter-0.7.0.tar.gz", hash = "sha256:c061d9738535497b5509f8970584f20de1e900806b239a39a9994fc191dad630", size = 162154 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/01/ac41fe6d402da0ff454e2abaee6b8cc29ad2c97cf985f503e46ca7724aca/jiter-0.7.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:91cec0ad755bd786c9f769ce8d843af955df6a8e56b17658771b2d5cb34a3ff8", size = 292667 }, - { url = "https://files.pythonhosted.org/packages/9d/cb/d2e612729676cbe022ad732aaed9c842ac459a70808a927f7f845cfc6dc1/jiter-0.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:feba70a28a27d962e353e978dbb6afd798e711c04cb0b4c5e77e9d3779033a1a", size = 306403 }, - { url = "https://files.pythonhosted.org/packages/e9/db/d88002c550f6405dbf98962cc3dc1c8e66de9c4f3246abebe1582b2f919f/jiter-0.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9d866ec066c3616cacb8535dbda38bb1d470b17b25f0317c4540182bc886ce2", size = 329020 }, - { url = "https://files.pythonhosted.org/packages/18/42/54d6527bcdea2909396849491b96a6fe595bd97ec43bdc522399c534ed33/jiter-0.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8e7a7a00b6f9f18289dd563596f97ecaba6c777501a8ba04bf98e03087bcbc60", size = 347638 }, - { url = "https://files.pythonhosted.org/packages/ec/12/a3c43061d5e189def91c07472e64a569196687f60c2f86150e29a5692ce7/jiter-0.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9aaf564094c7db8687f2660605e099f3d3e6ea5e7135498486674fcb78e29165", size = 373916 }, - { url = "https://files.pythonhosted.org/packages/32/08/2c7432ed26d194927ec07c1dfc08cdae5b6d302369df7fdda320d6393736/jiter-0.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a4d27e09825c1b3c7a667adb500ce8b840e8fc9f630da8454b44cdd4fb0081bb", size = 390942 }, - { url = "https://files.pythonhosted.org/packages/65/9b/70f3ecbd3f18ef19e50fbe5a51bdb1c520282720896c16ae1a68b90675b8/jiter-0.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ca7c287da9c1d56dda88da1d08855a787dbb09a7e2bd13c66a2e288700bd7c7", size = 327315 }, - { url = "https://files.pythonhosted.org/packages/2c/30/ba97e50e5fe1f58a1012257e0cfac0cc09e548b63f81982546c6dac8f1e7/jiter-0.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db19a6d160f093cbc8cd5ea2abad420b686f6c0e5fb4f7b41941ebc6a4f83cda", size = 367159 }, - { url = "https://files.pythonhosted.org/packages/a1/6d/73bb48ca87951c6c01b902258d0b792ed9404980bafceb1aa87ac43eb925/jiter-0.7.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6e46a63c7f877cf7441ffc821c28287cfb9f533ae6ed707bde15e7d4dfafa7ae", size = 514891 }, - { url = "https://files.pythonhosted.org/packages/6f/03/50c665a3d9067c5e384604310d67a184ae3176f27f677ca0c2670bb061ac/jiter-0.7.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7ba426fa7ff21cb119fa544b75dd3fbee6a70e55a5829709c0338d07ccd30e6d", size = 498039 }, - { url = "https://files.pythonhosted.org/packages/85/35/9fb7c7fea9b9c159d2089ea9b5ff4e3e56e2d42069456e3568dadf904e99/jiter-0.7.0-cp311-none-win32.whl", hash = "sha256:c07f55a64912b0c7982377831210836d2ea92b7bd343fca67a32212dd72e38e0", size = 198533 }, - { url = "https://files.pythonhosted.org/packages/96/19/e9b32c69c6dea404d983847e92cf86c3287b0f2f3e7621180a544c0ff153/jiter-0.7.0-cp311-none-win_amd64.whl", hash = "sha256:ed27b2c43e1b5f6c7fedc5c11d4d8bfa627de42d1143d87e39e2e83ddefd861a", size = 205728 }, - { url = "https://files.pythonhosted.org/packages/d9/7b/ed881a65e8f0989913408643b68a3a0913365c5c3884e85bae01a9679dd5/jiter-0.7.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:ac7930bcaaeb1e229e35c91c04ed2e9f39025b86ee9fc3141706bbf6fff4aeeb", size = 292762 }, - { url = "https://files.pythonhosted.org/packages/d8/44/d0409912bc28508abffd99b9d55baba869592c1d27f9ee1cc035ef62371e/jiter-0.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:571feae3e7c901a8eedde9fd2865b0dfc1432fb15cab8c675a8444f7d11b7c5d", size = 302790 }, - { url = "https://files.pythonhosted.org/packages/8d/4f/38d0e87c8863c1b1f2dbac48acca8da85f6931a7b735e7163781843170a5/jiter-0.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8af4df8a262fa2778b68c2a03b6e9d1cb4d43d02bea6976d46be77a3a331af1", size = 329246 }, - { url = "https://files.pythonhosted.org/packages/88/3c/1af75094cbeba25df672b3f772dc717203be843e08248a0e03ef0ca382bc/jiter-0.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd028d4165097a611eb0c7494d8c1f2aebd46f73ca3200f02a175a9c9a6f22f5", size = 347808 }, - { url = "https://files.pythonhosted.org/packages/0b/74/55f00ca01223665e1418bec76cdeebb17a5f9ffae94e886da5c9bef5abd2/jiter-0.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6b487247c7836810091e9455efe56a52ec51bfa3a222237e1587d04d3e04527", size = 374011 }, - { url = "https://files.pythonhosted.org/packages/f7/ae/c1c892861796aa0adb720da75c59de5dbcf74ad51243c2aeea46681dcb16/jiter-0.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6d28a92f28814e1a9f2824dc11f4e17e1df1f44dc4fdeb94c5450d34bcb2602", size = 388863 }, - { url = "https://files.pythonhosted.org/packages/9d/a2/914587a68cba16920b1f979267a4e5c19f6977cac8fb8a6fbbd00035d0ed/jiter-0.7.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90443994bbafe134f0b34201dad3ebe1c769f0599004084e046fb249ad912425", size = 326765 }, - { url = "https://files.pythonhosted.org/packages/c8/ea/79abc48a6c9ba9ee3ccb0c194ec4cc1dd62e523c7c7003189380d00e5f16/jiter-0.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f9abf464f9faac652542ce8360cea8e68fba2b78350e8a170248f9bcc228702a", size = 367756 }, - { url = "https://files.pythonhosted.org/packages/4b/eb/ddc874819382081f9ad71cf681ee76450b17ac981f78a8db6408e7e28f34/jiter-0.7.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db7a8d99fc5f842f7d2852f06ccaed066532292c41723e5dff670c339b649f88", size = 515349 }, - { url = "https://files.pythonhosted.org/packages/af/9d/816d2d7f19070b72cf0133437cbacf99a9202f6fbbc2cfa2111fb686b0e0/jiter-0.7.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:15cf691ebd8693b70c94627d6b748f01e6d697d9a6e9f2bc310934fcfb7cf25e", size = 498050 }, - { url = "https://files.pythonhosted.org/packages/3e/a5/d0afb758c02d2d3c8ac3214a5be26579594d790944eaee7a47af06915e0e/jiter-0.7.0-cp312-none-win32.whl", hash = "sha256:9dcd54fa422fb66ca398bec296fed5f58e756aa0589496011cfea2abb5be38a5", size = 198912 }, - { url = "https://files.pythonhosted.org/packages/d0/8e/80b2afd0391a3530966d8fc2f9c104955ba41093b3c319ae40b25e68e323/jiter-0.7.0-cp312-none-win_amd64.whl", hash = "sha256:cc989951f73f9375b8eacd571baaa057f3d7d11b7ce6f67b9d54642e7475bfad", size = 199942 }, - { url = "https://files.pythonhosted.org/packages/50/bb/82c7180dc126687ddcc25386727b3a1688ab8eff496afe7838b69886fcc7/jiter-0.7.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:24cecd18df540963cd27c08ca5ce1d0179f229ff78066d9eecbe5add29361340", size = 292624 }, - { url = "https://files.pythonhosted.org/packages/11/c2/3b6d4596eab2ff81ebfe5bab779f457433cc2ffb8a2d1d6ab5ac187f26f6/jiter-0.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d41b46236b90b043cca73785674c23d2a67d16f226394079d0953f94e765ed76", size = 304723 }, - { url = "https://files.pythonhosted.org/packages/49/65/56f78dfccfb22e43815cad4a468b4360f8cfebecc024edb5e2a625b83a04/jiter-0.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b160db0987171365c153e406a45dcab0ee613ae3508a77bfff42515cb4ce4d6e", size = 328319 }, - { url = "https://files.pythonhosted.org/packages/fd/f2/9e3ed9ac0b122dd65250fc83cd0f0979da82f055ef6041411191f6301284/jiter-0.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d1c8d91e0f0bd78602eaa081332e8ee4f512c000716f5bc54e9a037306d693a7", size = 347323 }, - { url = "https://files.pythonhosted.org/packages/42/18/24517f9f8575daf36fdac9dd53fcecde3d4c5bdd9f7b97a55e26ed2555b5/jiter-0.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:997706c683195eeff192d2e5285ce64d2a610414f37da3a3f2625dcf8517cf90", size = 374073 }, - { url = "https://files.pythonhosted.org/packages/a1/b1/b368ccdeff3eabb4b293a21a94317a6f717ecc5bfbfca4eecd12ff39da3f/jiter-0.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ea52a8a0ff0229ab2920284079becd2bae0688d432fca94857ece83bb49c541", size = 388224 }, - { url = "https://files.pythonhosted.org/packages/92/1e/cc3d0655bcbc026e4b7746cb1ccab10d6eb2c29ffa64e574072db4d55f73/jiter-0.7.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d77449d2738cf74752bb35d75ee431af457e741124d1db5e112890023572c7c", size = 326145 }, - { url = "https://files.pythonhosted.org/packages/bb/24/d410c732326738d4f392689621ff14e10d3717efe7de9ecb97c44d8765a3/jiter-0.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8203519907a1d81d6cb00902c98e27c2d0bf25ce0323c50ca594d30f5f1fbcf", size = 366857 }, - { url = "https://files.pythonhosted.org/packages/14/a1/53df95b8248968936e7ba9eb5839918e3cfd183e56356d2961b9b29a49fc/jiter-0.7.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41d15ccc53931c822dd7f1aebf09faa3cda2d7b48a76ef304c7dbc19d1302e51", size = 514972 }, - { url = "https://files.pythonhosted.org/packages/97/c8/1876add533606ff1204450dd2564638cac7f164ff90844cb921cdf25cf68/jiter-0.7.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:febf3179b2fabf71fbd2fd52acb8594163bb173348b388649567a548f356dbf6", size = 497728 }, - { url = "https://files.pythonhosted.org/packages/94/31/1e59f246e264414b004864b63783e54aa3397be88f53dda3b01db3ae4251/jiter-0.7.0-cp313-none-win32.whl", hash = "sha256:4a8e2d866e7eda19f012444e01b55079d8e1c4c30346aaac4b97e80c54e2d6d3", size = 198660 }, - { url = "https://files.pythonhosted.org/packages/ca/96/58b3d260e212add0087563672931b1176e70bef1225839a4470ec66157a5/jiter-0.7.0-cp313-none-win_amd64.whl", hash = "sha256:7417c2b928062c496f381fb0cb50412eee5ad1d8b53dbc0e011ce45bb2de522c", size = 199305 }, -] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, -] - -[[package]] -name = "markupsafe" -version = "3.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353 }, - { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392 }, - { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984 }, - { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120 }, - { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032 }, - { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057 }, - { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359 }, - { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306 }, - { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094 }, - { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521 }, - { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, - { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, - { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, - { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 }, - { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 }, - { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 }, - { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 }, - { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, - { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, - { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, - { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 }, - { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 }, - { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 }, - { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 }, - { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 }, - { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 }, - { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 }, - { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 }, - { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 }, - { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 }, - { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 }, - { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 }, - { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 }, - { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 }, - { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 }, - { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 }, - { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 }, - { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 }, - { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, - { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, -] - -[[package]] -name = "msal" -version = "1.31.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cryptography" }, - { name = "pyjwt", extra = ["crypto"] }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/59/04/8d7aa5c671a26ca5612257fd419f97380ba89cdd231b2eb67df58483796d/msal-1.31.0.tar.gz", hash = "sha256:2c4f189cf9cc8f00c80045f66d39b7c0f3ed45873fd3d1f2af9f22db2e12ff4b", size = 144950 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cd/40/0a5d743484e1ad00493bdffa8d10d7dbc6a51fec95290ad396e47e79fa43/msal-1.31.0-py3-none-any.whl", hash = "sha256:96bc37cff82ebe4b160d5fc0f1196f6ca8b50e274ecd0ec5bf69c438514086e7", size = 113109 }, -] - -[[package]] -name = "msal-extensions" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "msal" }, - { name = "portalocker" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2d/38/ad49272d0a5af95f7a0cb64a79bbd75c9c187f3b789385a143d8d537a5eb/msal_extensions-1.2.0.tar.gz", hash = "sha256:6f41b320bfd2933d631a215c91ca0dd3e67d84bd1a2f50ce917d5874ec646bef", size = 22391 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/69/314d887a01599669fb330da14e5c6ff5f138609e322812a942a74ef9b765/msal_extensions-1.2.0-py3-none-any.whl", hash = "sha256:cf5ba83a2113fa6dc011a254a72f1c223c88d7dfad74cc30617c4679a417704d", size = 19254 }, -] - -[[package]] -name = "multidict" -version = "6.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/be/504b89a5e9ca731cd47487e91c469064f8ae5af93b7259758dcfc2b9c848/multidict-6.1.0.tar.gz", hash = "sha256:22ae2ebf9b0c69d206c003e2f6a914ea33f0a932d4aa16f236afc049d9958f4a", size = 64002 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/93/13/df3505a46d0cd08428e4c8169a196131d1b0c4b515c3649829258843dde6/multidict-6.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3efe2c2cb5763f2f1b275ad2bf7a287d3f7ebbef35648a9726e3b69284a4f3d6", size = 48570 }, - { url = "https://files.pythonhosted.org/packages/f0/e1/a215908bfae1343cdb72f805366592bdd60487b4232d039c437fe8f5013d/multidict-6.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7053d3b0353a8b9de430a4f4b4268ac9a4fb3481af37dfe49825bf45ca24156", size = 29316 }, - { url = "https://files.pythonhosted.org/packages/70/0f/6dc70ddf5d442702ed74f298d69977f904960b82368532c88e854b79f72b/multidict-6.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:27e5fc84ccef8dfaabb09d82b7d179c7cf1a3fbc8a966f8274fcb4ab2eb4cadb", size = 29640 }, - { url = "https://files.pythonhosted.org/packages/d8/6d/9c87b73a13d1cdea30b321ef4b3824449866bd7f7127eceed066ccb9b9ff/multidict-6.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e2b90b43e696f25c62656389d32236e049568b39320e2735d51f08fd362761b", size = 131067 }, - { url = "https://files.pythonhosted.org/packages/cc/1e/1b34154fef373371fd6c65125b3d42ff5f56c7ccc6bfff91b9b3c60ae9e0/multidict-6.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d83a047959d38a7ff552ff94be767b7fd79b831ad1cd9920662db05fec24fe72", size = 138507 }, - { url = "https://files.pythonhosted.org/packages/fb/e0/0bc6b2bac6e461822b5f575eae85da6aae76d0e2a79b6665d6206b8e2e48/multidict-6.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1a9dd711d0877a1ece3d2e4fea11a8e75741ca21954c919406b44e7cf971304", size = 133905 }, - { url = "https://files.pythonhosted.org/packages/ba/af/73d13b918071ff9b2205fcf773d316e0f8fefb4ec65354bbcf0b10908cc6/multidict-6.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec2abea24d98246b94913b76a125e855eb5c434f7c46546046372fe60f666351", size = 129004 }, - { url = "https://files.pythonhosted.org/packages/74/21/23960627b00ed39643302d81bcda44c9444ebcdc04ee5bedd0757513f259/multidict-6.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4867cafcbc6585e4b678876c489b9273b13e9fff9f6d6d66add5e15d11d926cb", size = 121308 }, - { url = "https://files.pythonhosted.org/packages/8b/5c/cf282263ffce4a596ed0bb2aa1a1dddfe1996d6a62d08842a8d4b33dca13/multidict-6.1.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5b48204e8d955c47c55b72779802b219a39acc3ee3d0116d5080c388970b76e3", size = 132608 }, - { url = "https://files.pythonhosted.org/packages/d7/3e/97e778c041c72063f42b290888daff008d3ab1427f5b09b714f5a8eff294/multidict-6.1.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8fff389528cad1618fb4b26b95550327495462cd745d879a8c7c2115248e399", size = 127029 }, - { url = "https://files.pythonhosted.org/packages/47/ac/3efb7bfe2f3aefcf8d103e9a7162572f01936155ab2f7ebcc7c255a23212/multidict-6.1.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a7a9541cd308eed5e30318430a9c74d2132e9a8cb46b901326272d780bf2d423", size = 137594 }, - { url = "https://files.pythonhosted.org/packages/42/9b/6c6e9e8dc4f915fc90a9b7798c44a30773dea2995fdcb619870e705afe2b/multidict-6.1.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:da1758c76f50c39a2efd5e9859ce7d776317eb1dd34317c8152ac9251fc574a3", size = 134556 }, - { url = "https://files.pythonhosted.org/packages/1d/10/8e881743b26aaf718379a14ac58572a240e8293a1c9d68e1418fb11c0f90/multidict-6.1.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c943a53e9186688b45b323602298ab727d8865d8c9ee0b17f8d62d14b56f0753", size = 130993 }, - { url = "https://files.pythonhosted.org/packages/45/84/3eb91b4b557442802d058a7579e864b329968c8d0ea57d907e7023c677f2/multidict-6.1.0-cp311-cp311-win32.whl", hash = "sha256:90f8717cb649eea3504091e640a1b8568faad18bd4b9fcd692853a04475a4b80", size = 26405 }, - { url = "https://files.pythonhosted.org/packages/9f/0b/ad879847ecbf6d27e90a6eabb7eff6b62c129eefe617ea45eae7c1f0aead/multidict-6.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:82176036e65644a6cc5bd619f65f6f19781e8ec2e5330f51aa9ada7504cc1926", size = 28795 }, - { url = "https://files.pythonhosted.org/packages/fd/16/92057c74ba3b96d5e211b553895cd6dc7cc4d1e43d9ab8fafc727681ef71/multidict-6.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b04772ed465fa3cc947db808fa306d79b43e896beb677a56fb2347ca1a49c1fa", size = 48713 }, - { url = "https://files.pythonhosted.org/packages/94/3d/37d1b8893ae79716179540b89fc6a0ee56b4a65fcc0d63535c6f5d96f217/multidict-6.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6180c0ae073bddeb5a97a38c03f30c233e0a4d39cd86166251617d1bbd0af436", size = 29516 }, - { url = "https://files.pythonhosted.org/packages/a2/12/adb6b3200c363062f805275b4c1e656be2b3681aada66c80129932ff0bae/multidict-6.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:071120490b47aa997cca00666923a83f02c7fbb44f71cf7f136df753f7fa8761", size = 29557 }, - { url = "https://files.pythonhosted.org/packages/47/e9/604bb05e6e5bce1e6a5cf80a474e0f072e80d8ac105f1b994a53e0b28c42/multidict-6.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50b3a2710631848991d0bf7de077502e8994c804bb805aeb2925a981de58ec2e", size = 130170 }, - { url = "https://files.pythonhosted.org/packages/7e/13/9efa50801785eccbf7086b3c83b71a4fb501a4d43549c2f2f80b8787d69f/multidict-6.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b58c621844d55e71c1b7f7c498ce5aa6985d743a1a59034c57a905b3f153c1ef", size = 134836 }, - { url = "https://files.pythonhosted.org/packages/bf/0f/93808b765192780d117814a6dfcc2e75de6dcc610009ad408b8814dca3ba/multidict-6.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b6d90641869892caa9ca42ff913f7ff1c5ece06474fbd32fb2cf6834726c95", size = 133475 }, - { url = "https://files.pythonhosted.org/packages/d3/c8/529101d7176fe7dfe1d99604e48d69c5dfdcadb4f06561f465c8ef12b4df/multidict-6.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b820514bfc0b98a30e3d85462084779900347e4d49267f747ff54060cc33925", size = 131049 }, - { url = "https://files.pythonhosted.org/packages/ca/0c/fc85b439014d5a58063e19c3a158a889deec399d47b5269a0f3b6a2e28bc/multidict-6.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:10a9b09aba0c5b48c53761b7c720aaaf7cf236d5fe394cd399c7ba662d5f9966", size = 120370 }, - { url = "https://files.pythonhosted.org/packages/db/46/d4416eb20176492d2258fbd47b4abe729ff3b6e9c829ea4236f93c865089/multidict-6.1.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1e16bf3e5fc9f44632affb159d30a437bfe286ce9e02754759be5536b169b305", size = 125178 }, - { url = "https://files.pythonhosted.org/packages/5b/46/73697ad7ec521df7de5531a32780bbfd908ded0643cbe457f981a701457c/multidict-6.1.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76f364861c3bfc98cbbcbd402d83454ed9e01a5224bb3a28bf70002a230f73e2", size = 119567 }, - { url = "https://files.pythonhosted.org/packages/cd/ed/51f060e2cb0e7635329fa6ff930aa5cffa17f4c7f5c6c3ddc3500708e2f2/multidict-6.1.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:820c661588bd01a0aa62a1283f20d2be4281b086f80dad9e955e690c75fb54a2", size = 129822 }, - { url = "https://files.pythonhosted.org/packages/df/9e/ee7d1954b1331da3eddea0c4e08d9142da5f14b1321c7301f5014f49d492/multidict-6.1.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:0e5f362e895bc5b9e67fe6e4ded2492d8124bdf817827f33c5b46c2fe3ffaca6", size = 128656 }, - { url = "https://files.pythonhosted.org/packages/77/00/8538f11e3356b5d95fa4b024aa566cde7a38aa7a5f08f4912b32a037c5dc/multidict-6.1.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3ec660d19bbc671e3a6443325f07263be452c453ac9e512f5eb935e7d4ac28b3", size = 125360 }, - { url = "https://files.pythonhosted.org/packages/be/05/5d334c1f2462d43fec2363cd00b1c44c93a78c3925d952e9a71caf662e96/multidict-6.1.0-cp312-cp312-win32.whl", hash = "sha256:58130ecf8f7b8112cdb841486404f1282b9c86ccb30d3519faf301b2e5659133", size = 26382 }, - { url = "https://files.pythonhosted.org/packages/a3/bf/f332a13486b1ed0496d624bcc7e8357bb8053823e8cd4b9a18edc1d97e73/multidict-6.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:188215fc0aafb8e03341995e7c4797860181562380f81ed0a87ff455b70bf1f1", size = 28529 }, - { url = "https://files.pythonhosted.org/packages/22/67/1c7c0f39fe069aa4e5d794f323be24bf4d33d62d2a348acdb7991f8f30db/multidict-6.1.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:d569388c381b24671589335a3be6e1d45546c2988c2ebe30fdcada8457a31008", size = 48771 }, - { url = "https://files.pythonhosted.org/packages/3c/25/c186ee7b212bdf0df2519eacfb1981a017bda34392c67542c274651daf23/multidict-6.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:052e10d2d37810b99cc170b785945421141bf7bb7d2f8799d431e7db229c385f", size = 29533 }, - { url = "https://files.pythonhosted.org/packages/67/5e/04575fd837e0958e324ca035b339cea174554f6f641d3fb2b4f2e7ff44a2/multidict-6.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f90c822a402cb865e396a504f9fc8173ef34212a342d92e362ca498cad308e28", size = 29595 }, - { url = "https://files.pythonhosted.org/packages/d3/b2/e56388f86663810c07cfe4a3c3d87227f3811eeb2d08450b9e5d19d78876/multidict-6.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b225d95519a5bf73860323e633a664b0d85ad3d5bede6d30d95b35d4dfe8805b", size = 130094 }, - { url = "https://files.pythonhosted.org/packages/6c/ee/30ae9b4186a644d284543d55d491fbd4239b015d36b23fea43b4c94f7052/multidict-6.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:23bfd518810af7de1116313ebd9092cb9aa629beb12f6ed631ad53356ed6b86c", size = 134876 }, - { url = "https://files.pythonhosted.org/packages/84/c7/70461c13ba8ce3c779503c70ec9d0345ae84de04521c1f45a04d5f48943d/multidict-6.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c09fcfdccdd0b57867577b719c69e347a436b86cd83747f179dbf0cc0d4c1f3", size = 133500 }, - { url = "https://files.pythonhosted.org/packages/4a/9f/002af221253f10f99959561123fae676148dd730e2daa2cd053846a58507/multidict-6.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf6bea52ec97e95560af5ae576bdac3aa3aae0b6758c6efa115236d9e07dae44", size = 131099 }, - { url = "https://files.pythonhosted.org/packages/82/42/d1c7a7301d52af79d88548a97e297f9d99c961ad76bbe6f67442bb77f097/multidict-6.1.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57feec87371dbb3520da6192213c7d6fc892d5589a93db548331954de8248fd2", size = 120403 }, - { url = "https://files.pythonhosted.org/packages/68/f3/471985c2c7ac707547553e8f37cff5158030d36bdec4414cb825fbaa5327/multidict-6.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0c3f390dc53279cbc8ba976e5f8035eab997829066756d811616b652b00a23a3", size = 125348 }, - { url = "https://files.pythonhosted.org/packages/67/2c/e6df05c77e0e433c214ec1d21ddd203d9a4770a1f2866a8ca40a545869a0/multidict-6.1.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:59bfeae4b25ec05b34f1956eaa1cb38032282cd4dfabc5056d0a1ec4d696d3aa", size = 119673 }, - { url = "https://files.pythonhosted.org/packages/c5/cd/bc8608fff06239c9fb333f9db7743a1b2eafe98c2666c9a196e867a3a0a4/multidict-6.1.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b2f59caeaf7632cc633b5cf6fc449372b83bbdf0da4ae04d5be36118e46cc0aa", size = 129927 }, - { url = "https://files.pythonhosted.org/packages/44/8e/281b69b7bc84fc963a44dc6e0bbcc7150e517b91df368a27834299a526ac/multidict-6.1.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:37bb93b2178e02b7b618893990941900fd25b6b9ac0fa49931a40aecdf083fe4", size = 128711 }, - { url = "https://files.pythonhosted.org/packages/12/a4/63e7cd38ed29dd9f1881d5119f272c898ca92536cdb53ffe0843197f6c85/multidict-6.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4e9f48f58c2c523d5a06faea47866cd35b32655c46b443f163d08c6d0ddb17d6", size = 125519 }, - { url = "https://files.pythonhosted.org/packages/38/e0/4f5855037a72cd8a7a2f60a3952d9aa45feedb37ae7831642102604e8a37/multidict-6.1.0-cp313-cp313-win32.whl", hash = "sha256:3a37ffb35399029b45c6cc33640a92bef403c9fd388acce75cdc88f58bd19a81", size = 26426 }, - { url = "https://files.pythonhosted.org/packages/7e/a5/17ee3a4db1e310b7405f5d25834460073a8ccd86198ce044dfaf69eac073/multidict-6.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:e9aa71e15d9d9beaad2c6b9319edcdc0a49a43ef5c0a4c8265ca9ee7d6c67774", size = 28531 }, - { url = "https://files.pythonhosted.org/packages/99/b7/b9e70fde2c0f0c9af4cc5277782a89b66d35948ea3369ec9f598358c3ac5/multidict-6.1.0-py3-none-any.whl", hash = "sha256:48e171e52d1c4d33888e529b999e5900356b9ae588c2f09a52dcefb158b27506", size = 10051 }, -] - -[[package]] -name = "openai" -version = "1.54.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "distro" }, - { name = "httpx" }, - { name = "jiter" }, - { name = "pydantic" }, - { name = "sniffio" }, - { name = "tqdm" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/da/26/f1a79d8332ac5ed38fdc347701aa4a7ad8f8f66ec3f9880122c455d7ffb1/openai-1.54.2.tar.gz", hash = "sha256:0dbb8f2bb36f7ff1d200d103b9f95c35773ed3248e3a697b02f5a39015627e5e", size = 312551 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/0f/ea8717dedbef16fa61a0bdeb0b7ae96ff574933ed5932102d3f5a4ce01a1/openai-1.54.2-py3-none-any.whl", hash = "sha256:77010b439e69d37f67cc2f44eaa62b2b6d5a60add2d8636e4603c0e762982708", size = 389315 }, -] - -[[package]] -name = "openai-client" -version = "0.1.0" -source = { editable = "../openai-client" } -dependencies = [ - { name = "azure-ai-contentsafety" }, - { name = "azure-core", extra = ["aio"] }, - { name = "azure-identity" }, - { name = "openai" }, - { name = "pillow" }, - { name = "python-liquid" }, - { name = "semantic-workbench-assistant" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, - { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "openai", specifier = ">=1.3.9" }, - { name = "pillow", specifier = ">=11.0.0" }, - { name = "python-liquid", specifier = ">=1.12.1" }, - { name = "semantic-workbench-assistant", editable = "../semantic-workbench-assistant" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[package.metadata.requires-dev] -dev = [{ name = "pytest", specifier = ">=8.3.3" }] - -[[package]] -name = "packaging" -version = "24.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/51/65/50db4dda066951078f0a96cf12f4b9ada6e4b811516bf0262c0f4f7064d4/packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", size = 148788 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124", size = 53985 }, -] - -[[package]] -name = "pillow" -version = "11.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/26/0d95c04c868f6bdb0c447e3ee2de5564411845e36a858cfd63766bc7b563/pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739", size = 46737780 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f0/eb/f7e21b113dd48a9c97d364e0915b3988c6a0b6207652f5a92372871b7aa4/pillow-11.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1c1d72714f429a521d8d2d018badc42414c3077eb187a59579f28e4270b4b0fc", size = 3154705 }, - { url = "https://files.pythonhosted.org/packages/25/b3/2b54a1d541accebe6bd8b1358b34ceb2c509f51cb7dcda8687362490da5b/pillow-11.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:499c3a1b0d6fc8213519e193796eb1a86a1be4b1877d678b30f83fd979811d1a", size = 2979222 }, - { url = "https://files.pythonhosted.org/packages/20/12/1a41eddad8265c5c19dda8fb6c269ce15ee25e0b9f8f26286e6202df6693/pillow-11.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8b2351c85d855293a299038e1f89db92a2f35e8d2f783489c6f0b2b5f3fe8a3", size = 4190220 }, - { url = "https://files.pythonhosted.org/packages/a9/9b/8a8c4d07d77447b7457164b861d18f5a31ae6418ef5c07f6f878fa09039a/pillow-11.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f4dba50cfa56f910241eb7f883c20f1e7b1d8f7d91c750cd0b318bad443f4d5", size = 4291399 }, - { url = "https://files.pythonhosted.org/packages/fc/e4/130c5fab4a54d3991129800dd2801feeb4b118d7630148cd67f0e6269d4c/pillow-11.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:5ddbfd761ee00c12ee1be86c9c0683ecf5bb14c9772ddbd782085779a63dd55b", size = 4202709 }, - { url = "https://files.pythonhosted.org/packages/39/63/b3fc299528d7df1f678b0666002b37affe6b8751225c3d9c12cf530e73ed/pillow-11.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:45c566eb10b8967d71bf1ab8e4a525e5a93519e29ea071459ce517f6b903d7fa", size = 4372556 }, - { url = "https://files.pythonhosted.org/packages/c6/a6/694122c55b855b586c26c694937d36bb8d3b09c735ff41b2f315c6e66a10/pillow-11.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b4fd7bd29610a83a8c9b564d457cf5bd92b4e11e79a4ee4716a63c959699b306", size = 4287187 }, - { url = "https://files.pythonhosted.org/packages/ba/a9/f9d763e2671a8acd53d29b1e284ca298bc10a595527f6be30233cdb9659d/pillow-11.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:cb929ca942d0ec4fac404cbf520ee6cac37bf35be479b970c4ffadf2b6a1cad9", size = 4418468 }, - { url = "https://files.pythonhosted.org/packages/6e/0e/b5cbad2621377f11313a94aeb44ca55a9639adabcaaa073597a1925f8c26/pillow-11.0.0-cp311-cp311-win32.whl", hash = "sha256:006bcdd307cc47ba43e924099a038cbf9591062e6c50e570819743f5607404f5", size = 2249249 }, - { url = "https://files.pythonhosted.org/packages/dc/83/1470c220a4ff06cd75fc609068f6605e567ea51df70557555c2ab6516b2c/pillow-11.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:52a2d8323a465f84faaba5236567d212c3668f2ab53e1c74c15583cf507a0291", size = 2566769 }, - { url = "https://files.pythonhosted.org/packages/52/98/def78c3a23acee2bcdb2e52005fb2810ed54305602ec1bfcfab2bda6f49f/pillow-11.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:16095692a253047fe3ec028e951fa4221a1f3ed3d80c397e83541a3037ff67c9", size = 2254611 }, - { url = "https://files.pythonhosted.org/packages/1c/a3/26e606ff0b2daaf120543e537311fa3ae2eb6bf061490e4fea51771540be/pillow-11.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d2c0a187a92a1cb5ef2c8ed5412dd8d4334272617f532d4ad4de31e0495bd923", size = 3147642 }, - { url = "https://files.pythonhosted.org/packages/4f/d5/1caabedd8863526a6cfa44ee7a833bd97f945dc1d56824d6d76e11731939/pillow-11.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:084a07ef0821cfe4858fe86652fffac8e187b6ae677e9906e192aafcc1b69903", size = 2978999 }, - { url = "https://files.pythonhosted.org/packages/d9/ff/5a45000826a1aa1ac6874b3ec5a856474821a1b59d838c4f6ce2ee518fe9/pillow-11.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8069c5179902dcdce0be9bfc8235347fdbac249d23bd90514b7a47a72d9fecf4", size = 4196794 }, - { url = "https://files.pythonhosted.org/packages/9d/21/84c9f287d17180f26263b5f5c8fb201de0f88b1afddf8a2597a5c9fe787f/pillow-11.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f02541ef64077f22bf4924f225c0fd1248c168f86e4b7abdedd87d6ebaceab0f", size = 4300762 }, - { url = "https://files.pythonhosted.org/packages/84/39/63fb87cd07cc541438b448b1fed467c4d687ad18aa786a7f8e67b255d1aa/pillow-11.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:fcb4621042ac4b7865c179bb972ed0da0218a076dc1820ffc48b1d74c1e37fe9", size = 4210468 }, - { url = "https://files.pythonhosted.org/packages/7f/42/6e0f2c2d5c60f499aa29be14f860dd4539de322cd8fb84ee01553493fb4d/pillow-11.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:00177a63030d612148e659b55ba99527803288cea7c75fb05766ab7981a8c1b7", size = 4381824 }, - { url = "https://files.pythonhosted.org/packages/31/69/1ef0fb9d2f8d2d114db982b78ca4eeb9db9a29f7477821e160b8c1253f67/pillow-11.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8853a3bf12afddfdf15f57c4b02d7ded92c7a75a5d7331d19f4f9572a89c17e6", size = 4296436 }, - { url = "https://files.pythonhosted.org/packages/44/ea/dad2818c675c44f6012289a7c4f46068c548768bc6c7f4e8c4ae5bbbc811/pillow-11.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3107c66e43bda25359d5ef446f59c497de2b5ed4c7fdba0894f8d6cf3822dafc", size = 4429714 }, - { url = "https://files.pythonhosted.org/packages/af/3a/da80224a6eb15bba7a0dcb2346e2b686bb9bf98378c0b4353cd88e62b171/pillow-11.0.0-cp312-cp312-win32.whl", hash = "sha256:86510e3f5eca0ab87429dd77fafc04693195eec7fd6a137c389c3eeb4cfb77c6", size = 2249631 }, - { url = "https://files.pythonhosted.org/packages/57/97/73f756c338c1d86bb802ee88c3cab015ad7ce4b838f8a24f16b676b1ac7c/pillow-11.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:8ec4a89295cd6cd4d1058a5e6aec6bf51e0eaaf9714774e1bfac7cfc9051db47", size = 2567533 }, - { url = "https://files.pythonhosted.org/packages/0b/30/2b61876e2722374558b871dfbfcbe4e406626d63f4f6ed92e9c8e24cac37/pillow-11.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:27a7860107500d813fcd203b4ea19b04babe79448268403172782754870dac25", size = 2254890 }, - { url = "https://files.pythonhosted.org/packages/63/24/e2e15e392d00fcf4215907465d8ec2a2f23bcec1481a8ebe4ae760459995/pillow-11.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:bcd1fb5bb7b07f64c15618c89efcc2cfa3e95f0e3bcdbaf4642509de1942a699", size = 3147300 }, - { url = "https://files.pythonhosted.org/packages/43/72/92ad4afaa2afc233dc44184adff289c2e77e8cd916b3ddb72ac69495bda3/pillow-11.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e038b0745997c7dcaae350d35859c9715c71e92ffb7e0f4a8e8a16732150f38", size = 2978742 }, - { url = "https://files.pythonhosted.org/packages/9e/da/c8d69c5bc85d72a8523fe862f05ababdc52c0a755cfe3d362656bb86552b/pillow-11.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ae08bd8ffc41aebf578c2af2f9d8749d91f448b3bfd41d7d9ff573d74f2a6b2", size = 4194349 }, - { url = "https://files.pythonhosted.org/packages/cd/e8/686d0caeed6b998351d57796496a70185376ed9c8ec7d99e1d19ad591fc6/pillow-11.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d69bfd8ec3219ae71bcde1f942b728903cad25fafe3100ba2258b973bd2bc1b2", size = 4298714 }, - { url = "https://files.pythonhosted.org/packages/ec/da/430015cec620d622f06854be67fd2f6721f52fc17fca8ac34b32e2d60739/pillow-11.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:61b887f9ddba63ddf62fd02a3ba7add935d053b6dd7d58998c630e6dbade8527", size = 4208514 }, - { url = "https://files.pythonhosted.org/packages/44/ae/7e4f6662a9b1cb5f92b9cc9cab8321c381ffbee309210940e57432a4063a/pillow-11.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:c6a660307ca9d4867caa8d9ca2c2658ab685de83792d1876274991adec7b93fa", size = 4380055 }, - { url = "https://files.pythonhosted.org/packages/74/d5/1a807779ac8a0eeed57f2b92a3c32ea1b696e6140c15bd42eaf908a261cd/pillow-11.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:73e3a0200cdda995c7e43dd47436c1548f87a30bb27fb871f352a22ab8dcf45f", size = 4296751 }, - { url = "https://files.pythonhosted.org/packages/38/8c/5fa3385163ee7080bc13026d59656267daaaaf3c728c233d530e2c2757c8/pillow-11.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fba162b8872d30fea8c52b258a542c5dfd7b235fb5cb352240c8d63b414013eb", size = 4430378 }, - { url = "https://files.pythonhosted.org/packages/ca/1d/ad9c14811133977ff87035bf426875b93097fb50af747793f013979facdb/pillow-11.0.0-cp313-cp313-win32.whl", hash = "sha256:f1b82c27e89fffc6da125d5eb0ca6e68017faf5efc078128cfaa42cf5cb38798", size = 2249588 }, - { url = "https://files.pythonhosted.org/packages/fb/01/3755ba287dac715e6afdb333cb1f6d69740a7475220b4637b5ce3d78cec2/pillow-11.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ba470552b48e5835f1d23ecb936bb7f71d206f9dfeee64245f30c3270b994de", size = 2567509 }, - { url = "https://files.pythonhosted.org/packages/c0/98/2c7d727079b6be1aba82d195767d35fcc2d32204c7a5820f822df5330152/pillow-11.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:846e193e103b41e984ac921b335df59195356ce3f71dcfd155aa79c603873b84", size = 2254791 }, - { url = "https://files.pythonhosted.org/packages/eb/38/998b04cc6f474e78b563716b20eecf42a2fa16a84589d23c8898e64b0ffd/pillow-11.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4ad70c4214f67d7466bea6a08061eba35c01b1b89eaa098040a35272a8efb22b", size = 3150854 }, - { url = "https://files.pythonhosted.org/packages/13/8e/be23a96292113c6cb26b2aa3c8b3681ec62b44ed5c2bd0b258bd59503d3c/pillow-11.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:6ec0d5af64f2e3d64a165f490d96368bb5dea8b8f9ad04487f9ab60dc4bb6003", size = 2982369 }, - { url = "https://files.pythonhosted.org/packages/97/8a/3db4eaabb7a2ae8203cd3a332a005e4aba00067fc514aaaf3e9721be31f1/pillow-11.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c809a70e43c7977c4a42aefd62f0131823ebf7dd73556fa5d5950f5b354087e2", size = 4333703 }, - { url = "https://files.pythonhosted.org/packages/28/ac/629ffc84ff67b9228fe87a97272ab125bbd4dc462745f35f192d37b822f1/pillow-11.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:4b60c9520f7207aaf2e1d94de026682fc227806c6e1f55bba7606d1c94dd623a", size = 4412550 }, - { url = "https://files.pythonhosted.org/packages/d6/07/a505921d36bb2df6868806eaf56ef58699c16c388e378b0dcdb6e5b2fb36/pillow-11.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1e2688958a840c822279fda0086fec1fdab2f95bf2b717b66871c4ad9859d7e8", size = 4461038 }, - { url = "https://files.pythonhosted.org/packages/d6/b9/fb620dd47fc7cc9678af8f8bd8c772034ca4977237049287e99dda360b66/pillow-11.0.0-cp313-cp313t-win32.whl", hash = "sha256:607bbe123c74e272e381a8d1957083a9463401f7bd01287f50521ecb05a313f8", size = 2253197 }, - { url = "https://files.pythonhosted.org/packages/df/86/25dde85c06c89d7fc5db17940f07aae0a56ac69aa9ccb5eb0f09798862a8/pillow-11.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5c39ed17edea3bc69c743a8dd3e9853b7509625c2462532e62baa0732163a904", size = 2572169 }, - { url = "https://files.pythonhosted.org/packages/51/85/9c33f2517add612e17f3381aee7c4072779130c634921a756c97bc29fb49/pillow-11.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:75acbbeb05b86bc53cbe7b7e6fe00fbcf82ad7c684b3ad82e3d711da9ba287d3", size = 2256828 }, -] - -[[package]] -name = "portalocker" -version = "2.10.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pywin32", marker = "platform_system == 'Windows'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ed/d3/c6c64067759e87af98cc668c1cc75171347d0f1577fab7ca3749134e3cd4/portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f", size = 40891 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/fb/a70a4214956182e0d7a9099ab17d50bfcba1056188e9b14f35b9e2b62a0d/portalocker-2.10.1-py3-none-any.whl", hash = "sha256:53a5984ebc86a025552264b459b46a2086e269b21823cb572f8f28ee759e45bf", size = 18423 }, -] - -[[package]] -name = "propcache" -version = "0.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a9/4d/5e5a60b78dbc1d464f8a7bbaeb30957257afdc8512cbb9dfd5659304f5cd/propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70", size = 40951 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/1c/71eec730e12aec6511e702ad0cd73c2872eccb7cad39de8ba3ba9de693ef/propcache-0.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:63f13bf09cc3336eb04a837490b8f332e0db41da66995c9fd1ba04552e516354", size = 80811 }, - { url = "https://files.pythonhosted.org/packages/89/c3/7e94009f9a4934c48a371632197406a8860b9f08e3f7f7d922ab69e57a41/propcache-0.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608cce1da6f2672a56b24a015b42db4ac612ee709f3d29f27a00c943d9e851de", size = 46365 }, - { url = "https://files.pythonhosted.org/packages/c0/1d/c700d16d1d6903aeab28372fe9999762f074b80b96a0ccc953175b858743/propcache-0.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:466c219deee4536fbc83c08d09115249db301550625c7fef1c5563a584c9bc87", size = 45602 }, - { url = "https://files.pythonhosted.org/packages/2e/5e/4a3e96380805bf742712e39a4534689f4cddf5fa2d3a93f22e9fd8001b23/propcache-0.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc2db02409338bf36590aa985a461b2c96fce91f8e7e0f14c50c5fcc4f229016", size = 236161 }, - { url = "https://files.pythonhosted.org/packages/a5/85/90132481183d1436dff6e29f4fa81b891afb6cb89a7306f32ac500a25932/propcache-0.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a6ed8db0a556343d566a5c124ee483ae113acc9a557a807d439bcecc44e7dfbb", size = 244938 }, - { url = "https://files.pythonhosted.org/packages/4a/89/c893533cb45c79c970834274e2d0f6d64383ec740be631b6a0a1d2b4ddc0/propcache-0.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:91997d9cb4a325b60d4e3f20967f8eb08dfcb32b22554d5ef78e6fd1dda743a2", size = 243576 }, - { url = "https://files.pythonhosted.org/packages/8c/56/98c2054c8526331a05f205bf45cbb2cda4e58e56df70e76d6a509e5d6ec6/propcache-0.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c7dde9e533c0a49d802b4f3f218fa9ad0a1ce21f2c2eb80d5216565202acab4", size = 236011 }, - { url = "https://files.pythonhosted.org/packages/2d/0c/8b8b9f8a6e1abd869c0fa79b907228e7abb966919047d294ef5df0d136cf/propcache-0.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffcad6c564fe6b9b8916c1aefbb37a362deebf9394bd2974e9d84232e3e08504", size = 224834 }, - { url = "https://files.pythonhosted.org/packages/18/bb/397d05a7298b7711b90e13108db697732325cafdcd8484c894885c1bf109/propcache-0.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:97a58a28bcf63284e8b4d7b460cbee1edaab24634e82059c7b8c09e65284f178", size = 224946 }, - { url = "https://files.pythonhosted.org/packages/25/19/4fc08dac19297ac58135c03770b42377be211622fd0147f015f78d47cd31/propcache-0.2.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:945db8ee295d3af9dbdbb698cce9bbc5c59b5c3fe328bbc4387f59a8a35f998d", size = 217280 }, - { url = "https://files.pythonhosted.org/packages/7e/76/c79276a43df2096ce2aba07ce47576832b1174c0c480fe6b04bd70120e59/propcache-0.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:39e104da444a34830751715f45ef9fc537475ba21b7f1f5b0f4d71a3b60d7fe2", size = 220088 }, - { url = "https://files.pythonhosted.org/packages/c3/9a/8a8cf428a91b1336b883f09c8b884e1734c87f724d74b917129a24fe2093/propcache-0.2.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c5ecca8f9bab618340c8e848d340baf68bcd8ad90a8ecd7a4524a81c1764b3db", size = 233008 }, - { url = "https://files.pythonhosted.org/packages/25/7b/768a8969abd447d5f0f3333df85c6a5d94982a1bc9a89c53c154bf7a8b11/propcache-0.2.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c436130cc779806bdf5d5fae0d848713105472b8566b75ff70048c47d3961c5b", size = 237719 }, - { url = "https://files.pythonhosted.org/packages/ed/0d/e5d68ccc7976ef8b57d80613ac07bbaf0614d43f4750cf953f0168ef114f/propcache-0.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:191db28dc6dcd29d1a3e063c3be0b40688ed76434622c53a284e5427565bbd9b", size = 227729 }, - { url = "https://files.pythonhosted.org/packages/05/64/17eb2796e2d1c3d0c431dc5f40078d7282f4645af0bb4da9097fbb628c6c/propcache-0.2.0-cp311-cp311-win32.whl", hash = "sha256:5f2564ec89058ee7c7989a7b719115bdfe2a2fb8e7a4543b8d1c0cc4cf6478c1", size = 40473 }, - { url = "https://files.pythonhosted.org/packages/83/c5/e89fc428ccdc897ade08cd7605f174c69390147526627a7650fb883e0cd0/propcache-0.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:6e2e54267980349b723cff366d1e29b138b9a60fa376664a157a342689553f71", size = 44921 }, - { url = "https://files.pythonhosted.org/packages/7c/46/a41ca1097769fc548fc9216ec4c1471b772cc39720eb47ed7e38ef0006a9/propcache-0.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2ee7606193fb267be4b2e3b32714f2d58cad27217638db98a60f9efb5efeccc2", size = 80800 }, - { url = "https://files.pythonhosted.org/packages/75/4f/93df46aab9cc473498ff56be39b5f6ee1e33529223d7a4d8c0a6101a9ba2/propcache-0.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:91ee8fc02ca52e24bcb77b234f22afc03288e1dafbb1f88fe24db308910c4ac7", size = 46443 }, - { url = "https://files.pythonhosted.org/packages/0b/17/308acc6aee65d0f9a8375e36c4807ac6605d1f38074b1581bd4042b9fb37/propcache-0.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2e900bad2a8456d00a113cad8c13343f3b1f327534e3589acc2219729237a2e8", size = 45676 }, - { url = "https://files.pythonhosted.org/packages/65/44/626599d2854d6c1d4530b9a05e7ff2ee22b790358334b475ed7c89f7d625/propcache-0.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f52a68c21363c45297aca15561812d542f8fc683c85201df0bebe209e349f793", size = 246191 }, - { url = "https://files.pythonhosted.org/packages/f2/df/5d996d7cb18df076debae7d76ac3da085c0575a9f2be6b1f707fe227b54c/propcache-0.2.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1e41d67757ff4fbc8ef2af99b338bfb955010444b92929e9e55a6d4dcc3c4f09", size = 251791 }, - { url = "https://files.pythonhosted.org/packages/2e/6d/9f91e5dde8b1f662f6dd4dff36098ed22a1ef4e08e1316f05f4758f1576c/propcache-0.2.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a64e32f8bd94c105cc27f42d3b658902b5bcc947ece3c8fe7bc1b05982f60e89", size = 253434 }, - { url = "https://files.pythonhosted.org/packages/3c/e9/1b54b7e26f50b3e0497cd13d3483d781d284452c2c50dd2a615a92a087a3/propcache-0.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:55346705687dbd7ef0d77883ab4f6fabc48232f587925bdaf95219bae072491e", size = 248150 }, - { url = "https://files.pythonhosted.org/packages/a7/ef/a35bf191c8038fe3ce9a414b907371c81d102384eda5dbafe6f4dce0cf9b/propcache-0.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00181262b17e517df2cd85656fcd6b4e70946fe62cd625b9d74ac9977b64d8d9", size = 233568 }, - { url = "https://files.pythonhosted.org/packages/97/d9/d00bb9277a9165a5e6d60f2142cd1a38a750045c9c12e47ae087f686d781/propcache-0.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6994984550eaf25dd7fc7bd1b700ff45c894149341725bb4edc67f0ffa94efa4", size = 229874 }, - { url = "https://files.pythonhosted.org/packages/8e/78/c123cf22469bdc4b18efb78893e69c70a8b16de88e6160b69ca6bdd88b5d/propcache-0.2.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:56295eb1e5f3aecd516d91b00cfd8bf3a13991de5a479df9e27dd569ea23959c", size = 225857 }, - { url = "https://files.pythonhosted.org/packages/31/1b/fd6b2f1f36d028820d35475be78859d8c89c8f091ad30e377ac49fd66359/propcache-0.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:439e76255daa0f8151d3cb325f6dd4a3e93043e6403e6491813bcaaaa8733887", size = 227604 }, - { url = "https://files.pythonhosted.org/packages/99/36/b07be976edf77a07233ba712e53262937625af02154353171716894a86a6/propcache-0.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f6475a1b2ecb310c98c28d271a30df74f9dd436ee46d09236a6b750a7599ce57", size = 238430 }, - { url = "https://files.pythonhosted.org/packages/0d/64/5822f496c9010e3966e934a011ac08cac8734561842bc7c1f65586e0683c/propcache-0.2.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3444cdba6628accf384e349014084b1cacd866fbb88433cd9d279d90a54e0b23", size = 244814 }, - { url = "https://files.pythonhosted.org/packages/fd/bd/8657918a35d50b18a9e4d78a5df7b6c82a637a311ab20851eef4326305c1/propcache-0.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:4a9d9b4d0a9b38d1c391bb4ad24aa65f306c6f01b512e10a8a34a2dc5675d348", size = 235922 }, - { url = "https://files.pythonhosted.org/packages/a8/6f/ec0095e1647b4727db945213a9f395b1103c442ef65e54c62e92a72a3f75/propcache-0.2.0-cp312-cp312-win32.whl", hash = "sha256:69d3a98eebae99a420d4b28756c8ce6ea5a29291baf2dc9ff9414b42676f61d5", size = 40177 }, - { url = "https://files.pythonhosted.org/packages/20/a2/bd0896fdc4f4c1db46d9bc361c8c79a9bf08ccc08ba054a98e38e7ba1557/propcache-0.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:ad9c9b99b05f163109466638bd30ada1722abb01bbb85c739c50b6dc11f92dc3", size = 44446 }, - { url = "https://files.pythonhosted.org/packages/a8/a7/5f37b69197d4f558bfef5b4bceaff7c43cc9b51adf5bd75e9081d7ea80e4/propcache-0.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ecddc221a077a8132cf7c747d5352a15ed763b674c0448d811f408bf803d9ad7", size = 78120 }, - { url = "https://files.pythonhosted.org/packages/c8/cd/48ab2b30a6b353ecb95a244915f85756d74f815862eb2ecc7a518d565b48/propcache-0.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0e53cb83fdd61cbd67202735e6a6687a7b491c8742dfc39c9e01e80354956763", size = 45127 }, - { url = "https://files.pythonhosted.org/packages/a5/ba/0a1ef94a3412aab057bd996ed5f0ac7458be5bf469e85c70fa9ceb43290b/propcache-0.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92fe151145a990c22cbccf9ae15cae8ae9eddabfc949a219c9f667877e40853d", size = 44419 }, - { url = "https://files.pythonhosted.org/packages/b4/6c/ca70bee4f22fa99eacd04f4d2f1699be9d13538ccf22b3169a61c60a27fa/propcache-0.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d6a21ef516d36909931a2967621eecb256018aeb11fc48656e3257e73e2e247a", size = 229611 }, - { url = "https://files.pythonhosted.org/packages/19/70/47b872a263e8511ca33718d96a10c17d3c853aefadeb86dc26e8421184b9/propcache-0.2.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f88a4095e913f98988f5b338c1d4d5d07dbb0b6bad19892fd447484e483ba6b", size = 234005 }, - { url = "https://files.pythonhosted.org/packages/4f/be/3b0ab8c84a22e4a3224719099c1229ddfdd8a6a1558cf75cb55ee1e35c25/propcache-0.2.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a5b3bb545ead161be780ee85a2b54fdf7092815995661947812dde94a40f6fb", size = 237270 }, - { url = "https://files.pythonhosted.org/packages/04/d8/f071bb000d4b8f851d312c3c75701e586b3f643fe14a2e3409b1b9ab3936/propcache-0.2.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67aeb72e0f482709991aa91345a831d0b707d16b0257e8ef88a2ad246a7280bf", size = 231877 }, - { url = "https://files.pythonhosted.org/packages/93/e7/57a035a1359e542bbb0a7df95aad6b9871ebee6dce2840cb157a415bd1f3/propcache-0.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c997f8c44ec9b9b0bcbf2d422cc00a1d9b9c681f56efa6ca149a941e5560da2", size = 217848 }, - { url = "https://files.pythonhosted.org/packages/f0/93/d1dea40f112ec183398fb6c42fde340edd7bab202411c4aa1a8289f461b6/propcache-0.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2a66df3d4992bc1d725b9aa803e8c5a66c010c65c741ad901e260ece77f58d2f", size = 216987 }, - { url = "https://files.pythonhosted.org/packages/62/4c/877340871251145d3522c2b5d25c16a1690ad655fbab7bb9ece6b117e39f/propcache-0.2.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3ebbcf2a07621f29638799828b8d8668c421bfb94c6cb04269130d8de4fb7136", size = 212451 }, - { url = "https://files.pythonhosted.org/packages/7c/bb/a91b72efeeb42906ef58ccf0cdb87947b54d7475fee3c93425d732f16a61/propcache-0.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1235c01ddaa80da8235741e80815ce381c5267f96cc49b1477fdcf8c047ef325", size = 212879 }, - { url = "https://files.pythonhosted.org/packages/9b/7f/ee7fea8faac57b3ec5d91ff47470c6c5d40d7f15d0b1fccac806348fa59e/propcache-0.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3947483a381259c06921612550867b37d22e1df6d6d7e8361264b6d037595f44", size = 222288 }, - { url = "https://files.pythonhosted.org/packages/ff/d7/acd67901c43d2e6b20a7a973d9d5fd543c6e277af29b1eb0e1f7bd7ca7d2/propcache-0.2.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d5bed7f9805cc29c780f3aee05de3262ee7ce1f47083cfe9f77471e9d6777e83", size = 228257 }, - { url = "https://files.pythonhosted.org/packages/8d/6f/6272ecc7a8daad1d0754cfc6c8846076a8cb13f810005c79b15ce0ef0cf2/propcache-0.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e4a91d44379f45f5e540971d41e4626dacd7f01004826a18cb048e7da7e96544", size = 221075 }, - { url = "https://files.pythonhosted.org/packages/7c/bd/c7a6a719a6b3dd8b3aeadb3675b5783983529e4a3185946aa444d3e078f6/propcache-0.2.0-cp313-cp313-win32.whl", hash = "sha256:f902804113e032e2cdf8c71015651c97af6418363bea8d78dc0911d56c335032", size = 39654 }, - { url = "https://files.pythonhosted.org/packages/88/e7/0eef39eff84fa3e001b44de0bd41c7c0e3432e7648ffd3d64955910f002d/propcache-0.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:8f188cfcc64fb1266f4684206c9de0e80f54622c3f22a910cbd200478aeae61e", size = 43705 }, - { url = "https://files.pythonhosted.org/packages/3d/b6/e6d98278f2d49b22b4d033c9f792eda783b9ab2094b041f013fc69bcde87/propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036", size = 11603 }, -] - -[[package]] -name = "pycparser" -version = "2.22" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, -] - -[[package]] -name = "pydantic" -version = "2.9.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a9/b7/d9e3f12af310e1120c21603644a1cd86f59060e040ec5c3a80b8f05fae30/pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f", size = 769917 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/df/e4/ba44652d562cbf0bf320e0f3810206149c8a4e99cdbf66da82e97ab53a15/pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12", size = 434928 }, -] - -[[package]] -name = "pydantic-core" -version = "2.23.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e2/aa/6b6a9b9f8537b872f552ddd46dd3da230367754b6f707b8e1e963f515ea3/pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863", size = 402156 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/30/890a583cd3f2be27ecf32b479d5d615710bb926d92da03e3f7838ff3e58b/pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8", size = 1865160 }, - { url = "https://files.pythonhosted.org/packages/1d/9a/b634442e1253bc6889c87afe8bb59447f106ee042140bd57680b3b113ec7/pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d", size = 1776777 }, - { url = "https://files.pythonhosted.org/packages/75/9a/7816295124a6b08c24c96f9ce73085032d8bcbaf7e5a781cd41aa910c891/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e", size = 1799244 }, - { url = "https://files.pythonhosted.org/packages/a9/8f/89c1405176903e567c5f99ec53387449e62f1121894aa9fc2c4fdc51a59b/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607", size = 1805307 }, - { url = "https://files.pythonhosted.org/packages/d5/a5/1a194447d0da1ef492e3470680c66048fef56fc1f1a25cafbea4bc1d1c48/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd", size = 2000663 }, - { url = "https://files.pythonhosted.org/packages/13/a5/1df8541651de4455e7d587cf556201b4f7997191e110bca3b589218745a5/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea", size = 2655941 }, - { url = "https://files.pythonhosted.org/packages/44/31/a3899b5ce02c4316865e390107f145089876dff7e1dfc770a231d836aed8/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e", size = 2052105 }, - { url = "https://files.pythonhosted.org/packages/1b/aa/98e190f8745d5ec831f6d5449344c48c0627ac5fed4e5340a44b74878f8e/pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b", size = 1919967 }, - { url = "https://files.pythonhosted.org/packages/ae/35/b6e00b6abb2acfee3e8f85558c02a0822e9a8b2f2d812ea8b9079b118ba0/pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0", size = 1964291 }, - { url = "https://files.pythonhosted.org/packages/13/46/7bee6d32b69191cd649bbbd2361af79c472d72cb29bb2024f0b6e350ba06/pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64", size = 2109666 }, - { url = "https://files.pythonhosted.org/packages/39/ef/7b34f1b122a81b68ed0a7d0e564da9ccdc9a2924c8d6c6b5b11fa3a56970/pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f", size = 1732940 }, - { url = "https://files.pythonhosted.org/packages/2f/76/37b7e76c645843ff46c1d73e046207311ef298d3f7b2f7d8f6ac60113071/pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3", size = 1916804 }, - { url = "https://files.pythonhosted.org/packages/74/7b/8e315f80666194b354966ec84b7d567da77ad927ed6323db4006cf915f3f/pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231", size = 1856459 }, - { url = "https://files.pythonhosted.org/packages/14/de/866bdce10ed808323d437612aca1ec9971b981e1c52e5e42ad9b8e17a6f6/pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee", size = 1770007 }, - { url = "https://files.pythonhosted.org/packages/dc/69/8edd5c3cd48bb833a3f7ef9b81d7666ccddd3c9a635225214e044b6e8281/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87", size = 1790245 }, - { url = "https://files.pythonhosted.org/packages/80/33/9c24334e3af796ce80d2274940aae38dd4e5676298b4398eff103a79e02d/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8", size = 1801260 }, - { url = "https://files.pythonhosted.org/packages/a5/6f/e9567fd90104b79b101ca9d120219644d3314962caa7948dd8b965e9f83e/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327", size = 1996872 }, - { url = "https://files.pythonhosted.org/packages/2d/ad/b5f0fe9e6cfee915dd144edbd10b6e9c9c9c9d7a56b69256d124b8ac682e/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2", size = 2661617 }, - { url = "https://files.pythonhosted.org/packages/06/c8/7d4b708f8d05a5cbfda3243aad468052c6e99de7d0937c9146c24d9f12e9/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36", size = 2071831 }, - { url = "https://files.pythonhosted.org/packages/89/4d/3079d00c47f22c9a9a8220db088b309ad6e600a73d7a69473e3a8e5e3ea3/pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126", size = 1917453 }, - { url = "https://files.pythonhosted.org/packages/e9/88/9df5b7ce880a4703fcc2d76c8c2d8eb9f861f79d0c56f4b8f5f2607ccec8/pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e", size = 1968793 }, - { url = "https://files.pythonhosted.org/packages/e3/b9/41f7efe80f6ce2ed3ee3c2dcfe10ab7adc1172f778cc9659509a79518c43/pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24", size = 2116872 }, - { url = "https://files.pythonhosted.org/packages/63/08/b59b7a92e03dd25554b0436554bf23e7c29abae7cce4b1c459cd92746811/pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84", size = 1738535 }, - { url = "https://files.pythonhosted.org/packages/88/8d/479293e4d39ab409747926eec4329de5b7129beaedc3786eca070605d07f/pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9", size = 1917992 }, - { url = "https://files.pythonhosted.org/packages/ad/ef/16ee2df472bf0e419b6bc68c05bf0145c49247a1095e85cee1463c6a44a1/pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc", size = 1856143 }, - { url = "https://files.pythonhosted.org/packages/da/fa/bc3dbb83605669a34a93308e297ab22be82dfb9dcf88c6cf4b4f264e0a42/pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd", size = 1770063 }, - { url = "https://files.pythonhosted.org/packages/4e/48/e813f3bbd257a712303ebdf55c8dc46f9589ec74b384c9f652597df3288d/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05", size = 1790013 }, - { url = "https://files.pythonhosted.org/packages/b4/e0/56eda3a37929a1d297fcab1966db8c339023bcca0b64c5a84896db3fcc5c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d", size = 1801077 }, - { url = "https://files.pythonhosted.org/packages/04/be/5e49376769bfbf82486da6c5c1683b891809365c20d7c7e52792ce4c71f3/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510", size = 1996782 }, - { url = "https://files.pythonhosted.org/packages/bc/24/e3ee6c04f1d58cc15f37bcc62f32c7478ff55142b7b3e6d42ea374ea427c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6", size = 2661375 }, - { url = "https://files.pythonhosted.org/packages/c1/f8/11a9006de4e89d016b8de74ebb1db727dc100608bb1e6bbe9d56a3cbbcce/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b", size = 2071635 }, - { url = "https://files.pythonhosted.org/packages/7c/45/bdce5779b59f468bdf262a5bc9eecbae87f271c51aef628d8c073b4b4b4c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327", size = 1916994 }, - { url = "https://files.pythonhosted.org/packages/d8/fa/c648308fe711ee1f88192cad6026ab4f925396d1293e8356de7e55be89b5/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6", size = 1968877 }, - { url = "https://files.pythonhosted.org/packages/16/16/b805c74b35607d24d37103007f899abc4880923b04929547ae68d478b7f4/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f", size = 2116814 }, - { url = "https://files.pythonhosted.org/packages/d1/58/5305e723d9fcdf1c5a655e6a4cc2a07128bf644ff4b1d98daf7a9dbf57da/pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769", size = 1738360 }, - { url = "https://files.pythonhosted.org/packages/a5/ae/e14b0ff8b3f48e02394d8acd911376b7b66e164535687ef7dc24ea03072f/pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5", size = 1919411 }, -] - -[[package]] -name = "pydantic-settings" -version = "2.6.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b5/d4/9dfbe238f45ad8b168f5c96ee49a3df0598ce18a0795a983b419949ce65b/pydantic_settings-2.6.1.tar.gz", hash = "sha256:e0f92546d8a9923cb8941689abf85d6601a8c19a23e97a34b2964a2e3f813ca0", size = 75646 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5e/f9/ff95fd7d760af42f647ea87f9b8a383d891cdb5e5dbd4613edaeb094252a/pydantic_settings-2.6.1-py3-none-any.whl", hash = "sha256:7fb0637c786a558d3103436278a7c4f1cfd29ba8973238a50c5bb9a55387da87", size = 28595 }, -] - -[[package]] -name = "pygments" -version = "2.18.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", size = 4891905 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", size = 1205513 }, -] - -[[package]] -name = "pyjwt" -version = "2.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fb/68/ce067f09fca4abeca8771fe667d89cc347d1e99da3e093112ac329c6020e/pyjwt-2.9.0.tar.gz", hash = "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c", size = 78825 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/84/0fdf9b18ba31d69877bd39c9cd6052b47f3761e9910c15de788e519f079f/PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850", size = 22344 }, -] - -[package.optional-dependencies] -crypto = [ - { name = "cryptography" }, -] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892 }, -] - -[[package]] -name = "python-dotenv" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 }, -] - -[[package]] -name = "python-json-logger" -version = "2.0.7" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/4f/da/95963cebfc578dabd323d7263958dfb68898617912bb09327dd30e9c8d13/python-json-logger-2.0.7.tar.gz", hash = "sha256:23e7ec02d34237c5aa1e29a070193a4ea87583bb4e7f8fd06d3de8264c4b2e1c", size = 10508 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/35/a6/145655273568ee78a581e734cf35beb9e33a370b29c5d3c8fee3744de29f/python_json_logger-2.0.7-py3-none-any.whl", hash = "sha256:f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd", size = 8067 }, -] - -[[package]] -name = "python-liquid" -version = "1.12.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "importlib-resources" }, - { name = "python-dateutil" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/59/b4/c4e39470edf507056333cd688a36bb7fbdb17090105d9f454ecf6ff09845/python_liquid-1.12.1.tar.gz", hash = "sha256:7367e979125859fb4116f360f224a89a52ecb455fb26843c43e4d800b389d325", size = 124636 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/6e/bfd01926e28f6cf355a7a8460271ba135013870f5857b06f35dbf65ab237/python_liquid-1.12.1-py3-none-any.whl", hash = "sha256:2224312944be16c1a44406398eb8a07c7e57398d5c0ef15ff950946dbefe7c33", size = 206592 }, -] - -[[package]] -name = "python-multipart" -version = "0.0.17" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/40/22/edea41c2d4a22e666c0c7db7acdcbf7bc8c1c1f7d3b3ca246ec982fec612/python_multipart-0.0.17.tar.gz", hash = "sha256:41330d831cae6e2f22902704ead2826ea038d0419530eadff3ea80175aec5538", size = 36452 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/fb/275137a799169392f1fa88fff2be92f16eee38e982720a8aaadefc4a36b2/python_multipart-0.0.17-py3-none-any.whl", hash = "sha256:15dc4f487e0a9476cc1201261188ee0940165cffc94429b6fc565c4d3045cb5d", size = 24453 }, -] - -[[package]] -name = "pywin32" -version = "308" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/e2/02652007469263fe1466e98439831d65d4ca80ea1a2df29abecedf7e47b7/pywin32-308-cp311-cp311-win32.whl", hash = "sha256:5d8c8015b24a7d6855b1550d8e660d8daa09983c80e5daf89a273e5c6fb5095a", size = 5928156 }, - { url = "https://files.pythonhosted.org/packages/48/ef/f4fb45e2196bc7ffe09cad0542d9aff66b0e33f6c0954b43e49c33cad7bd/pywin32-308-cp311-cp311-win_amd64.whl", hash = "sha256:575621b90f0dc2695fec346b2d6302faebd4f0f45c05ea29404cefe35d89442b", size = 6559559 }, - { url = "https://files.pythonhosted.org/packages/79/ef/68bb6aa865c5c9b11a35771329e95917b5559845bd75b65549407f9fc6b4/pywin32-308-cp311-cp311-win_arm64.whl", hash = "sha256:100a5442b7332070983c4cd03f2e906a5648a5104b8a7f50175f7906efd16bb6", size = 7972495 }, - { url = "https://files.pythonhosted.org/packages/00/7c/d00d6bdd96de4344e06c4afbf218bc86b54436a94c01c71a8701f613aa56/pywin32-308-cp312-cp312-win32.whl", hash = "sha256:587f3e19696f4bf96fde9d8a57cec74a57021ad5f204c9e627e15c33ff568897", size = 5939729 }, - { url = "https://files.pythonhosted.org/packages/21/27/0c8811fbc3ca188f93b5354e7c286eb91f80a53afa4e11007ef661afa746/pywin32-308-cp312-cp312-win_amd64.whl", hash = "sha256:00b3e11ef09ede56c6a43c71f2d31857cf7c54b0ab6e78ac659497abd2834f47", size = 6543015 }, - { url = "https://files.pythonhosted.org/packages/9d/0f/d40f8373608caed2255781a3ad9a51d03a594a1248cd632d6a298daca693/pywin32-308-cp312-cp312-win_arm64.whl", hash = "sha256:9b4de86c8d909aed15b7011182c8cab38c8850de36e6afb1f0db22b8959e3091", size = 7976033 }, - { url = "https://files.pythonhosted.org/packages/a9/a4/aa562d8935e3df5e49c161b427a3a2efad2ed4e9cf81c3de636f1fdddfd0/pywin32-308-cp313-cp313-win32.whl", hash = "sha256:1c44539a37a5b7b21d02ab34e6a4d314e0788f1690d65b48e9b0b89f31abbbed", size = 5938579 }, - { url = "https://files.pythonhosted.org/packages/c7/50/b0efb8bb66210da67a53ab95fd7a98826a97ee21f1d22949863e6d588b22/pywin32-308-cp313-cp313-win_amd64.whl", hash = "sha256:fd380990e792eaf6827fcb7e187b2b4b1cede0585e3d0c9e84201ec27b9905e4", size = 6542056 }, - { url = "https://files.pythonhosted.org/packages/26/df/2b63e3e4f2df0224f8aaf6d131f54fe4e8c96400eb9df563e2aae2e1a1f9/pywin32-308-cp313-cp313-win_arm64.whl", hash = "sha256:ef313c46d4c18dfb82a2431e3051ac8f112ccee1a34f29c263c583c568db63cd", size = 7974986 }, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612 }, - { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040 }, - { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829 }, - { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167 }, - { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952 }, - { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301 }, - { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638 }, - { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850 }, - { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980 }, - { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873 }, - { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302 }, - { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154 }, - { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223 }, - { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542 }, - { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164 }, - { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611 }, - { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591 }, - { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338 }, - { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309 }, - { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679 }, - { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428 }, - { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361 }, - { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523 }, - { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660 }, - { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597 }, - { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527 }, - { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446 }, -] - -[[package]] -name = "regex" -version = "2024.11.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/58/7e4d9493a66c88a7da6d205768119f51af0f684fe7be7bac8328e217a52c/regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638", size = 482669 }, - { url = "https://files.pythonhosted.org/packages/34/4c/8f8e631fcdc2ff978609eaeef1d6994bf2f028b59d9ac67640ed051f1218/regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7", size = 287684 }, - { url = "https://files.pythonhosted.org/packages/c5/1b/f0e4d13e6adf866ce9b069e191f303a30ab1277e037037a365c3aad5cc9c/regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20", size = 284589 }, - { url = "https://files.pythonhosted.org/packages/25/4d/ab21047f446693887f25510887e6820b93f791992994f6498b0318904d4a/regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114", size = 792121 }, - { url = "https://files.pythonhosted.org/packages/45/ee/c867e15cd894985cb32b731d89576c41a4642a57850c162490ea34b78c3b/regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3", size = 831275 }, - { url = "https://files.pythonhosted.org/packages/b3/12/b0f480726cf1c60f6536fa5e1c95275a77624f3ac8fdccf79e6727499e28/regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f", size = 818257 }, - { url = "https://files.pythonhosted.org/packages/bf/ce/0d0e61429f603bac433910d99ef1a02ce45a8967ffbe3cbee48599e62d88/regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0", size = 792727 }, - { url = "https://files.pythonhosted.org/packages/e4/c1/243c83c53d4a419c1556f43777ccb552bccdf79d08fda3980e4e77dd9137/regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55", size = 780667 }, - { url = "https://files.pythonhosted.org/packages/c5/f4/75eb0dd4ce4b37f04928987f1d22547ddaf6c4bae697623c1b05da67a8aa/regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89", size = 776963 }, - { url = "https://files.pythonhosted.org/packages/16/5d/95c568574e630e141a69ff8a254c2f188b4398e813c40d49228c9bbd9875/regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d", size = 784700 }, - { url = "https://files.pythonhosted.org/packages/8e/b5/f8495c7917f15cc6fee1e7f395e324ec3e00ab3c665a7dc9d27562fd5290/regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34", size = 848592 }, - { url = "https://files.pythonhosted.org/packages/1c/80/6dd7118e8cb212c3c60b191b932dc57db93fb2e36fb9e0e92f72a5909af9/regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d", size = 852929 }, - { url = "https://files.pythonhosted.org/packages/11/9b/5a05d2040297d2d254baf95eeeb6df83554e5e1df03bc1a6687fc4ba1f66/regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45", size = 781213 }, - { url = "https://files.pythonhosted.org/packages/26/b7/b14e2440156ab39e0177506c08c18accaf2b8932e39fb092074de733d868/regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9", size = 261734 }, - { url = "https://files.pythonhosted.org/packages/80/32/763a6cc01d21fb3819227a1cc3f60fd251c13c37c27a73b8ff4315433a8e/regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60", size = 274052 }, - { url = "https://files.pythonhosted.org/packages/ba/30/9a87ce8336b172cc232a0db89a3af97929d06c11ceaa19d97d84fa90a8f8/regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a", size = 483781 }, - { url = "https://files.pythonhosted.org/packages/01/e8/00008ad4ff4be8b1844786ba6636035f7ef926db5686e4c0f98093612add/regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9", size = 288455 }, - { url = "https://files.pythonhosted.org/packages/60/85/cebcc0aff603ea0a201667b203f13ba75d9fc8668fab917ac5b2de3967bc/regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2", size = 284759 }, - { url = "https://files.pythonhosted.org/packages/94/2b/701a4b0585cb05472a4da28ee28fdfe155f3638f5e1ec92306d924e5faf0/regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4", size = 794976 }, - { url = "https://files.pythonhosted.org/packages/4b/bf/fa87e563bf5fee75db8915f7352e1887b1249126a1be4813837f5dbec965/regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577", size = 833077 }, - { url = "https://files.pythonhosted.org/packages/a1/56/7295e6bad94b047f4d0834e4779491b81216583c00c288252ef625c01d23/regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3", size = 823160 }, - { url = "https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e", size = 796896 }, - { url = "https://files.pythonhosted.org/packages/24/56/0b3f1b66d592be6efec23a795b37732682520b47c53da5a32c33ed7d84e3/regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe", size = 783997 }, - { url = "https://files.pythonhosted.org/packages/f9/a1/eb378dada8b91c0e4c5f08ffb56f25fcae47bf52ad18f9b2f33b83e6d498/regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e", size = 781725 }, - { url = "https://files.pythonhosted.org/packages/83/f2/033e7dec0cfd6dda93390089864732a3409246ffe8b042e9554afa9bff4e/regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29", size = 789481 }, - { url = "https://files.pythonhosted.org/packages/83/23/15d4552ea28990a74e7696780c438aadd73a20318c47e527b47a4a5a596d/regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39", size = 852896 }, - { url = "https://files.pythonhosted.org/packages/e3/39/ed4416bc90deedbfdada2568b2cb0bc1fdb98efe11f5378d9892b2a88f8f/regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51", size = 860138 }, - { url = "https://files.pythonhosted.org/packages/93/2d/dd56bb76bd8e95bbce684326302f287455b56242a4f9c61f1bc76e28360e/regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad", size = 787692 }, - { url = "https://files.pythonhosted.org/packages/0b/55/31877a249ab7a5156758246b9c59539abbeba22461b7d8adc9e8475ff73e/regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54", size = 262135 }, - { url = "https://files.pythonhosted.org/packages/38/ec/ad2d7de49a600cdb8dd78434a1aeffe28b9d6fc42eb36afab4a27ad23384/regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b", size = 273567 }, - { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525 }, - { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324 }, - { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617 }, - { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023 }, - { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072 }, - { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130 }, - { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857 }, - { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006 }, - { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650 }, - { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545 }, - { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045 }, - { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182 }, - { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733 }, - { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122 }, - { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545 }, -] - -[[package]] -name = "requests" -version = "2.32.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, -] - -[[package]] -name = "rich" -version = "13.9.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 }, -] - -[[package]] -name = "semantic-workbench-api-model" -version = "0.1.0" -source = { editable = "../semantic-workbench-api-model" } -dependencies = [ - { name = "asgi-correlation-id" }, - { name = "fastapi", extra = ["standard"] }, -] - -[package.metadata] -requires-dist = [ - { name = "asgi-correlation-id", specifier = ">=4.3.1" }, - { name = "fastapi", extras = ["standard"], specifier = "~=0.115.0" }, -] - -[[package]] -name = "semantic-workbench-assistant" -version = "0.1.0" -source = { editable = "../semantic-workbench-assistant" } -dependencies = [ - { name = "asgi-correlation-id" }, - { name = "backoff" }, - { name = "deepmerge" }, - { name = "fastapi", extra = ["standard"] }, - { name = "pydantic-settings" }, - { name = "python-json-logger" }, - { name = "rich" }, - { name = "semantic-workbench-api-model" }, -] - -[package.metadata] -requires-dist = [ - { name = "asgi-correlation-id", specifier = ">=4.3.1" }, - { name = "backoff", specifier = ">=2.2.1" }, - { name = "deepmerge", specifier = ">=2.0" }, - { name = "fastapi", extras = ["standard"], specifier = "~=0.115.0" }, - { name = "pydantic-settings", specifier = ">=2.2.0" }, - { name = "python-json-logger", specifier = ">=2.0.7" }, - { name = "rich", specifier = ">=13.7.0" }, - { name = "semantic-workbench-api-model", editable = "../semantic-workbench-api-model" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "asgi-lifespan", specifier = ">=2.1.0" }, - { name = "pytest", specifier = ">=7.4.3" }, - { name = "pytest-asyncio", specifier = ">=0.23.5.post1" }, - { name = "pytest-httpx", specifier = ">=0.30.0" }, -] - -[[package]] -name = "shellingham" -version = "1.5.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 }, -] - -[[package]] -name = "six" -version = "1.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/71/39/171f1c67cd00715f190ba0b100d606d440a28c93c7714febeca8b79af85e/six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", size = 34041 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", size = 11053 }, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, -] - -[[package]] -name = "starlette" -version = "0.41.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3e/da/1fb4bdb72ae12b834becd7e1e7e47001d32f91ec0ce8d7bc1b618d9f0bd9/starlette-0.41.2.tar.gz", hash = "sha256:9834fd799d1a87fd346deb76158668cfa0b0d56f85caefe8268e2d97c3468b62", size = 2573867 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/54/43/f185bfd0ca1d213beb4293bed51d92254df23d8ceaf6c0e17146d508a776/starlette-0.41.2-py3-none-any.whl", hash = "sha256:fbc189474b4731cf30fcef52f18a8d070e3f3b46c6a04c97579e85e6ffca942d", size = 73259 }, -] - -[[package]] -name = "tiktoken" -version = "0.8.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "regex" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/37/02/576ff3a6639e755c4f70997b2d315f56d6d71e0d046f4fb64cb81a3fb099/tiktoken-0.8.0.tar.gz", hash = "sha256:9ccbb2740f24542534369c5635cfd9b2b3c2490754a78ac8831d99f89f94eeb2", size = 35107 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/1e/ca48e7bfeeccaf76f3a501bd84db1fa28b3c22c9d1a1f41af9fb7579c5f6/tiktoken-0.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d622d8011e6d6f239297efa42a2657043aaed06c4f68833550cac9e9bc723ef1", size = 1039700 }, - { url = "https://files.pythonhosted.org/packages/8c/f8/f0101d98d661b34534769c3818f5af631e59c36ac6d07268fbfc89e539ce/tiktoken-0.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2efaf6199717b4485031b4d6edb94075e4d79177a172f38dd934d911b588d54a", size = 982413 }, - { url = "https://files.pythonhosted.org/packages/ac/3c/2b95391d9bd520a73830469f80a96e3790e6c0a5ac2444f80f20b4b31051/tiktoken-0.8.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5637e425ce1fc49cf716d88df3092048359a4b3bbb7da762840426e937ada06d", size = 1144242 }, - { url = "https://files.pythonhosted.org/packages/01/c4/c4a4360de845217b6aa9709c15773484b50479f36bb50419c443204e5de9/tiktoken-0.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fb0e352d1dbe15aba082883058b3cce9e48d33101bdaac1eccf66424feb5b47", size = 1176588 }, - { url = "https://files.pythonhosted.org/packages/f8/a3/ef984e976822cd6c2227c854f74d2e60cf4cd6fbfca46251199914746f78/tiktoken-0.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:56edfefe896c8f10aba372ab5706b9e3558e78db39dd497c940b47bf228bc419", size = 1237261 }, - { url = "https://files.pythonhosted.org/packages/1e/86/eea2309dc258fb86c7d9b10db536434fc16420feaa3b6113df18b23db7c2/tiktoken-0.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:326624128590def898775b722ccc327e90b073714227175ea8febbc920ac0a99", size = 884537 }, - { url = "https://files.pythonhosted.org/packages/c1/22/34b2e136a6f4af186b6640cbfd6f93400783c9ef6cd550d9eab80628d9de/tiktoken-0.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:881839cfeae051b3628d9823b2e56b5cc93a9e2efb435f4cf15f17dc45f21586", size = 1039357 }, - { url = "https://files.pythonhosted.org/packages/04/d2/c793cf49c20f5855fd6ce05d080c0537d7418f22c58e71f392d5e8c8dbf7/tiktoken-0.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fe9399bdc3f29d428f16a2f86c3c8ec20be3eac5f53693ce4980371c3245729b", size = 982616 }, - { url = "https://files.pythonhosted.org/packages/b3/a1/79846e5ef911cd5d75c844de3fa496a10c91b4b5f550aad695c5df153d72/tiktoken-0.8.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a58deb7075d5b69237a3ff4bb51a726670419db6ea62bdcd8bd80c78497d7ab", size = 1144011 }, - { url = "https://files.pythonhosted.org/packages/26/32/e0e3a859136e95c85a572e4806dc58bf1ddf651108ae8b97d5f3ebe1a244/tiktoken-0.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2908c0d043a7d03ebd80347266b0e58440bdef5564f84f4d29fb235b5df3b04", size = 1175432 }, - { url = "https://files.pythonhosted.org/packages/c7/89/926b66e9025b97e9fbabeaa59048a736fe3c3e4530a204109571104f921c/tiktoken-0.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:294440d21a2a51e12d4238e68a5972095534fe9878be57d905c476017bff99fc", size = 1236576 }, - { url = "https://files.pythonhosted.org/packages/45/e2/39d4aa02a52bba73b2cd21ba4533c84425ff8786cc63c511d68c8897376e/tiktoken-0.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:d8f3192733ac4d77977432947d563d7e1b310b96497acd3c196c9bddb36ed9db", size = 883824 }, - { url = "https://files.pythonhosted.org/packages/e3/38/802e79ba0ee5fcbf240cd624143f57744e5d411d2e9d9ad2db70d8395986/tiktoken-0.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:02be1666096aff7da6cbd7cdaa8e7917bfed3467cd64b38b1f112e96d3b06a24", size = 1039648 }, - { url = "https://files.pythonhosted.org/packages/b1/da/24cdbfc302c98663fbea66f5866f7fa1048405c7564ab88483aea97c3b1a/tiktoken-0.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c94ff53c5c74b535b2cbf431d907fc13c678bbd009ee633a2aca269a04389f9a", size = 982763 }, - { url = "https://files.pythonhosted.org/packages/e4/f0/0ecf79a279dfa41fc97d00adccf976ecc2556d3c08ef3e25e45eb31f665b/tiktoken-0.8.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b231f5e8982c245ee3065cd84a4712d64692348bc609d84467c57b4b72dcbc5", size = 1144417 }, - { url = "https://files.pythonhosted.org/packages/ab/d3/155d2d4514f3471a25dc1d6d20549ef254e2aa9bb5b1060809b1d3b03d3a/tiktoken-0.8.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4177faa809bd55f699e88c96d9bb4635d22e3f59d635ba6fd9ffedf7150b9953", size = 1175108 }, - { url = "https://files.pythonhosted.org/packages/19/eb/5989e16821ee8300ef8ee13c16effc20dfc26c777d05fbb6825e3c037b81/tiktoken-0.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5376b6f8dc4753cd81ead935c5f518fa0fbe7e133d9e25f648d8c4dabdd4bad7", size = 1236520 }, - { url = "https://files.pythonhosted.org/packages/40/59/14b20465f1d1cb89cfbc96ec27e5617b2d41c79da12b5e04e96d689be2a7/tiktoken-0.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:18228d624807d66c87acd8f25fc135665617cab220671eb65b50f5d70fa51f69", size = 883849 }, -] - -[[package]] -name = "tqdm" -version = "4.67.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "platform_system == 'Windows'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e8/4f/0153c21dc5779a49a0598c445b1978126b1344bab9ee71e53e44877e14e0/tqdm-4.67.0.tar.gz", hash = "sha256:fe5a6f95e6fe0b9755e9469b77b9c3cf850048224ecaa8293d7d2d31f97d869a", size = 169739 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/78/57043611a16c655c8350b4c01b8d6abfb38cc2acb475238b62c2146186d7/tqdm-4.67.0-py3-none-any.whl", hash = "sha256:0cd8af9d56911acab92182e88d763100d4788bdf421d251616040cc4d44863be", size = 78590 }, -] - -[[package]] -name = "typer" -version = "0.12.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "shellingham" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c5/58/a79003b91ac2c6890fc5d90145c662fd5771c6f11447f116b63300436bc9/typer-0.12.5.tar.gz", hash = "sha256:f592f089bedcc8ec1b974125d64851029c3b1af145f04aca64d69410f0c9b722", size = 98953 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a8/2b/886d13e742e514f704c33c4caa7df0f3b89e5a25ef8db02aa9ca3d9535d5/typer-0.12.5-py3-none-any.whl", hash = "sha256:62fe4e471711b147e3365034133904df3e235698399bc4de2b36c8579298d52b", size = 47288 }, -] - -[[package]] -name = "typing-extensions" -version = "4.12.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, -] - -[[package]] -name = "urllib3" -version = "2.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", size = 300677 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338 }, -] - -[[package]] -name = "uvicorn" -version = "0.32.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e0/fc/1d785078eefd6945f3e5bab5c076e4230698046231eb0f3747bc5c8fa992/uvicorn-0.32.0.tar.gz", hash = "sha256:f78b36b143c16f54ccdb8190d0a26b5f1901fe5a3c777e1ab29f26391af8551e", size = 77564 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/14/78bd0e95dd2444b6caacbca2b730671d4295ccb628ef58b81bee903629df/uvicorn-0.32.0-py3-none-any.whl", hash = "sha256:60b8f3a5ac027dcd31448f411ced12b5ef452c646f76f02f8cc3f25d8d26fd82", size = 63723 }, -] - -[package.optional-dependencies] -standard = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "httptools" }, - { name = "python-dotenv" }, - { name = "pyyaml" }, - { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, - { name = "watchfiles" }, - { name = "websockets" }, -] - -[[package]] -name = "uvloop" -version = "0.21.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/57/a7/4cf0334105c1160dd6819f3297f8700fda7fc30ab4f61fbf3e725acbc7cc/uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8", size = 1447410 }, - { url = "https://files.pythonhosted.org/packages/8c/7c/1517b0bbc2dbe784b563d6ab54f2ef88c890fdad77232c98ed490aa07132/uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0", size = 805476 }, - { url = "https://files.pythonhosted.org/packages/ee/ea/0bfae1aceb82a503f358d8d2fa126ca9dbdb2ba9c7866974faec1cb5875c/uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e", size = 3960855 }, - { url = "https://files.pythonhosted.org/packages/8a/ca/0864176a649838b838f36d44bf31c451597ab363b60dc9e09c9630619d41/uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb", size = 3973185 }, - { url = "https://files.pythonhosted.org/packages/30/bf/08ad29979a936d63787ba47a540de2132169f140d54aa25bc8c3df3e67f4/uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6", size = 3820256 }, - { url = "https://files.pythonhosted.org/packages/da/e2/5cf6ef37e3daf2f06e651aae5ea108ad30df3cb269102678b61ebf1fdf42/uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d", size = 3937323 }, - { url = "https://files.pythonhosted.org/packages/8c/4c/03f93178830dc7ce8b4cdee1d36770d2f5ebb6f3d37d354e061eefc73545/uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c", size = 1471284 }, - { url = "https://files.pythonhosted.org/packages/43/3e/92c03f4d05e50f09251bd8b2b2b584a2a7f8fe600008bcc4523337abe676/uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2", size = 821349 }, - { url = "https://files.pythonhosted.org/packages/a6/ef/a02ec5da49909dbbfb1fd205a9a1ac4e88ea92dcae885e7c961847cd51e2/uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d", size = 4580089 }, - { url = "https://files.pythonhosted.org/packages/06/a7/b4e6a19925c900be9f98bec0a75e6e8f79bb53bdeb891916609ab3958967/uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc", size = 4693770 }, - { url = "https://files.pythonhosted.org/packages/ce/0c/f07435a18a4b94ce6bd0677d8319cd3de61f3a9eeb1e5f8ab4e8b5edfcb3/uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb", size = 4451321 }, - { url = "https://files.pythonhosted.org/packages/8f/eb/f7032be105877bcf924709c97b1bf3b90255b4ec251f9340cef912559f28/uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f", size = 4659022 }, - { url = "https://files.pythonhosted.org/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123 }, - { url = "https://files.pythonhosted.org/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325 }, - { url = "https://files.pythonhosted.org/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806 }, - { url = "https://files.pythonhosted.org/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068 }, - { url = "https://files.pythonhosted.org/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428 }, - { url = "https://files.pythonhosted.org/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018 }, -] - -[[package]] -name = "watchfiles" -version = "0.24.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c8/27/2ba23c8cc85796e2d41976439b08d52f691655fdb9401362099502d1f0cf/watchfiles-0.24.0.tar.gz", hash = "sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1", size = 37870 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/85/02/366ae902cd81ca5befcd1854b5c7477b378f68861597cef854bd6dc69fbe/watchfiles-0.24.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:bdcd5538e27f188dd3c804b4a8d5f52a7fc7f87e7fd6b374b8e36a4ca03db428", size = 375579 }, - { url = "https://files.pythonhosted.org/packages/bc/67/d8c9d256791fe312fea118a8a051411337c948101a24586e2df237507976/watchfiles-0.24.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2dadf8a8014fde6addfd3c379e6ed1a981c8f0a48292d662e27cabfe4239c83c", size = 367726 }, - { url = "https://files.pythonhosted.org/packages/b1/dc/a8427b21ef46386adf824a9fec4be9d16a475b850616cfd98cf09a97a2ef/watchfiles-0.24.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6509ed3f467b79d95fc62a98229f79b1a60d1b93f101e1c61d10c95a46a84f43", size = 437735 }, - { url = "https://files.pythonhosted.org/packages/3a/21/0b20bef581a9fbfef290a822c8be645432ceb05fb0741bf3c032e0d90d9a/watchfiles-0.24.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8360f7314a070c30e4c976b183d1d8d1585a4a50c5cb603f431cebcbb4f66327", size = 433644 }, - { url = "https://files.pythonhosted.org/packages/1c/e8/d5e5f71cc443c85a72e70b24269a30e529227986096abe091040d6358ea9/watchfiles-0.24.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:316449aefacf40147a9efaf3bd7c9bdd35aaba9ac5d708bd1eb5763c9a02bef5", size = 450928 }, - { url = "https://files.pythonhosted.org/packages/61/ee/bf17f5a370c2fcff49e1fec987a6a43fd798d8427ea754ce45b38f9e117a/watchfiles-0.24.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73bde715f940bea845a95247ea3e5eb17769ba1010efdc938ffcb967c634fa61", size = 469072 }, - { url = "https://files.pythonhosted.org/packages/a3/34/03b66d425986de3fc6077e74a74c78da298f8cb598887f664a4485e55543/watchfiles-0.24.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3770e260b18e7f4e576edca4c0a639f704088602e0bc921c5c2e721e3acb8d15", size = 475517 }, - { url = "https://files.pythonhosted.org/packages/70/eb/82f089c4f44b3171ad87a1b433abb4696f18eb67292909630d886e073abe/watchfiles-0.24.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa0fd7248cf533c259e59dc593a60973a73e881162b1a2f73360547132742823", size = 425480 }, - { url = "https://files.pythonhosted.org/packages/53/20/20509c8f5291e14e8a13104b1808cd7cf5c44acd5feaecb427a49d387774/watchfiles-0.24.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d7a2e3b7f5703ffbd500dabdefcbc9eafeff4b9444bbdd5d83d79eedf8428fab", size = 612322 }, - { url = "https://files.pythonhosted.org/packages/df/2b/5f65014a8cecc0a120f5587722068a975a692cadbe9fe4ea56b3d8e43f14/watchfiles-0.24.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d831ee0a50946d24a53821819b2327d5751b0c938b12c0653ea5be7dea9c82ec", size = 595094 }, - { url = "https://files.pythonhosted.org/packages/18/98/006d8043a82c0a09d282d669c88e587b3a05cabdd7f4900e402250a249ac/watchfiles-0.24.0-cp311-none-win32.whl", hash = "sha256:49d617df841a63b4445790a254013aea2120357ccacbed00253f9c2b5dc24e2d", size = 264191 }, - { url = "https://files.pythonhosted.org/packages/8a/8b/badd9247d6ec25f5f634a9b3d0d92e39c045824ec7e8afcedca8ee52c1e2/watchfiles-0.24.0-cp311-none-win_amd64.whl", hash = "sha256:d3dcb774e3568477275cc76554b5a565024b8ba3a0322f77c246bc7111c5bb9c", size = 277527 }, - { url = "https://files.pythonhosted.org/packages/af/19/35c957c84ee69d904299a38bae3614f7cede45f07f174f6d5a2f4dbd6033/watchfiles-0.24.0-cp311-none-win_arm64.whl", hash = "sha256:9301c689051a4857d5b10777da23fafb8e8e921bcf3abe6448a058d27fb67633", size = 266253 }, - { url = "https://files.pythonhosted.org/packages/35/82/92a7bb6dc82d183e304a5f84ae5437b59ee72d48cee805a9adda2488b237/watchfiles-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7211b463695d1e995ca3feb38b69227e46dbd03947172585ecb0588f19b0d87a", size = 374137 }, - { url = "https://files.pythonhosted.org/packages/87/91/49e9a497ddaf4da5e3802d51ed67ff33024597c28f652b8ab1e7c0f5718b/watchfiles-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4b8693502d1967b00f2fb82fc1e744df128ba22f530e15b763c8d82baee15370", size = 367733 }, - { url = "https://files.pythonhosted.org/packages/0d/d8/90eb950ab4998effea2df4cf3a705dc594f6bc501c5a353073aa990be965/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdab9555053399318b953a1fe1f586e945bc8d635ce9d05e617fd9fe3a4687d6", size = 437322 }, - { url = "https://files.pythonhosted.org/packages/6c/a2/300b22e7bc2a222dd91fce121cefa7b49aa0d26a627b2777e7bdfcf1110b/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:34e19e56d68b0dad5cff62273107cf5d9fbaf9d75c46277aa5d803b3ef8a9e9b", size = 433409 }, - { url = "https://files.pythonhosted.org/packages/99/44/27d7708a43538ed6c26708bcccdde757da8b7efb93f4871d4cc39cffa1cc/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41face41f036fee09eba33a5b53a73e9a43d5cb2c53dad8e61fa6c9f91b5a51e", size = 452142 }, - { url = "https://files.pythonhosted.org/packages/b0/ec/c4e04f755be003129a2c5f3520d2c47026f00da5ecb9ef1e4f9449637571/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5148c2f1ea043db13ce9b0c28456e18ecc8f14f41325aa624314095b6aa2e9ea", size = 469414 }, - { url = "https://files.pythonhosted.org/packages/c5/4e/cdd7de3e7ac6432b0abf282ec4c1a1a2ec62dfe423cf269b86861667752d/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e4bd963a935aaf40b625c2499f3f4f6bbd0c3776f6d3bc7c853d04824ff1c9f", size = 472962 }, - { url = "https://files.pythonhosted.org/packages/27/69/e1da9d34da7fc59db358424f5d89a56aaafe09f6961b64e36457a80a7194/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c79d7719d027b7a42817c5d96461a99b6a49979c143839fc37aa5748c322f234", size = 425705 }, - { url = "https://files.pythonhosted.org/packages/e8/c1/24d0f7357be89be4a43e0a656259676ea3d7a074901f47022f32e2957798/watchfiles-0.24.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:32aa53a9a63b7f01ed32e316e354e81e9da0e6267435c7243bf8ae0f10b428ef", size = 612851 }, - { url = "https://files.pythonhosted.org/packages/c7/af/175ba9b268dec56f821639c9893b506c69fd999fe6a2e2c51de420eb2f01/watchfiles-0.24.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ce72dba6a20e39a0c628258b5c308779b8697f7676c254a845715e2a1039b968", size = 594868 }, - { url = "https://files.pythonhosted.org/packages/44/81/1f701323a9f70805bc81c74c990137123344a80ea23ab9504a99492907f8/watchfiles-0.24.0-cp312-none-win32.whl", hash = "sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444", size = 264109 }, - { url = "https://files.pythonhosted.org/packages/b4/0b/32cde5bc2ebd9f351be326837c61bdeb05ad652b793f25c91cac0b48a60b/watchfiles-0.24.0-cp312-none-win_amd64.whl", hash = "sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896", size = 277055 }, - { url = "https://files.pythonhosted.org/packages/4b/81/daade76ce33d21dbec7a15afd7479de8db786e5f7b7d249263b4ea174e08/watchfiles-0.24.0-cp312-none-win_arm64.whl", hash = "sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418", size = 266169 }, - { url = "https://files.pythonhosted.org/packages/30/dc/6e9f5447ae14f645532468a84323a942996d74d5e817837a5c8ce9d16c69/watchfiles-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48", size = 373764 }, - { url = "https://files.pythonhosted.org/packages/79/c0/c3a9929c372816c7fc87d8149bd722608ea58dc0986d3ef7564c79ad7112/watchfiles-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90", size = 367873 }, - { url = "https://files.pythonhosted.org/packages/2e/11/ff9a4445a7cfc1c98caf99042df38964af12eed47d496dd5d0d90417349f/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94", size = 438381 }, - { url = "https://files.pythonhosted.org/packages/48/a3/763ba18c98211d7bb6c0f417b2d7946d346cdc359d585cc28a17b48e964b/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e", size = 432809 }, - { url = "https://files.pythonhosted.org/packages/30/4c/616c111b9d40eea2547489abaf4ffc84511e86888a166d3a4522c2ba44b5/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827", size = 451801 }, - { url = "https://files.pythonhosted.org/packages/b6/be/d7da83307863a422abbfeb12903a76e43200c90ebe5d6afd6a59d158edea/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df", size = 468886 }, - { url = "https://files.pythonhosted.org/packages/1d/d3/3dfe131ee59d5e90b932cf56aba5c996309d94dafe3d02d204364c23461c/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab", size = 472973 }, - { url = "https://files.pythonhosted.org/packages/42/6c/279288cc5653a289290d183b60a6d80e05f439d5bfdfaf2d113738d0f932/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f", size = 425282 }, - { url = "https://files.pythonhosted.org/packages/d6/d7/58afe5e85217e845edf26d8780c2d2d2ae77675eeb8d1b8b8121d799ce52/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b", size = 612540 }, - { url = "https://files.pythonhosted.org/packages/6d/d5/b96eeb9fe3fda137200dd2f31553670cbc731b1e13164fd69b49870b76ec/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18", size = 593625 }, - { url = "https://files.pythonhosted.org/packages/c1/e5/c326fe52ee0054107267608d8cea275e80be4455b6079491dfd9da29f46f/watchfiles-0.24.0-cp313-none-win32.whl", hash = "sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07", size = 263899 }, - { url = "https://files.pythonhosted.org/packages/a6/8b/8a7755c5e7221bb35fe4af2dc44db9174f90ebf0344fd5e9b1e8b42d381e/watchfiles-0.24.0-cp313-none-win_amd64.whl", hash = "sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366", size = 276622 }, -] - -[[package]] -name = "websockets" -version = "13.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e2/73/9223dbc7be3dcaf2a7bbf756c351ec8da04b1fa573edaf545b95f6b0c7fd/websockets-13.1.tar.gz", hash = "sha256:a3b3366087c1bc0a2795111edcadddb8b3b59509d5db5d7ea3fdd69f954a8878", size = 158549 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b2/f0/cf0b8a30d86b49e267ac84addbebbc7a48a6e7bb7c19db80f62411452311/websockets-13.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:61fc0dfcda609cda0fc9fe7977694c0c59cf9d749fbb17f4e9483929e3c48a19", size = 157813 }, - { url = "https://files.pythonhosted.org/packages/bf/e7/22285852502e33071a8cf0ac814f8988480ec6db4754e067b8b9d0e92498/websockets-13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ceec59f59d092c5007e815def4ebb80c2de330e9588e101cf8bd94c143ec78a5", size = 155469 }, - { url = "https://files.pythonhosted.org/packages/68/d4/c8c7c1e5b40ee03c5cc235955b0fb1ec90e7e37685a5f69229ad4708dcde/websockets-13.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c1dca61c6db1166c48b95198c0b7d9c990b30c756fc2923cc66f68d17dc558fd", size = 155717 }, - { url = "https://files.pythonhosted.org/packages/c9/e4/c50999b9b848b1332b07c7fd8886179ac395cb766fda62725d1539e7bc6c/websockets-13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:308e20f22c2c77f3f39caca508e765f8725020b84aa963474e18c59accbf4c02", size = 165379 }, - { url = "https://files.pythonhosted.org/packages/bc/49/4a4ad8c072f18fd79ab127650e47b160571aacfc30b110ee305ba25fffc9/websockets-13.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:62d516c325e6540e8a57b94abefc3459d7dab8ce52ac75c96cad5549e187e3a7", size = 164376 }, - { url = "https://files.pythonhosted.org/packages/af/9b/8c06d425a1d5a74fd764dd793edd02be18cf6fc3b1ccd1f29244ba132dc0/websockets-13.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c6e35319b46b99e168eb98472d6c7d8634ee37750d7693656dc766395df096", size = 164753 }, - { url = "https://files.pythonhosted.org/packages/d5/5b/0acb5815095ff800b579ffc38b13ab1b915b317915023748812d24e0c1ac/websockets-13.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5f9fee94ebafbc3117c30be1844ed01a3b177bb6e39088bc6b2fa1dc15572084", size = 165051 }, - { url = "https://files.pythonhosted.org/packages/30/93/c3891c20114eacb1af09dedfcc620c65c397f4fd80a7009cd12d9457f7f5/websockets-13.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7c1e90228c2f5cdde263253fa5db63e6653f1c00e7ec64108065a0b9713fa1b3", size = 164489 }, - { url = "https://files.pythonhosted.org/packages/28/09/af9e19885539759efa2e2cd29b8b3f9eecef7ecefea40d46612f12138b36/websockets-13.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6548f29b0e401eea2b967b2fdc1c7c7b5ebb3eeb470ed23a54cd45ef078a0db9", size = 164438 }, - { url = "https://files.pythonhosted.org/packages/b6/08/6f38b8e625b3d93de731f1d248cc1493327f16cb45b9645b3e791782cff0/websockets-13.1-cp311-cp311-win32.whl", hash = "sha256:c11d4d16e133f6df8916cc5b7e3e96ee4c44c936717d684a94f48f82edb7c92f", size = 158710 }, - { url = "https://files.pythonhosted.org/packages/fb/39/ec8832ecb9bb04a8d318149005ed8cee0ba4e0205835da99e0aa497a091f/websockets-13.1-cp311-cp311-win_amd64.whl", hash = "sha256:d04f13a1d75cb2b8382bdc16ae6fa58c97337253826dfe136195b7f89f661557", size = 159137 }, - { url = "https://files.pythonhosted.org/packages/df/46/c426282f543b3c0296cf964aa5a7bb17e984f58dde23460c3d39b3148fcf/websockets-13.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9d75baf00138f80b48f1eac72ad1535aac0b6461265a0bcad391fc5aba875cfc", size = 157821 }, - { url = "https://files.pythonhosted.org/packages/aa/85/22529867010baac258da7c45848f9415e6cf37fef00a43856627806ffd04/websockets-13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:9b6f347deb3dcfbfde1c20baa21c2ac0751afaa73e64e5b693bb2b848efeaa49", size = 155480 }, - { url = "https://files.pythonhosted.org/packages/29/2c/bdb339bfbde0119a6e84af43ebf6275278698a2241c2719afc0d8b0bdbf2/websockets-13.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de58647e3f9c42f13f90ac7e5f58900c80a39019848c5547bc691693098ae1bd", size = 155715 }, - { url = "https://files.pythonhosted.org/packages/9f/d0/8612029ea04c5c22bf7af2fd3d63876c4eaeef9b97e86c11972a43aa0e6c/websockets-13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1b54689e38d1279a51d11e3467dd2f3a50f5f2e879012ce8f2d6943f00e83f0", size = 165647 }, - { url = "https://files.pythonhosted.org/packages/56/04/1681ed516fa19ca9083f26d3f3a302257e0911ba75009533ed60fbb7b8d1/websockets-13.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf1781ef73c073e6b0f90af841aaf98501f975d306bbf6221683dd594ccc52b6", size = 164592 }, - { url = "https://files.pythonhosted.org/packages/38/6f/a96417a49c0ed132bb6087e8e39a37db851c70974f5c724a4b2a70066996/websockets-13.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d23b88b9388ed85c6faf0e74d8dec4f4d3baf3ecf20a65a47b836d56260d4b9", size = 165012 }, - { url = "https://files.pythonhosted.org/packages/40/8b/fccf294919a1b37d190e86042e1a907b8f66cff2b61e9befdbce03783e25/websockets-13.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3c78383585f47ccb0fcf186dcb8a43f5438bd7d8f47d69e0b56f71bf431a0a68", size = 165311 }, - { url = "https://files.pythonhosted.org/packages/c1/61/f8615cf7ce5fe538476ab6b4defff52beb7262ff8a73d5ef386322d9761d/websockets-13.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d6d300f8ec35c24025ceb9b9019ae9040c1ab2f01cddc2bcc0b518af31c75c14", size = 164692 }, - { url = "https://files.pythonhosted.org/packages/5c/f1/a29dd6046d3a722d26f182b783a7997d25298873a14028c4760347974ea3/websockets-13.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a9dcaf8b0cc72a392760bb8755922c03e17a5a54e08cca58e8b74f6902b433cf", size = 164686 }, - { url = "https://files.pythonhosted.org/packages/0f/99/ab1cdb282f7e595391226f03f9b498f52109d25a2ba03832e21614967dfa/websockets-13.1-cp312-cp312-win32.whl", hash = "sha256:2f85cf4f2a1ba8f602298a853cec8526c2ca42a9a4b947ec236eaedb8f2dc80c", size = 158712 }, - { url = "https://files.pythonhosted.org/packages/46/93/e19160db48b5581feac8468330aa11b7292880a94a37d7030478596cc14e/websockets-13.1-cp312-cp312-win_amd64.whl", hash = "sha256:38377f8b0cdeee97c552d20cf1865695fcd56aba155ad1b4ca8779a5b6ef4ac3", size = 159145 }, - { url = "https://files.pythonhosted.org/packages/51/20/2b99ca918e1cbd33c53db2cace5f0c0cd8296fc77558e1908799c712e1cd/websockets-13.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a9ab1e71d3d2e54a0aa646ab6d4eebfaa5f416fe78dfe4da2839525dc5d765c6", size = 157828 }, - { url = "https://files.pythonhosted.org/packages/b8/47/0932a71d3d9c0e9483174f60713c84cee58d62839a143f21a2bcdbd2d205/websockets-13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b9d7439d7fab4dce00570bb906875734df13d9faa4b48e261c440a5fec6d9708", size = 155487 }, - { url = "https://files.pythonhosted.org/packages/a9/60/f1711eb59ac7a6c5e98e5637fef5302f45b6f76a2c9d64fd83bbb341377a/websockets-13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327b74e915cf13c5931334c61e1a41040e365d380f812513a255aa804b183418", size = 155721 }, - { url = "https://files.pythonhosted.org/packages/6a/e6/ba9a8db7f9d9b0e5f829cf626ff32677f39824968317223605a6b419d445/websockets-13.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:325b1ccdbf5e5725fdcb1b0e9ad4d2545056479d0eee392c291c1bf76206435a", size = 165609 }, - { url = "https://files.pythonhosted.org/packages/c1/22/4ec80f1b9c27a0aebd84ccd857252eda8418ab9681eb571b37ca4c5e1305/websockets-13.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:346bee67a65f189e0e33f520f253d5147ab76ae42493804319b5716e46dddf0f", size = 164556 }, - { url = "https://files.pythonhosted.org/packages/27/ac/35f423cb6bb15600438db80755609d27eda36d4c0b3c9d745ea12766c45e/websockets-13.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:91a0fa841646320ec0d3accdff5b757b06e2e5c86ba32af2e0815c96c7a603c5", size = 164993 }, - { url = "https://files.pythonhosted.org/packages/31/4e/98db4fd267f8be9e52e86b6ee4e9aa7c42b83452ea0ea0672f176224b977/websockets-13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:18503d2c5f3943e93819238bf20df71982d193f73dcecd26c94514f417f6b135", size = 165360 }, - { url = "https://files.pythonhosted.org/packages/3f/15/3f0de7cda70ffc94b7e7024544072bc5b26e2c1eb36545291abb755d8cdb/websockets-13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:a9cd1af7e18e5221d2878378fbc287a14cd527fdd5939ed56a18df8a31136bb2", size = 164745 }, - { url = "https://files.pythonhosted.org/packages/a1/6e/66b6b756aebbd680b934c8bdbb6dcb9ce45aad72cde5f8a7208dbb00dd36/websockets-13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:70c5be9f416aa72aab7a2a76c90ae0a4fe2755c1816c153c1a2bcc3333ce4ce6", size = 164732 }, - { url = "https://files.pythonhosted.org/packages/35/c6/12e3aab52c11aeb289e3dbbc05929e7a9d90d7a9173958477d3ef4f8ce2d/websockets-13.1-cp313-cp313-win32.whl", hash = "sha256:624459daabeb310d3815b276c1adef475b3e6804abaf2d9d2c061c319f7f187d", size = 158709 }, - { url = "https://files.pythonhosted.org/packages/41/d8/63d6194aae711d7263df4498200c690a9c39fb437ede10f3e157a6343e0d/websockets-13.1-cp313-cp313-win_amd64.whl", hash = "sha256:c518e84bb59c2baae725accd355c8dc517b4a3ed8db88b4bc93c78dae2974bf2", size = 159144 }, - { url = "https://files.pythonhosted.org/packages/56/27/96a5cd2626d11c8280656c6c71d8ab50fe006490ef9971ccd154e0c42cd2/websockets-13.1-py3-none-any.whl", hash = "sha256:a9a396a6ad26130cdae92ae10c36af09d9bfe6cafe69670fd3b6da9b07b4044f", size = 152134 }, -] - -[[package]] -name = "yarl" -version = "1.17.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "multidict" }, - { name = "propcache" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/54/9c/9c0a9bfa683fc1be7fdcd9687635151544d992cccd48892dc5e0a5885a29/yarl-1.17.1.tar.gz", hash = "sha256:067a63fcfda82da6b198fa73079b1ca40b7c9b7994995b6ee38acda728b64d47", size = 178163 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/0f/ce6a2c8aab9946446fb27f1e28f0fd89ce84ae913ab18a92d18078a1c7ed/yarl-1.17.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:cbad927ea8ed814622305d842c93412cb47bd39a496ed0f96bfd42b922b4a217", size = 140727 }, - { url = "https://files.pythonhosted.org/packages/9d/df/204f7a502bdc3973cd9fc29e7dfad18ae48b3acafdaaf1ae07c0f41025aa/yarl-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fca4b4307ebe9c3ec77a084da3a9d1999d164693d16492ca2b64594340999988", size = 93560 }, - { url = "https://files.pythonhosted.org/packages/a2/e1/f4d522ae0560c91a4ea31113a50f00f85083be885e1092fc6e74eb43cb1d/yarl-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ff5c6771c7e3511a06555afa317879b7db8d640137ba55d6ab0d0c50425cab75", size = 91497 }, - { url = "https://files.pythonhosted.org/packages/f1/82/783d97bf4a226f1a2e59b1966f2752244c2bf4dc89bc36f61d597b8e34e5/yarl-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b29beab10211a746f9846baa39275e80034e065460d99eb51e45c9a9495bcca", size = 339446 }, - { url = "https://files.pythonhosted.org/packages/e5/ff/615600647048d81289c80907165de713fbc566d1e024789863a2f6563ba3/yarl-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a52a1ffdd824fb1835272e125385c32fd8b17fbdefeedcb4d543cc23b332d74", size = 354616 }, - { url = "https://files.pythonhosted.org/packages/a5/04/bfb7adb452bd19dfe0c35354ffce8ebc3086e028e5f8270e409d17da5466/yarl-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58c8e9620eb82a189c6c40cb6b59b4e35b2ee68b1f2afa6597732a2b467d7e8f", size = 351801 }, - { url = "https://files.pythonhosted.org/packages/10/e0/efe21edacdc4a638ce911f8cabf1c77cac3f60e9819ba7d891b9ceb6e1d4/yarl-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d216e5d9b8749563c7f2c6f7a0831057ec844c68b4c11cb10fc62d4fd373c26d", size = 343381 }, - { url = "https://files.pythonhosted.org/packages/63/f9/7bc7e69857d6fc3920ecd173592f921d5701f4a0dd3f2ae293b386cfa3bf/yarl-1.17.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:881764d610e3269964fc4bb3c19bb6fce55422828e152b885609ec176b41cf11", size = 337093 }, - { url = "https://files.pythonhosted.org/packages/93/52/99da61947466275ff17d7bc04b0ac31dfb7ec699bd8d8985dffc34c3a913/yarl-1.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8c79e9d7e3d8a32d4824250a9c6401194fb4c2ad9a0cec8f6a96e09a582c2cc0", size = 346619 }, - { url = "https://files.pythonhosted.org/packages/91/8a/8aaad86a35a16e485ba0e5de0d2ae55bf8dd0c9f1cccac12be4c91366b1d/yarl-1.17.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:299f11b44d8d3a588234adbe01112126010bd96d9139c3ba7b3badd9829261c3", size = 344347 }, - { url = "https://files.pythonhosted.org/packages/af/b6/97f29f626b4a1768ffc4b9b489533612cfcb8905c90f745aade7b2eaf75e/yarl-1.17.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:cc7d768260f4ba4ea01741c1b5fe3d3a6c70eb91c87f4c8761bbcce5181beafe", size = 350316 }, - { url = "https://files.pythonhosted.org/packages/d7/98/8e0e8b812479569bdc34d66dd3e2471176ca33be4ff5c272a01333c4b269/yarl-1.17.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:de599af166970d6a61accde358ec9ded821234cbbc8c6413acfec06056b8e860", size = 361336 }, - { url = "https://files.pythonhosted.org/packages/9e/d3/d1507efa0a85c25285f8eb51df9afa1ba1b6e446dda781d074d775b6a9af/yarl-1.17.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2b24ec55fad43e476905eceaf14f41f6478780b870eda5d08b4d6de9a60b65b4", size = 365350 }, - { url = "https://files.pythonhosted.org/packages/22/ba/ee7f1830449c96bae6f33210b7d89e8aaf3079fbdaf78ac398e50a9da404/yarl-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9fb815155aac6bfa8d86184079652c9715c812d506b22cfa369196ef4e99d1b4", size = 357689 }, - { url = "https://files.pythonhosted.org/packages/a0/85/321c563dc5afe1661108831b965c512d185c61785400f5606006507d2e18/yarl-1.17.1-cp311-cp311-win32.whl", hash = "sha256:7615058aabad54416ddac99ade09a5510cf77039a3b903e94e8922f25ed203d7", size = 83635 }, - { url = "https://files.pythonhosted.org/packages/bc/da/543a32c00860588ff1235315b68f858cea30769099c32cd22b7bb266411b/yarl-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:14bc88baa44e1f84164a392827b5defb4fa8e56b93fecac3d15315e7c8e5d8b3", size = 90218 }, - { url = "https://files.pythonhosted.org/packages/5d/af/e25615c7920396219b943b9ff8b34636ae3e1ad30777649371317d7f05f8/yarl-1.17.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:327828786da2006085a4d1feb2594de6f6d26f8af48b81eb1ae950c788d97f61", size = 141839 }, - { url = "https://files.pythonhosted.org/packages/83/5e/363d9de3495c7c66592523f05d21576a811015579e0c87dd38c7b5788afd/yarl-1.17.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:cc353841428d56b683a123a813e6a686e07026d6b1c5757970a877195f880c2d", size = 94125 }, - { url = "https://files.pythonhosted.org/packages/e3/a2/b65447626227ebe36f18f63ac551790068bf42c69bb22dfa3ae986170728/yarl-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c73df5b6e8fabe2ddb74876fb82d9dd44cbace0ca12e8861ce9155ad3c886139", size = 92048 }, - { url = "https://files.pythonhosted.org/packages/a1/f5/2ef86458446f85cde10582054fd5113495ef8ce8477da35aaaf26d2970ef/yarl-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bdff5e0995522706c53078f531fb586f56de9c4c81c243865dd5c66c132c3b5", size = 331472 }, - { url = "https://files.pythonhosted.org/packages/f3/6b/1ba79758ba352cdf2ad4c20cab1b982dd369aa595bb0d7601fc89bf82bee/yarl-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:06157fb3c58f2736a5e47c8fcbe1afc8b5de6fb28b14d25574af9e62150fcaac", size = 341260 }, - { url = "https://files.pythonhosted.org/packages/2d/41/4e07c2afca3f9ed3da5b0e38d43d0280d9b624a3d5c478c425e5ce17775c/yarl-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1654ec814b18be1af2c857aa9000de7a601400bd4c9ca24629b18486c2e35463", size = 340882 }, - { url = "https://files.pythonhosted.org/packages/c3/c0/cd8e94618983c1b811af082e1a7ad7764edb3a6af2bc6b468e0e686238ba/yarl-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f6595c852ca544aaeeb32d357e62c9c780eac69dcd34e40cae7b55bc4fb1147", size = 336648 }, - { url = "https://files.pythonhosted.org/packages/ac/fc/73ec4340d391ffbb8f34eb4c55429784ec9f5bd37973ce86d52d67135418/yarl-1.17.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:459e81c2fb920b5f5df744262d1498ec2c8081acdcfe18181da44c50f51312f7", size = 325019 }, - { url = "https://files.pythonhosted.org/packages/57/48/da3ebf418fc239d0a156b3bdec6b17a5446f8d2dea752299c6e47b143a85/yarl-1.17.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7e48cdb8226644e2fbd0bdb0a0f87906a3db07087f4de77a1b1b1ccfd9e93685", size = 342841 }, - { url = "https://files.pythonhosted.org/packages/5d/79/107272745a470a8167924e353a5312eb52b5a9bb58e22686adc46c94f7ec/yarl-1.17.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d9b6b28a57feb51605d6ae5e61a9044a31742db557a3b851a74c13bc61de5172", size = 341433 }, - { url = "https://files.pythonhosted.org/packages/30/9c/6459668b3b8dcc11cd061fc53e12737e740fb6b1575b49c84cbffb387b3a/yarl-1.17.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e594b22688d5747b06e957f1ef822060cb5cb35b493066e33ceac0cf882188b7", size = 344927 }, - { url = "https://files.pythonhosted.org/packages/c5/0b/93a17ed733aca8164fc3a01cb7d47b3f08854ce4f957cce67a6afdb388a0/yarl-1.17.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5f236cb5999ccd23a0ab1bd219cfe0ee3e1c1b65aaf6dd3320e972f7ec3a39da", size = 355732 }, - { url = "https://files.pythonhosted.org/packages/9a/63/ead2ed6aec3c59397e135cadc66572330325a0c24cd353cd5c94f5e63463/yarl-1.17.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a2a64e62c7a0edd07c1c917b0586655f3362d2c2d37d474db1a509efb96fea1c", size = 362123 }, - { url = "https://files.pythonhosted.org/packages/89/bf/f6b75b4c2fcf0e7bb56edc0ed74e33f37fac45dc40e5a52a3be66b02587a/yarl-1.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d0eea830b591dbc68e030c86a9569826145df485b2b4554874b07fea1275a199", size = 356355 }, - { url = "https://files.pythonhosted.org/packages/45/1f/50a0257cd07eef65c8c65ad6a21f5fb230012d659e021aeb6ac8a7897bf6/yarl-1.17.1-cp312-cp312-win32.whl", hash = "sha256:46ddf6e0b975cd680eb83318aa1d321cb2bf8d288d50f1754526230fcf59ba96", size = 83279 }, - { url = "https://files.pythonhosted.org/packages/bc/82/fafb2c1268d63d54ec08b3a254fbe51f4ef098211501df646026717abee3/yarl-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:117ed8b3732528a1e41af3aa6d4e08483c2f0f2e3d3d7dca7cf538b3516d93df", size = 89590 }, - { url = "https://files.pythonhosted.org/packages/06/1e/5a93e3743c20eefbc68bd89334d9c9f04f3f2334380f7bbf5e950f29511b/yarl-1.17.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:5d1d42556b063d579cae59e37a38c61f4402b47d70c29f0ef15cee1acaa64488", size = 139974 }, - { url = "https://files.pythonhosted.org/packages/a1/be/4e0f6919013c7c5eaea5c31811c551ccd599d2fc80aa3dd6962f1bbdcddd/yarl-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c0167540094838ee9093ef6cc2c69d0074bbf84a432b4995835e8e5a0d984374", size = 93364 }, - { url = "https://files.pythonhosted.org/packages/73/f0/650f994bc491d0cb85df8bb45392780b90eab1e175f103a5edc61445ff67/yarl-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2f0a6423295a0d282d00e8701fe763eeefba8037e984ad5de44aa349002562ac", size = 91177 }, - { url = "https://files.pythonhosted.org/packages/f3/e8/9945ed555d14b43ede3ae8b1bd73e31068a694cad2b9d3cad0a28486c2eb/yarl-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5b078134f48552c4d9527db2f7da0b5359abd49393cdf9794017baec7506170", size = 333086 }, - { url = "https://files.pythonhosted.org/packages/a6/c0/7d167e48e14d26639ca066825af8da7df1d2fcdba827e3fd6341aaf22a3b/yarl-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d401f07261dc5aa36c2e4efc308548f6ae943bfff20fcadb0a07517a26b196d8", size = 343661 }, - { url = "https://files.pythonhosted.org/packages/fa/81/80a266517531d4e3553aecd141800dbf48d02e23ebd52909e63598a80134/yarl-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5f1ac7359e17efe0b6e5fec21de34145caef22b260e978336f325d5c84e6938", size = 345196 }, - { url = "https://files.pythonhosted.org/packages/b0/77/6adc482ba7f2dc6c0d9b3b492e7cd100edfac4cfc3849c7ffa26fd7beb1a/yarl-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f63d176a81555984e91f2c84c2a574a61cab7111cc907e176f0f01538e9ff6e", size = 338743 }, - { url = "https://files.pythonhosted.org/packages/6d/cc/f0c4c0b92ff3ada517ffde2b127406c001504b225692216d969879ada89a/yarl-1.17.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e275792097c9f7e80741c36de3b61917aebecc08a67ae62899b074566ff8556", size = 326719 }, - { url = "https://files.pythonhosted.org/packages/18/3b/7bfc80d3376b5fa162189993a87a5a6a58057f88315bd0ea00610055b57a/yarl-1.17.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:81713b70bea5c1386dc2f32a8f0dab4148a2928c7495c808c541ee0aae614d67", size = 345826 }, - { url = "https://files.pythonhosted.org/packages/2e/66/cf0b0338107a5c370205c1a572432af08f36ca12ecce127f5b558398b4fd/yarl-1.17.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:aa46dce75078fceaf7cecac5817422febb4355fbdda440db55206e3bd288cfb8", size = 340335 }, - { url = "https://files.pythonhosted.org/packages/2f/52/b084b0eec0fd4d2490e1d33ace3320fad704c5f1f3deaa709f929d2d87fc/yarl-1.17.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1ce36ded585f45b1e9bb36d0ae94765c6608b43bd2e7f5f88079f7a85c61a4d3", size = 345301 }, - { url = "https://files.pythonhosted.org/packages/ef/38/9e2036d948efd3bafcdb4976cb212166fded76615f0dfc6c1492c4ce4784/yarl-1.17.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:2d374d70fdc36f5863b84e54775452f68639bc862918602d028f89310a034ab0", size = 354205 }, - { url = "https://files.pythonhosted.org/packages/81/c1/13dfe1e70b86811733316221c696580725ceb1c46d4e4db852807e134310/yarl-1.17.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2d9f0606baaec5dd54cb99667fcf85183a7477f3766fbddbe3f385e7fc253299", size = 360501 }, - { url = "https://files.pythonhosted.org/packages/91/87/756e05c74cd8bf9e71537df4a2cae7e8211a9ebe0d2350a3e26949e1e41c/yarl-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b0341e6d9a0c0e3cdc65857ef518bb05b410dbd70d749a0d33ac0f39e81a4258", size = 359452 }, - { url = "https://files.pythonhosted.org/packages/06/b2/b2bb09c1e6d59e1c9b1b36a86caa473e22c3dbf26d1032c030e9bfb554dc/yarl-1.17.1-cp313-cp313-win32.whl", hash = "sha256:2e7ba4c9377e48fb7b20dedbd473cbcbc13e72e1826917c185157a137dac9df2", size = 308904 }, - { url = "https://files.pythonhosted.org/packages/f3/27/f084d9a5668853c1f3b246620269b14ee871ef3c3cc4f3a1dd53645b68ec/yarl-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:949681f68e0e3c25377462be4b658500e85ca24323d9619fdc41f68d46a1ffda", size = 314637 }, - { url = "https://files.pythonhosted.org/packages/52/ad/1fe7ff5f3e8869d4c5070f47b96bac2b4d15e67c100a8278d8e7876329fc/yarl-1.17.1-py3-none-any.whl", hash = "sha256:f1790a4b1e8e8e028c391175433b9c8122c39b46e1663228158e61e6f915bf06", size = 44352 }, -] diff --git a/libraries/python/context/README.md b/libraries/python/context/README.md index 66f5ca23..f5e6580a 100644 --- a/libraries/python/context/README.md +++ b/libraries/python/context/README.md @@ -3,7 +3,6 @@ This library is shared among several different Make:Exploration projects including: - [Skill Library](../skills/skill-library/README.md) -- [Chat Driver](../chat-driver/README.md) The [Context](./context/context.py) class in this library is designed to be instantiated once and passed to all relevant parts of a system. diff --git a/libraries/python/chat-driver/README.md b/libraries/python/openai-client/openai_client/chat_driver/README.md similarity index 100% rename from libraries/python/chat-driver/README.md rename to libraries/python/openai-client/openai_client/chat_driver/README.md diff --git a/libraries/python/openai-client/openai_client/chat_driver/__init__.py b/libraries/python/openai-client/openai_client/chat_driver/__init__.py new file mode 100644 index 00000000..71ab1870 --- /dev/null +++ b/libraries/python/openai-client/openai_client/chat_driver/__init__.py @@ -0,0 +1,19 @@ +from .chat_driver import ( + ChatDriver, + ChatDriverConfig, +) +from .message_history_providers import ( + InMemoryMessageHistoryProvider, + LocalMessageHistoryProvider, + LocalMessageHistoryProviderConfig, + MessageHistoryProviderProtocol, +) + +__all__ = [ + "ChatDriver", + "ChatDriverConfig", + "InMemoryMessageHistoryProvider", + "LocalMessageHistoryProvider", + "LocalMessageHistoryProviderConfig", + "MessageHistoryProviderProtocol", +] diff --git a/libraries/python/chat-driver/chat_driver/chat_driver.py b/libraries/python/openai-client/openai_client/chat_driver/chat_driver.py similarity index 93% rename from libraries/python/chat-driver/chat_driver/chat_driver.py rename to libraries/python/openai-client/openai_client/chat_driver/chat_driver.py index bf93803c..22119ffc 100644 --- a/libraries/python/chat-driver/chat_driver/chat_driver.py +++ b/libraries/python/openai-client/openai_client/chat_driver/chat_driver.py @@ -9,14 +9,14 @@ ChatCompletionUserMessageParam, ) from openai.types.chat.completion_create_params import ResponseFormat +from pydantic import BaseModel + from openai_client.completion import TEXT_RESPONSE_FORMAT, message_content_from_completion from openai_client.errors import CompletionError from openai_client.messages import MessageFormatter, format_with_dict from openai_client.tools import ToolFunction, ToolFunctions, complete_with_tool_calls, function_list_to_tool_choice -from pydantic import BaseModel -from .in_memory_message_history_provider import InMemoryMessageHistoryProvider -from .message_history_provider import MessageHistoryProviderProtocol +from .message_history_providers import InMemoryMessageHistoryProvider, MessageHistoryProviderProtocol @dataclass @@ -34,19 +34,20 @@ class ChatDriver: """ A ChatDriver is a class that manages a conversation with a user. It provides methods to add messages to the conversation, and to generate responses to - user messages. The ChatDriver uses the OpenAI API to generate responses, and - can call functions registered with the ChatDriver to generate parts of the - response. The ChatDriver also provides a way to register commands that can - be called by the user to execute functions directly. + user messages. The ChatDriver uses the OpenAI Chat Completion API to + generate responses, and can call functions registered with the ChatDriver to + generate parts of the response. The ChatDriver also provides a way to + register commands that can be called by the user to execute functions + directly. Instructions are messages that are sent to the OpenAI model before any other messages. These instructions are used to guide the model in generating a response. The ChatDriver allows you to set instructions that can be formatted with variables. - If you want to just generate responses using the OpenAI API, you should use - the client directly (but we do have some helpers in the openai_helpers - module) to make this simpler. + If you want to just generate responses using the OpenAI Chat Completion API, + you should use the client directly (but we do have some helpers in the + openai_helpers module) to make this simpler. """ def __init__(self, config: ChatDriverConfig) -> None: diff --git a/libraries/python/openai-client/openai_client/chat_driver/message_history_providers/__init__.py b/libraries/python/openai-client/openai_client/chat_driver/message_history_providers/__init__.py new file mode 100644 index 00000000..e67e4661 --- /dev/null +++ b/libraries/python/openai-client/openai_client/chat_driver/message_history_providers/__init__.py @@ -0,0 +1,13 @@ +from .in_memory_message_history_provider import InMemoryMessageHistoryProvider +from .local_message_history_provider import ( + LocalMessageHistoryProvider, + LocalMessageHistoryProviderConfig, +) +from .message_history_provider import MessageHistoryProviderProtocol + +__all__ = [ + "LocalMessageHistoryProvider", + "LocalMessageHistoryProviderConfig", + "InMemoryMessageHistoryProvider", + "MessageHistoryProviderProtocol", +] diff --git a/libraries/python/chat-driver/chat_driver/in_memory_message_history_provider.py b/libraries/python/openai-client/openai_client/chat_driver/message_history_providers/in_memory_message_history_provider.py similarity index 100% rename from libraries/python/chat-driver/chat_driver/in_memory_message_history_provider.py rename to libraries/python/openai-client/openai_client/chat_driver/message_history_providers/in_memory_message_history_provider.py diff --git a/libraries/python/chat-driver/chat_driver/local_message_history_provider.py b/libraries/python/openai-client/openai_client/chat_driver/message_history_providers/local_message_history_provider.py similarity index 100% rename from libraries/python/chat-driver/chat_driver/local_message_history_provider.py rename to libraries/python/openai-client/openai_client/chat_driver/message_history_providers/local_message_history_provider.py diff --git a/libraries/python/chat-driver/chat_driver/message_history_provider.py b/libraries/python/openai-client/openai_client/chat_driver/message_history_providers/message_history_provider.py similarity index 100% rename from libraries/python/chat-driver/chat_driver/message_history_provider.py rename to libraries/python/openai-client/openai_client/chat_driver/message_history_providers/message_history_provider.py diff --git a/libraries/python/chat-driver/tests/formatted_instructions_test.py b/libraries/python/openai-client/openai_client/chat_driver/message_history_providers/tests/formatted_instructions_test.py similarity index 95% rename from libraries/python/chat-driver/tests/formatted_instructions_test.py rename to libraries/python/openai-client/openai_client/chat_driver/message_history_providers/tests/formatted_instructions_test.py index c79ef24c..06818dff 100644 --- a/libraries/python/chat-driver/tests/formatted_instructions_test.py +++ b/libraries/python/openai-client/openai_client/chat_driver/message_history_providers/tests/formatted_instructions_test.py @@ -1,5 +1,5 @@ -from chat_driver.chat_driver import ChatDriver -from openai_client.messages import format_with_dict +from openai_client.chat_driver import ChatDriver +from openai_client.messages import format_with_liquid def test_formatted_instructions() -> None: @@ -34,7 +34,7 @@ def test_formatted_instructions() -> None: "user_feedback": user_feedback, "chat_history": chat_history, }, - formatter=format_with_dict, + formatter=format_with_liquid, ) expected = [ diff --git a/libraries/python/openai-client/openai_client/messages.py b/libraries/python/openai-client/openai_client/messages.py index 37dd4547..15437f03 100644 --- a/libraries/python/openai-client/openai_client/messages.py +++ b/libraries/python/openai-client/openai_client/messages.py @@ -83,29 +83,29 @@ def apply_truncation_to_dict(dict_: dict, maximum_length: int, filler_text: str) MessageFormatter = Callable[[str, dict[str, Any]], str] -def format_with_dict(value: str, vars: dict[str, Any]) -> str: +def format_with_dict(template: str, vars: dict[str, Any]) -> str: """ Format a string with the given variables using the Python format method. """ - if value and vars: - for key, value in vars.items(): - try: - value = value.format(**{key: value}) - except KeyError: - pass - return value + parsed = template + for key, value in vars.items(): + try: + parsed = template.format(**{key: value}) + except KeyError: + pass + return parsed -def format_with_liquid(value: str, vars: dict[str, Any]) -> str: +def format_with_liquid(template: str, vars: dict[str, Any]) -> str: """ Format a string with the given variables using the Liquid template engine. """ - out = value - if not value: - return value - template = Template(value) - out = template.render(**vars) - return out + parsed = template + if not vars: + return template + liquid_template = Template(template) + parsed = liquid_template.render(**vars) + return parsed def create_system_message( diff --git a/libraries/python/openai-client/pyproject.toml b/libraries/python/openai-client/pyproject.toml index 65ebde11..eb7e136c 100644 --- a/libraries/python/openai-client/pyproject.toml +++ b/libraries/python/openai-client/pyproject.toml @@ -9,6 +9,7 @@ dependencies = [ "azure-ai-contentsafety>=1.0.0", "azure-core[aio]>=1.30.0", "azure-identity>=1.17.1", + "events>=0.1.0", "openai>=1.3.9", "pillow>=11.0.0", "python-liquid>=1.12.1", @@ -22,6 +23,7 @@ dev-dependencies = ["pytest>=8.3.3"] [tool.uv.sources] semantic-workbench-assistant = { path = "../semantic-workbench-assistant", editable = true } +events = { path = "../events", editable = true } [build-system] requires = ["hatchling"] diff --git a/libraries/python/openai-client/tests/test_formatted_messages.py b/libraries/python/openai-client/tests/test_formatted_messages.py new file mode 100644 index 00000000..aa83ceca --- /dev/null +++ b/libraries/python/openai-client/tests/test_formatted_messages.py @@ -0,0 +1,48 @@ +from textwrap import dedent + +from openai_client.messages import format_with_liquid + + +def test_formatted_messages() -> None: + # Set instructions. + instructions = [ + dedent(""" + Generate an outline for the document, including title. The outline should include the key points that will be covered in the document. Consider the attachments, the rationale for why they were uploaded, and the conversation that has taken place. The outline should be a hierarchical structure with multiple levels of detail, and it should be clear and easy to understand. The outline should be generated in a way that is consistent with the document that will be generated from it. + """).strip(), + "{{chat_history}}", + "{% for attachment in attachments %}{{attachment.filename}}{{attachment.content}}{% endfor %}", + "{{outline_versions.last}}", + "{{user_feedback}}", + ] + + # Set vars. + attachments = [ + {"filename": "filename1", "content": "content1"}, + {"filename": "filename2", "content": "content2"}, + ] + outline_versions = ["outline1", "outline2"] + user_feedback = "feedback" + chat_history = "history" + + actual = [ + format_with_liquid( + template=instruction, + vars={ + "attachments": attachments, + "outline_versions": outline_versions, + "user_feedback": user_feedback, + "chat_history": chat_history, + }, + ) + for instruction in instructions + ] + + expected = [ + "Generate an outline for the document, including title. The outline should include the key points that will be covered in the document. Consider the attachments, the rationale for why they were uploaded, and the conversation that has taken place. The outline should be a hierarchical structure with multiple levels of detail, and it should be clear and easy to understand. The outline should be generated in a way that is consistent with the document that will be generated from it.", + "history", + "filename1content1filename2content2", + "outline2", + "feedback", + ] + + assert actual == expected diff --git a/libraries/python/openai-client/uv.lock b/libraries/python/openai-client/uv.lock index bb3f757a..6418aff3 100644 --- a/libraries/python/openai-client/uv.lock +++ b/libraries/python/openai-client/uv.lock @@ -370,6 +370,17 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521 }, ] +[[package]] +name = "events" +version = "0.1.0" +source = { editable = "../events" } +dependencies = [ + { name = "pydantic" }, +] + +[package.metadata] +requires-dist = [{ name = "pydantic", specifier = ">=2.6.1" }] + [[package]] name = "fastapi" version = "0.115.0" @@ -751,6 +762,7 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, + { name = "events" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -768,6 +780,7 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "events", editable = "../events" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, diff --git a/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb b/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb index 61a62d3f..569df7f0 100644 --- a/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb +++ b/libraries/python/skills/notebooks/notebooks/chat_driver.ipynb @@ -20,7 +20,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -141,7 +141,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": {}, "outputs": [ { @@ -149,14 +149,14 @@ "output_type": "stream", "text": [ "{\n", - " \"id\": \"chatcmpl-ARRAZhqMa0AhQEzs0YAstZfa5CMm8\",\n", + " \"id\": \"chatcmpl-ASsXCOPTQYPT3ZLEzdoXzYpfPDLIi\",\n", " \"choices\": [\n", " {\n", " \"finish_reason\": \"stop\",\n", " \"index\": 0,\n", " \"logprobs\": null,\n", " \"message\": {\n", - " \"content\": \"This is a test. How can I assist you further?\",\n", + " \"content\": \"This is a test.\",\n", " \"refusal\": null,\n", " \"role\": \"assistant\",\n", " \"function_call\": null,\n", @@ -164,15 +164,15 @@ " }\n", " }\n", " ],\n", - " \"created\": 1731102659,\n", + " \"created\": 1731446178,\n", " \"model\": \"gpt-4o-2024-08-06\",\n", " \"object\": \"chat.completion\",\n", " \"service_tier\": null,\n", " \"system_fingerprint\": \"fp_d54531d9eb\",\n", " \"usage\": {\n", - " \"completion_tokens\": 12,\n", + " \"completion_tokens\": 5,\n", " \"prompt_tokens\": 12,\n", - " \"total_tokens\": 24,\n", + " \"total_tokens\": 17,\n", " \"completion_tokens_details\": null,\n", " \"prompt_tokens_details\": null\n", " }\n", @@ -202,14 +202,14 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "ChatCompletion(id='chatcmpl-AQgaCid05i8dGgUHijQsvPAsMYbv4', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='This is a test.', refusal=None, role='assistant', function_call=None, tool_calls=None))], created=1730923580, model='gpt-4o-2024-08-06', object='chat.completion', service_tier=None, system_fingerprint='fp_d54531d9eb', usage=CompletionUsage(completion_tokens=5, prompt_tokens=12, total_tokens=17, completion_tokens_details=None, prompt_tokens_details=None))\n" + "ChatCompletion(id='chatcmpl-ASsXGnCRUzKrj4CWU1Zbc1ZXaTRqm', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='This is a test.', refusal=None, role='assistant', function_call=None, tool_calls=None))], created=1731446182, model='gpt-4o-2024-08-06', object='chat.completion', service_tier=None, system_fingerprint='fp_d54531d9eb', usage=CompletionUsage(completion_tokens=5, prompt_tokens=12, total_tokens=17, completion_tokens_details=None, prompt_tokens_details=None))\n" ] } ], @@ -283,32 +283,28 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "The future of AI is both exciting and complex, with its trajectory shaped by advances in technology, ethical considerations, and societal needs. As we look ahead, several key themes emerge:\n", - "\n", - "1. **Integration and Personalization**: AI will become increasingly integrated into our daily lives, driving personalized experiences. From healthcare to education, AI systems will tailor recommendations and interventions to individual needs, optimizing outcomes across various sectors.\n", - "\n", - "2. **AI in Healthcare**: We can expect AI to revolutionize the healthcare industry by enhancing diagnostic accuracy, streamlining administrative processes, and developing personalized medicine. AI-driven tools could predict diseases, recommend treatments, and even aid in surgical procedures, ultimately improving patient care and reducing costs.\n", + "The future of AI is vast and holds immense potential to transform nearly every aspect of our lives. As we look forward, here are several key domains where AI is likely to make significant impacts:\n", "\n", - "3. **Autonomous Systems**: Autonomous vehicles, drones, and robotic systems will become more prevalent, transforming industries like transportation, logistics, and manufacturing. These systems will improve efficiency and safety while also creating new business models and opportunities.\n", + "1. **Healthcare**: AI will continue to revolutionize healthcare through personalized medicine, improved diagnostic capabilities, and efficient drug discovery. Machine learning algorithms can analyze patient data to suggest tailored treatment plans, detect diseases earlier, and even manage administrative tasks.\n", "\n", - "4. **Ethical and Responsible AI**: As AI systems become more autonomous, the demand for ethical AI frameworks will increase. Ensuring transparency, fairness, accountability, and privacy will be crucial to maintaining public trust. Developing AI systems that align with human values and societal norms will be an ongoing challenge.\n", + "2. **Transportation**: Autonomous vehicles and AI-driven logistics will reshape transportation infrastructure and mobility. This includes not only self-driving cars but also the optimization of public transport systems and delivery services.\n", "\n", - "5. **AI and the Workforce**: While AI will automate certain tasks, it will also create new job opportunities and demand an upskilled workforce. It is important to focus on reskilling and education initiatives to prepare the workforce for an AI-augmented future.\n", + "3. **Environment**: AI will play a crucial role in addressing environmental challenges. From optimizing energy consumption to predicting and mitigating natural disasters, AI can help manage resources more sustainably and minimize human impact on the planet.\n", "\n", - "6. **AI in Climate and Sustainability**: AI will play a significant role in addressing climate change and promoting sustainability. From optimizing energy usage and improving agricultural practices to predicting environmental changes, AI could be a critical tool in creating a more sustainable future.\n", + "4. **Workplace Automation**: While AI will automate routine tasks, it will also create opportunities for innovation and new job categories. We need to focus on reskilling and upskilling the workforce to harness AI as a tool for enhancing productivity and creativity.\n", "\n", - "7. **AI in Creativity and Arts**: AI is increasingly being used in creative fields, such as music, art, and literature. While it can augment human creativity by offering new tools and perspectives, there will be ongoing discussions about the nature of creativity and authorship.\n", + "5. **Ethics and Governance**: As AI systems become more integrated into our lives, ethical considerations and robust governance frameworks will become increasingly important. We must ensure that AI is developed and deployed responsibly, with fairness, transparency, and accountability at the forefront.\n", "\n", - "8. **AI Governance and Policy**: With AI's growing influence, policy and regulation will need to keep pace to address issues such as data ownership, algorithmic bias, and national security. International collaboration may be necessary to create coherent frameworks addressing these challenges.\n", + "6. **Education**: AI-powered tools can provide personalized learning experiences, helping educators better meet the diverse needs of students and enabling lifelong learning.\n", "\n", - "In summary, AI has the potential to greatly benefit society, but its development requires thoughtful consideration of ethical, social, and economic impacts. As we move forward, collaboration among technologists, policymakers, and the public will be essential to harness AI for the greater good.\n" + "Ultimately, the future of AI depends on how we choose to guide its development. If approached thoughtfully and inclusively, it has the potential to enhance human capabilities, address global challenges, and improve quality of life across the globe. It's crucial that as we advance these technologies, we remain vigilant about their societal implications, striving for a future that benefits all.\n" ] } ], @@ -386,7 +382,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -394,8 +390,8 @@ "output_type": "stream", "text": [ "{\n", - " \"thoughts\": \"AI is rapidly evolving and has the potential to transform virtually every industry. With advancements in machine learning, natural language processing, and robotics, AI will continue to play a crucial role in automating routine tasks and providing intelligent insights.\",\n", - " \"answer\": \"The future of AI involves deeper integration into everyday life and industry. We will likely see AI systems becoming more autonomous, sophisticated, and seamlessly integrated into systems like healthcare, transportation, and personalized services. AI's future encompasses not only technological advancements but also ethical considerations and ensuring beneficial societal impacts.\"\n", + " \"thoughts\": \"The future of AI is expected to be dynamic and transformative, impacting various sectors from healthcare to education. There is potential for AI to enhance productivity, improve decision-making, and create more personalized experiences.\",\n", + " \"answer\": \"AI is likely to become more integrated into everyday life, leading to smarter cities, more efficient industries, and advances in fields such as medicine and autonomous systems. Ethical considerations will be crucial as AI becomes more powerful, and there will be ongoing discussions about privacy, bias, and the job market. Overall, the future of AI promises significant benefits if its development is guided responsibly.\"\n", "}\n" ] } @@ -448,7 +444,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -456,8 +452,8 @@ "output_type": "stream", "text": [ "{\n", - " \"thoughts\": \"The future of AI is a convergence of technological advancement, ethical consideration, and societal adaptation. Its trajectory will be shaped by how well we manage its integration into daily life, ensuring it remains a tool to augment human capabilities rather than replace them entirely.\",\n", - " \"answer\": \"The future of AI is incredibly promising and multifaceted, with potential developments across various domains. In healthcare, AI may revolutionize diagnostics and personalized medicine, allowing for earlier detection of diseases and tailored treatment plans. In the realm of transportation, we can expect more sophisticated autonomous vehicles, improving safety and efficiency on our roads. Moreover, AI could enhance environmental monitoring and response, aiding in the fight against climate change by optimizing energy use and predicting environmental changes.\\n\\nHowever, as we look to this future, it is crucial to address the ethical implications of AI. This includes ensuring data privacy, reducing algorithmic bias, and contemplating the social impacts of automation on employment. Governance and regulation will play vital roles in guiding AI development to benefit society as a whole, promoting fairness, transparency, and accountability.\\n\\nUltimately, the future of AI will be defined by how humans choose to steer its development, balancing innovation with the responsibilities it entails. By fostering collaboration among technologists, ethicists, lawmakers, and the general public, we can harness AI's potential to create a more informed, just, and equitable world.\"\n", + " \"thoughts\": \"AI is already having a profound impact across various sectors, and its influence will only grow in the future as technologies continue to advance. We are likely to see significant developments in AI applications, enhanced human-AI collaboration, and ethical considerations around the technology's usage.\",\n", + " \"answer\": \"The future of AI holds tremendous potential to revolutionize how we live, work, and interact. In the coming years, we can expect AI to become increasingly integrated into our daily lives through smarter personal assistants, more efficient business processes, and advancements in healthcare, transportation, and communication technologies. AI will enable more personalized and anticipatory services, where systems proactively assist users based on their preferences and behaviors.\\n\\nFurthermore, AI will drive innovation by augmenting human capabilities, allowing us to tackle complex problems with greater efficiency. This collaboration between humans and machines could lead to breakthroughs in fields like medicine, environmental science, and education.\\n\\nHowever, with these opportunities come challenges. Ethical considerations, such as bias, privacy concerns, and the impact on employment, must be addressed. Developers and policymakers will need to work together to create guidelines and standards that ensure AI technologies are used responsibly and inclusively.\\n\\nAdditionally, explainability and transparency in AI systems will become increasingly important, as stakeholders will demand to understand how these technologies make decisions that affect them.\\n\\nOverall, the future of AI is bright and full of potential, but it requires a careful balancing act to ensure it benefits society as a whole.\"\n", "}\n" ] } @@ -531,7 +527,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -606,7 +602,7 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 8, "metadata": {}, "outputs": [ { @@ -614,8 +610,8 @@ "output_type": "stream", "text": [ "{\n", - " \"thoughts\": \"The weather is typically sunny in Beverly Hills, especially considering the geographic location known for its warm climate.\",\n", - " \"answer\": \"The weather in the 90210 area (Beverly Hills) is currently sunny with a temperature of 25°C (77°F). There is minimal cloud cover, at 20%.\"\n", + " \"thoughts\": \"I used a function to obtain current weather data for the specified ZIP code, which is 90210 (Beverly Hills, CA). The weather is typically warm and sunny during this season.\",\n", + " \"answer\": \"The current weather in 90210 (Beverly Hills, CA) is sunny with a temperature of 25°C (77°F), and the cloud cover is minimal at 20%. Perfect for outdoor activities!\"\n", "}\n" ] } @@ -701,14 +697,14 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "The result of the fish calculation on the number 53 is: `0b101011111001` in binary representation.\n" + "The fish calculation of 53 results in the binary number `0b101011111001`. If you need any further analysis or conversion, feel free to ask!\n" ] } ], @@ -814,35 +810,31 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "The future of AI is both exciting and complex, with the potential to profoundly transform many aspects of our lives over the coming decades. Let's explore a few key areas where AI is expected to make significant impacts:\n", - "\n", - "1. **Healthcare**: AI has the potential to revolutionize healthcare by improving diagnostics, personalizing treatment plans, and enhancing patient monitoring. Machine learning algorithms can analyze vast amounts of medical data to detect patterns that might be missed by human doctors, leading to earlier and more accurate diagnoses.\n", + "The future of AI is incredibly exciting and holds the potential to fundamentally transform various aspects of our lives, industries, and societies. First and foremost, we're seeing AI become increasingly integrated into our daily routines, from virtual assistants that help manage our schedules to smart home devices that optimize our living environments.\n", "\n", - "2. **Autonomous Systems**: From self-driving cars to drones, autonomous systems powered by AI are likely to become increasingly common. These systems can improve efficiency, safety, and accessibility in transportation and logistics, while also opening up new possibilities in areas like agriculture and disaster response.\n", + "In healthcare, AI will continue to revolutionize the industry with advancements in personalized medicine, predictive analytics, and automated diagnostics, leading to more efficient and accurate treatment options. In areas like finance, AI can enhance decision-making through better risk assessment and fraud detection.\n", "\n", - "3. **Work and Productivity**: AI can automate routine tasks, freeing up humans to focus on more complex and creative work. This has the potential to increase productivity and innovation, but also raises questions about job displacement and the future of work, necessitating thoughtful discussions on workforce retraining and the evolution of job roles.\n", + "The future of AI also includes significant advancements in natural language processing and computer vision, which will drive innovations in autonomous vehicles, intelligent virtual agents, and other fields requiring human-like perception and interaction.\n", "\n", - "4. **Personalization**: AI can enhance consumer experiences by providing personalized recommendations and services, from content and product suggestions to educational platforms tailored to individual learning styles. This can lead to increased satisfaction and efficiency, but also raises issues regarding privacy and data security.\n", + "Moreover, AI will play a crucial role in addressing global challenges such as climate change, by analyzing vast amounts of environmental data to develop more sustainable practices and technologies. In education, AI can offer personalized learning experiences tailored to the needs of each student, enhancing the accessibility and quality of education globally.\n", "\n", - "5. **Scientific Research**: AI is becoming an indispensable tool in scientific research, capable of analyzing complex datasets more quickly and accurately than traditional methods. This can accelerate discoveries in fields such as genomics, climate modeling, and materials science, potentially leading to groundbreaking innovations.\n", + "However, along with these prospects come important ethical considerations surrounding privacy, data security, and algorithmic bias. It is essential for us as a community to ensure that AI is developed and deployed responsibly, with a focus on transparency and inclusivity.\n", "\n", - "6. **Ethics and Fairness**: As AI becomes more integrated into society, it's crucial to address ethical considerations, including biases in AI systems and the impact on privacy and decision-making processes. Developing fair, transparent, and accountable AI systems will be essential for gaining public trust and maximizing benefits.\n", + "Finally, as AI continues to evolve, it could also lead to significant changes in the workforce, reshaping job markets and requiring us to rethink how education and skill development align with future needs.\n", "\n", - "7. **Global Challenges**: AI could play a crucial role in addressing global challenges like climate change, resource management, and sustainable development. By optimizing processes and offering innovative solutions, AI can contribute to making societies more resilient and adaptable.\n", - "\n", - "Overall, the future of AI promises to be a catalyst for growth and change across various domains. However, realizing this potential will require collaborative efforts from researchers, policymakers, businesses, and the public to ensure these technologies are developed and deployed in ways that are ethical and beneficial to all of humanity.\n" + "Ultimately, the future of AI is likely to be characterized by a delicate balance between innovation and ethical stewardship, necessitating collaboration across disciplines, industries, and borders to maximize benefits while minimizing potential risks.\n" ] } ], "source": [ - "from chat_driver import ChatDriver, ChatDriverConfig\n", + "from openai_client.chat_driver import ChatDriver, ChatDriverConfig\n", "\n", "instructions = \"You are a famous computer scientist. You are giving a talk at a conference. You are talking about the future of AI and how it will change the world. You are asked a questions by audience members.\"\n", "\n", @@ -872,7 +864,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 12, "metadata": {}, "outputs": [ { @@ -880,7 +872,7 @@ "output_type": "stream", "text": [ "\n", - "Hello, Paul! How can I assist you today?\n", + "Hello Paul! How can I assist you today?\n", "\n", "Commands:\n", "echo(text: str): Return the text.\n", @@ -895,7 +887,7 @@ "\n", "Echoing: Echo this.\n", "\n", - "The content of \"123.txt\" is: \"The purpose of life is to be happy.\" How else can I help you today?\n", + "The contents of \"123.txt\" are: \"The purpose of life is to be happy.\" How else can I help you?\n", "\n", "{\"description\":\"Sunny\",\"cloud_cover\":0.2,\"temp_c\":25.0,\"temp_f\":77.0}\n" ] @@ -903,8 +895,8 @@ ], "source": [ "from typing import Any, cast\n", - "from chat_driver import ChatDriver, ChatDriverConfig\n", - "from chat_driver import LocalMessageHistoryProvider\n", + "from openai_client.chat_driver import ChatDriver, ChatDriverConfig\n", + "from openai_client.chat_driver import LocalMessageHistoryProvider\n", "from pydantic import BaseModel, Field\n", "from openai_client.tools import ToolFunctions, ToolFunction\n", "\n", @@ -1039,7 +1031,7 @@ } ], "source": [ - "from chat_driver import ChatDriverConfig, ChatDriver\n", + "from openai_client.chat_driver import ChatDriverConfig, ChatDriver\n", "from context import Context\n", "from openai_client.tools import ToolFunction, ToolFunctions\n", "\n", @@ -1112,7 +1104,7 @@ "source": [ "from io import BytesIO\n", "from typing import Any, BinaryIO\n", - "from chat_driver import ChatDriverConfig, ChatDriver, ChatDriverConfig\n", + "from openai_client.chat_driver import ChatDriverConfig, ChatDriver, ChatDriverConfig\n", "from context import Context\n", "from assistant_drive import Drive, DriveConfig, IfDriveFileExistsBehavior \n", "\n", diff --git a/libraries/python/skills/notebooks/notebooks/skills.ipynb b/libraries/python/skills/notebooks/notebooks/skills.ipynb index b1d106df..84e0d740 100644 --- a/libraries/python/skills/notebooks/notebooks/skills.ipynb +++ b/libraries/python/skills/notebooks/notebooks/skills.ipynb @@ -128,13 +128,40 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['chat_driver', 'logs.jsonl', 'test.txt']\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "User: /help\n", + "Posix skill: Commands:\n", + "cd(directory: str): Change the current working directory.\n", + "help(): Return this help message.\n", + "ls(path: str = \".\"): List directory contents.\n", + "mkdir(dirname: str): Create a new directory.\n", + "mv(src: str, dest: str): Move a file or directory.\n", + "pwd(): Return the current directory.\n", + "read_file(filename: str): Read the contents of a file.\n", + "rm(path: str): Remove a file or directory.\n", + "run_command(command: str): Run a shell command in the current directory.\n", + "touch(filename: str): Create an empty file.\n", + "write_file(filename: str, content: str): Write content to a file.\n" + ] + } + ], "source": [ "from pathlib import Path\n", "from posix_skill import PosixSkill\n", - "from chat_driver import ChatDriverConfig\n", + "from openai_client.chat_driver import ChatDriverConfig\n", "from context import Context\n", "\n", "context = Context(\"skills-123.posix\")\n", @@ -144,11 +171,9 @@ " openai_client=async_client,\n", " model=model,\n", " instructions=\"You are an assistant that has access to a sand-boxed Posix shell.\",\n", - " context=context,\n", ")\n", "\n", "posix_skill = PosixSkill(\n", - " context=context,\n", " sandbox_dir=Path(\".data\"),\n", " chat_driver_config=chat_driver_config,\n", " mount_dir=\"/mnt/data\",\n", @@ -181,26 +206,38 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "User: Hi!\n", + "Assistant: MessageEvent: Hello! How can I assist you today?\n", + "User: /help\n", + "Assistant: MessageEvent: Commands:\n", + "help(): Return this help message.\n", + "list_routines(): Lists all the routines available in the assistant.\n", + "run_routine(name: str, vars: dict[str, typing.Any] | None): Run an assistant routine.\n" + ] + } + ], "source": [ "from pathlib import Path\n", "from skill_library import Assistant\n", - "from chat_driver import ChatDriverConfig\n", + "from openai_client.chat_driver import ChatDriverConfig\n", "from posix_skill import PosixSkill\n", "\n", "\n", "# Define the assistant.\n", - "instructions = \"You are a helpful assistant.\"\n", - "\n", "chat_driver_config = ChatDriverConfig(\n", " openai_client=async_client,\n", " model=model,\n", - " instructions=instructions,\n", + " instructions=\"You are a helpful assistant.\",\n", ")\n", "\n", - "assistant = Assistant(name=\"Alice\", chat_driver_config=chat_driver_config, session_id=\"posix-assistant-123\")\n", + "assistant = Assistant(name=\"Alice\", assistant_id=\"posix-assistant-123\", chat_driver_config=chat_driver_config)\n", "\n", "# Now that the assistant has been created with a context, we can create the\n", "# skills and register them with the assistant's context.\n", @@ -208,7 +245,6 @@ "# Define the posix skill. This skill will be used by the assistant. Note that\n", "# some skills may have a conversational interface using a chat driver.\n", "posix_skill = PosixSkill(\n", - " context=assistant.context,\n", " sandbox_dir=Path(\".data\"),\n", " mount_dir=\"/mnt/data\",\n", " chat_driver_config=ChatDriverConfig(\n", @@ -245,7 +281,7 @@ "source": [ "from pathlib import Path\n", "from skill_library import Assistant\n", - "from chat_driver import ChatDriverConfig\n", + "from openai_client.chat_driver import ChatDriverConfig\n", "from posix_skill import PosixSkill\n", "\n", "# Define the posix skill. This skill will be used by the assistant. Note that\n", @@ -260,11 +296,10 @@ " model=model,\n", " instructions=\"You are a helpful assistant.\",\n", " ),\n", - " session_id=\"assistant-123\",\n", + " assistant_id=\"assistant-123\",\n", ")\n", "\n", "posix_skill = PosixSkill(\n", - " context=assistant.context,\n", " sandbox_dir=Path(\".data\"),\n", " mount_dir=\"/mnt/data\",\n", " chat_driver_config=ChatDriverConfig(\n", @@ -302,7 +337,7 @@ "import nest_asyncio\n", "from pathlib import Path\n", "from skill_library import Assistant\n", - "from chat_driver import ChatDriverConfig\n", + "from openai_client.chat_driver import ChatDriverConfig\n", "from posix_skill import PosixSkill\n", "nest_asyncio.apply()\n", "\n", @@ -310,11 +345,10 @@ "chat_driver_config = ChatDriverConfig(\n", " openai_client=async_client, model=model, instructions=\"You are a helpful assistant.\"\n", ")\n", - "assistant = Assistant(name=\"Alice\", chat_driver_config=chat_driver_config, session_id=\"assistant-123\")\n", + "assistant = Assistant(name=\"Alice\", chat_driver_config=chat_driver_config, assistant_id=\"assistant-123\")\n", "\n", "# Define the posix skill.\n", "posix_skill = PosixSkill(\n", - " context=assistant.context,\n", " sandbox_dir=Path(\".data\"),\n", " mount_dir=\"/mnt/data\",\n", " chat_driver_config=ChatDriverConfig(\n", diff --git a/libraries/python/skills/notebooks/pyproject.toml b/libraries/python/skills/notebooks/pyproject.toml index 8017bf15..15f0120f 100644 --- a/libraries/python/skills/notebooks/pyproject.toml +++ b/libraries/python/skills/notebooks/pyproject.toml @@ -7,7 +7,6 @@ requires-python = ">=3.11" dependencies = [ "assistant-drive>=0.1.0", "azure-identity>=1.17.1", - "chat-driver>=0.1.0", "context>=0.1.0", "events>=0.1.0", "nest-asyncio>=1.6.0", @@ -25,9 +24,8 @@ dev-dependencies = [ [tool.uv.sources] assistant-drive = { path = "../../assistant-drive", editable = true } -chat-driver = { path = "../../chat-driver", editable = true } context = { path = "../../context", editable = true } events = { path = "../../events", editable = true } +openai-client = { path = "../../openai-client", editable = true } posix-skill = { path = "../skills/posix-skill", editable = true } skill-library = { path = "../skill-library/", editable = true } -openai-client = { path = "../../openai-client", editable = true } diff --git a/libraries/python/skills/notebooks/uv.lock b/libraries/python/skills/notebooks/uv.lock index c673a319..00b5314a 100644 --- a/libraries/python/skills/notebooks/uv.lock +++ b/libraries/python/skills/notebooks/uv.lock @@ -326,37 +326,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/28/76/e6222113b83e3622caa4bb41032d0b1bf785250607392e1b778aca0b8a7d/charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", size = 48543 }, ] -[[package]] -name = "chat-driver" -version = "0.1.0" -source = { editable = "../../chat-driver" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "events" }, - { name = "openai" }, - { name = "openai-client" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../context" }, - { name = "events", editable = "../../events" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "openai-client", editable = "../../openai-client" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - [[package]] name = "click" version = "8.1.7" @@ -1020,6 +989,7 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, + { name = "events" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -1032,6 +1002,7 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "events", editable = "../../events" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, @@ -1147,17 +1118,17 @@ name = "posix-skill" version = "0.1.0" source = { editable = "../skills/posix-skill" } dependencies = [ - { name = "chat-driver" }, { name = "context" }, { name = "events" }, + { name = "openai-client" }, { name = "skill-library" }, ] [package.metadata] requires-dist = [ - { name = "chat-driver", editable = "../../chat-driver" }, { name = "context", editable = "../../context" }, { name = "events", editable = "../../events" }, + { name = "openai-client", editable = "../../openai-client" }, { name = "skill-library", editable = "../skill-library" }, ] @@ -1681,10 +1652,10 @@ version = "0.1.0" source = { editable = "../skill-library" } dependencies = [ { name = "assistant-drive" }, - { name = "chat-driver" }, { name = "context" }, { name = "events" }, { name = "openai" }, + { name = "openai-client" }, { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, @@ -1695,10 +1666,10 @@ dependencies = [ [package.metadata] requires-dist = [ { name = "assistant-drive", editable = "../../assistant-drive" }, - { name = "chat-driver", editable = "../../chat-driver" }, { name = "context", editable = "../../context" }, { name = "events", editable = "../../events" }, { name = "openai", specifier = ">=1.16.1" }, + { name = "openai-client", editable = "../../openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, @@ -1720,7 +1691,6 @@ source = { virtual = "." } dependencies = [ { name = "assistant-drive" }, { name = "azure-identity" }, - { name = "chat-driver" }, { name = "context" }, { name = "events" }, { name = "nest-asyncio" }, @@ -1740,7 +1710,6 @@ dev = [ requires-dist = [ { name = "assistant-drive", editable = "../../assistant-drive" }, { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "chat-driver", editable = "../../chat-driver" }, { name = "context", editable = "../../context" }, { name = "events", editable = "../../events" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, diff --git a/libraries/python/skills/skill-library/README.md b/libraries/python/skills/skill-library/README.md index 7ad9c114..1e58128a 100644 --- a/libraries/python/skills/skill-library/README.md +++ b/libraries/python/skills/skill-library/README.md @@ -25,9 +25,10 @@ more easily: assistants by providing clearer purposeful abstractions and better defining or disambiguating commonly confused terms. For example, we separate out a lot of the complexity of interacting with the OpenAI Chat Completion API with the - [chat driver](../../chat-driver/README.md) abstraction and we now - distinguish between chat commands, chat tool functions, and routine actions in - a clear way, even though they're really all just functions. + [chat driver](../../openai-client/openai_client/chat_driver/README.md) + abstraction and we now distinguish between chat commands, chat tool functions, + and routine actions in a clear way, even though they're really all just + functions. - Routines (formerly referred to as "Recipes") make it clear that what we are developing agents that can automate productive work collaboratively with the user. We have several ideas here, from simply following a set of steps, to diff --git a/libraries/python/skills/skill-library/pyproject.toml b/libraries/python/skills/skill-library/pyproject.toml index c947f856..3662f6c5 100644 --- a/libraries/python/skills/skill-library/pyproject.toml +++ b/libraries/python/skills/skill-library/pyproject.toml @@ -7,9 +7,9 @@ readme = "README.md" requires-python = ">=3.11" dependencies = [ "assistant-drive>=0.1.0", - "chat-driver>=0.1.0", "context>=0.1.0", "events>=0.1.0", + "openai-client>=0.1.0", "openai>=1.16.1", "pydantic-settings>=2.3.4", "pydantic>=2.6.1", @@ -28,9 +28,10 @@ dev-dependencies = [ [tool.uv.sources] assistant-drive = { path = "../../assistant-drive", editable = true } -chat-driver = { path = "../../chat-driver", editable = true } context = { path = "../../context", editable = true } events = { path = "../../events", editable = true } +openai-client = { path = "../../openai-client", editable = true } + [build-system] requires = ["hatchling"] diff --git a/libraries/python/skills/skill-library/skill_library/actions.py b/libraries/python/skills/skill-library/skill_library/actions.py index 8cbd0e20..7350a97f 100644 --- a/libraries/python/skills/skill-library/skill_library/actions.py +++ b/libraries/python/skills/skill-library/skill_library/actions.py @@ -89,7 +89,7 @@ def __init__(self, actions: "Actions") -> None: def __getattr__(self, name: str) -> Callable: """Makes registered functions accessible as attributes of the functions object.""" if name not in self.actions.action_map: - raise AttributeError(f"'FunctionHandler' object has no attribute '{name}'") + raise AttributeError(f"'Actions' object has no attribute '{name}'") async def wrapper(*args, **kwargs) -> Any: return await self.actions.execute_action(name, args, kwargs) @@ -146,7 +146,10 @@ def get_actions(self) -> list[Action]: return [function for function in self.action_map.values()] async def execute_action( - self, name: str, args: tuple = (), kwargs: dict[str, Any] = {}, string_response: bool = False + self, + name: str, + args: tuple = (), + kwargs: dict[str, Any] = {}, ) -> Any: """ Run a function from the ToolFunctions list by name. If string_response @@ -155,9 +158,9 @@ async def execute_action( function = self.get_action(name) if not function: raise ValueError(f"Function {name} not found in registry.") - return await function.execute(string_response, *args, **kwargs) + return await function.execute(*args, **kwargs) - async def execute_action_string(self, function_string: str, string_response: bool = False) -> Any: + async def execute_action_string(self, function_string: str) -> Any: """Parse a function string and execute the function.""" try: function, args, kwargs = self.parse_action_string(function_string) @@ -165,7 +168,7 @@ async def execute_action_string(self, function_string: str, string_response: boo raise ValueError(f"{e}. Type: `/help` for more information.") if not function: raise ValueError("Function not found in registry. Type: `/help` for more information.") - return await function.execute(string_response, *args, **kwargs) + return await function.execute(*args, **kwargs) def parse_action_string(self, action_string: str) -> tuple[Action | None, list[Any], dict[str, Any]]: """Parse a function call string into a function and its arguments.""" diff --git a/libraries/python/skills/skill-library/skill_library/assistant.py b/libraries/python/skills/skill-library/skill_library/assistant.py index f8b8d3da..804d2017 100644 --- a/libraries/python/skills/skill-library/skill_library/assistant.py +++ b/libraries/python/skills/skill-library/skill_library/assistant.py @@ -4,16 +4,17 @@ from uuid import uuid4 from assistant_drive import Drive, DriveConfig, IfDriveFileExistsBehavior -from chat_driver import ( - TEXT_RESPONSE_FORMAT, - ChatDriver, - ChatDriverConfig, -) -from chat_driver.local_message_history_provider import LocalMessageHistoryProvider, LocalMessageHistoryProviderConfig from events import BaseEvent, EventProtocol from openai.types.chat.completion_create_params import ( ResponseFormat, ) +from openai_client.chat_driver import ( + ChatDriver, + ChatDriverConfig, + LocalMessageHistoryProvider, + LocalMessageHistoryProviderConfig, +) +from openai_client.completion import TEXT_RESPONSE_FORMAT from openai_client.messages import format_with_liquid from .run_context import RunContext @@ -26,9 +27,9 @@ def __init__( self, name, assistant_id: str | None, - drive_root: PathLike | None, - metadrive_drive_root: PathLike | None, chat_driver_config: ChatDriverConfig, + drive_root: PathLike | None = None, + metadrive_drive_root: PathLike | None = None, skills: list[Skill] = [], ) -> None: self.skill_registry: SkillRegistry = SkillRegistry() @@ -225,7 +226,7 @@ def list_routines(self) -> list[str]: """Lists all the routines available in the assistant.""" return self.assistant.list_routines() - async def run_routine(self, name: str, vars: dict[str, Any] | None = None) -> Any: + async def run_routine(self, name: str, vars: dict[str, Any] | None) -> Any: """ Run an assistant routine. """ diff --git a/libraries/python/skills/skill-library/skill_library/skill.py b/libraries/python/skills/skill-library/skill_library/skill.py index 9efc133a..f9c4e99d 100644 --- a/libraries/python/skills/skill-library/skill_library/skill.py +++ b/libraries/python/skills/skill-library/skill_library/skill.py @@ -1,9 +1,10 @@ import logging from typing import Any, Callable -from chat_driver import TEXT_RESPONSE_FORMAT, ChatDriver, ChatDriverConfig from events import BaseEvent, EventProtocol from openai.types.chat.completion_create_params import ResponseFormat +from openai_client.chat_driver import ChatDriver, ChatDriverConfig +from openai_client.completion import TEXT_RESPONSE_FORMAT from .actions import Actions from .routine import RoutineTypes @@ -52,17 +53,17 @@ def __init__( self.openai_client = chat_driver_config.openai_client if chat_driver_config else None # Register all provided actions with the action registry. - self.actions = Actions() - self.actions.add_functions(skill_actions) + self.action_registry = Actions() + self.action_registry.add_functions(skill_actions) # Also, register any commands provided by the chat driver. All # commands will be available to the skill. if self.chat_driver: - self.actions.add_functions(self.chat_driver.get_commands()) + self.action_registry.add_functions(self.chat_driver.get_commands()) # Make actions available to be called as attributes from the skill # directly. - self.actions = self.actions.functions + self.actions = self.action_registry.functions async def respond( self, @@ -82,10 +83,10 @@ async def respond( ) def get_actions(self) -> list[Callable]: - return [function.fn for function in self.actions.get_actions()] + return [function.fn for function in self.action_registry.get_actions()] def list_actions(self) -> list[str]: - return [action.name for action in self.actions.get_actions()] + return [action.name for action in self.action_registry.get_actions()] def add_routine(self, routine: RoutineTypes) -> None: """ diff --git a/libraries/python/skills/skill-library/uv.lock b/libraries/python/skills/skill-library/uv.lock index a4808eae..f6637e77 100644 --- a/libraries/python/skills/skill-library/uv.lock +++ b/libraries/python/skills/skill-library/uv.lock @@ -321,37 +321,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079", size = 49446 }, ] -[[package]] -name = "chat-driver" -version = "0.1.0" -source = { editable = "../../chat-driver" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "events" }, - { name = "openai" }, - { name = "openai-client" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../context" }, - { name = "events", editable = "../../events" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "openai-client", editable = "../../openai-client" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - [[package]] name = "click" version = "8.1.7" @@ -903,6 +872,7 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, + { name = "events" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -915,6 +885,7 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "events", editable = "../../events" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, @@ -1465,10 +1436,10 @@ version = "0.1.0" source = { editable = "." } dependencies = [ { name = "assistant-drive" }, - { name = "chat-driver" }, { name = "context" }, { name = "events" }, { name = "openai" }, + { name = "openai-client" }, { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, @@ -1486,10 +1457,10 @@ dev = [ [package.metadata] requires-dist = [ { name = "assistant-drive", editable = "../../assistant-drive" }, - { name = "chat-driver", editable = "../../chat-driver" }, { name = "context", editable = "../../context" }, { name = "events", editable = "../../events" }, { name = "openai", specifier = ">=1.16.1" }, + { name = "openai-client", editable = "../../openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, diff --git a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_content.py b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_content.py index 558607da..ccbb9ea5 100644 --- a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_content.py +++ b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_content.py @@ -1,6 +1,5 @@ -from chat_driver import ChatDriver, ChatDriverConfig -from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider from openai import AsyncAzureOpenAI, AsyncOpenAI +from openai_client.chat_driver import ChatDriver, ChatDriverConfig, InMemoryMessageHistoryProvider from openai_client.messages import format_with_liquid from ..document_skill import Outline, Paper diff --git a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_outline.py b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_outline.py index 6c8b4a40..8e7f6a24 100644 --- a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_outline.py +++ b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/draft_outline.py @@ -1,6 +1,5 @@ -from chat_driver import ChatDriver, ChatDriverConfig -from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider from openai import AsyncAzureOpenAI, AsyncOpenAI +from openai_client.chat_driver import ChatDriver, ChatDriverConfig, InMemoryMessageHistoryProvider from openai_client.messages import format_with_liquid from ..document_skill import Outline diff --git a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_outline_decision.py b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_outline_decision.py index 7b36e64b..2015d908 100644 --- a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_outline_decision.py +++ b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_outline_decision.py @@ -1,6 +1,5 @@ -from chat_driver import ChatDriver, ChatDriverConfig -from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider from openai import AsyncAzureOpenAI, AsyncOpenAI +from openai_client.chat_driver import ChatDriver, ChatDriverConfig, InMemoryMessageHistoryProvider from openai_client.messages import format_with_liquid from ..document_skill import Outline, Paper diff --git a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_page_decision.py b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_page_decision.py index 364d514c..e710e7d3 100644 --- a/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_page_decision.py +++ b/libraries/python/skills/skills/document-skill/document_skill/chat_drivers/get_user_feedback_for_page_decision.py @@ -1,6 +1,5 @@ -from chat_driver import ChatDriver, ChatDriverConfig -from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider from openai import AsyncAzureOpenAI, AsyncOpenAI +from openai_client.chat_driver import ChatDriver, ChatDriverConfig, InMemoryMessageHistoryProvider from openai_client.messages import format_with_liquid from ..document_skill import Outline, Paper diff --git a/libraries/python/skills/skills/document-skill/document_skill/document_skill.py b/libraries/python/skills/skills/document-skill/document_skill/document_skill.py index 9e58e35c..b825c065 100644 --- a/libraries/python/skills/skills/document-skill/document_skill/document_skill.py +++ b/libraries/python/skills/skills/document-skill/document_skill/document_skill.py @@ -1,7 +1,7 @@ # flake8: noqa # ruff: noqa -from chat_driver import ChatDriverConfig +from openai_client.chat_driver import ChatDriverConfig from openai import AsyncAzureOpenAI, AsyncOpenAI from pydantic import BaseModel # temp to have something to experiment with from skill_library import EmitterType, RoutineTypes, Skill diff --git a/libraries/python/skills/skills/document-skill/pyproject.toml b/libraries/python/skills/skills/document-skill/pyproject.toml index 4e437203..63e162e9 100644 --- a/libraries/python/skills/skills/document-skill/pyproject.toml +++ b/libraries/python/skills/skills/document-skill/pyproject.toml @@ -6,20 +6,20 @@ authors = [{name="MADE:Explorers"}] readme = "README.md" requires-python = ">=3.11" dependencies = [ - "skill-library>=0.1.0", - "chat-driver>=0.1.0", "context>=0.1.0", "events>=0.1.0", + "openai-client>=0.1.0", + "skill-library>=0.1.0", ] [tool.uv] package = true [tool.uv.sources] -skill-library = { path = "../../skill-library", editable= true } -chat-driver = { path = "../../../chat-driver", editable = true } context = { path = "../../../context", editable = true } events = { path = "../../../events", editable = true } +openai-client = { path = "../../../openai-client", editable = true } +skill-library = { path = "../../skill-library", editable= true } [build-system] requires = ["hatchling"] diff --git a/libraries/python/skills/skills/document-skill/uv.lock b/libraries/python/skills/skills/document-skill/uv.lock index 17bb2657..e8e201a5 100644 --- a/libraries/python/skills/skills/document-skill/uv.lock +++ b/libraries/python/skills/skills/document-skill/uv.lock @@ -306,37 +306,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/28/76/e6222113b83e3622caa4bb41032d0b1bf785250607392e1b778aca0b8a7d/charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", size = 48543 }, ] -[[package]] -name = "chat-driver" -version = "0.1.0" -source = { editable = "../../../chat-driver" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "events" }, - { name = "openai" }, - { name = "openai-client" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../../context" }, - { name = "events", editable = "../../../events" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "openai-client", editable = "../../../openai-client" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - [[package]] name = "click" version = "8.1.7" @@ -437,17 +406,17 @@ name = "document-skill" version = "0.1.0" source = { editable = "." } dependencies = [ - { name = "chat-driver" }, { name = "context" }, { name = "events" }, + { name = "openai-client" }, { name = "skill-library" }, ] [package.metadata] requires-dist = [ - { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, + { name = "openai-client", editable = "../../../openai-client" }, { name = "skill-library", editable = "../../skill-library" }, ] @@ -886,6 +855,7 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, + { name = "events" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -898,6 +868,7 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "events", editable = "../../../events" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, @@ -1397,10 +1368,10 @@ version = "0.1.0" source = { editable = "../../skill-library" } dependencies = [ { name = "assistant-drive" }, - { name = "chat-driver" }, { name = "context" }, { name = "events" }, { name = "openai" }, + { name = "openai-client" }, { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, @@ -1411,10 +1382,10 @@ dependencies = [ [package.metadata] requires-dist = [ { name = "assistant-drive", editable = "../../../assistant-drive" }, - { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, { name = "openai", specifier = ">=1.16.1" }, + { name = "openai-client", editable = "../../../openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/final_update.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/final_update.py index 1e4b4cb6..1d3690fe 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/final_update.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/final_update.py @@ -1,11 +1,10 @@ import logging -from chat_driver import ChatDriver, ChatDriverConfig -from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider from form_filler_skill.artifact import Artifact from form_filler_skill.definition import GCDefinition from form_filler_skill.message import Conversation from openai import AsyncAzureOpenAI, AsyncOpenAI +from openai_client.chat_driver import ChatDriver, ChatDriverConfig, InMemoryMessageHistoryProvider logger = logging.getLogger(__name__) diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_agenda_error.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_agenda_error.py index dbe26739..084762f6 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_agenda_error.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_agenda_error.py @@ -1,9 +1,8 @@ import logging -from chat_driver import ChatDriver, ChatDriverConfig -from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider from form_filler_skill.message import Conversation, ConversationMessageType from openai import AsyncAzureOpenAI, AsyncOpenAI +from openai_client.chat_driver import ChatDriver, ChatDriverConfig, InMemoryMessageHistoryProvider logger = logging.getLogger(__name__) diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_artifact_error.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_artifact_error.py index e73ee449..0dea8d17 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_artifact_error.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/fix_artifact_error.py @@ -1,10 +1,9 @@ import logging -from chat_driver import ChatDriver, ChatDriverConfig -from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider from events import BaseEvent from form_filler_skill.message import Conversation, ConversationMessageType from openai import AsyncAzureOpenAI, AsyncOpenAI +from openai_client.chat_driver import ChatDriver, ChatDriverConfig, InMemoryMessageHistoryProvider logger = logging.getLogger(__name__) diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action.py index 804e59b8..e03cc6e7 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/choose_action.py @@ -1,7 +1,5 @@ import logging -from chat_driver import ChatDriver, ChatDriverConfig -from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider from form_filler_skill.agenda import Agenda, AgendaItem from form_filler_skill.definition import GCDefinition from form_filler_skill.message import Conversation @@ -12,6 +10,7 @@ format_resource, ) from openai import AsyncAzureOpenAI, AsyncOpenAI +from openai_client.chat_driver import ChatDriver, ChatDriverConfig, InMemoryMessageHistoryProvider from pydantic import ValidationError from skill_library.run_context import RunContext diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/execute_reasoning.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/execute_reasoning.py index 849056f4..c81448b7 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/execute_reasoning.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/unneeded/execute_reasoning.py @@ -1,8 +1,7 @@ import logging -from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol -from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider from openai import AsyncAzureOpenAI, AsyncOpenAI +from openai_client.chat_driver import ChatDriver, ChatDriverConfig, InMemoryMessageHistoryProvider logger = logging.getLogger(__name__) @@ -31,7 +30,6 @@ async def execute_reasoning( - context: ContextProtocol, open_ai_client: AsyncOpenAI | AsyncAzureOpenAI, reasoning: str, artifact_schema: str, diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact.py index 2598180a..8f1051ec 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/chat_drivers/update_artifact.py @@ -1,7 +1,5 @@ import logging -from chat_driver import ChatDriver, ChatDriverConfig -from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider from form_filler_skill.agenda import Agenda, AgendaItem from form_filler_skill.definition import GCDefinition from form_filler_skill.message import Conversation @@ -12,6 +10,7 @@ format_resource, ) from openai import AsyncAzureOpenAI, AsyncOpenAI +from openai_client.chat_driver import ChatDriver, ChatDriverConfig, InMemoryMessageHistoryProvider from pydantic import ValidationError from ..artifact import Artifact diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/form_filler_skill.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/form_filler_skill.py index 85133997..1e901c18 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/form_filler_skill.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/form_filler_skill.py @@ -3,7 +3,7 @@ from typing import Any, Optional -from chat_driver import ChatDriverConfig +from openai_client.chat_driver import ChatDriverConfig from skill_library import FunctionRoutine, RoutineTypes, Skill from skill_library.run_context import RunContext diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_final_update.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_final_update.py index 1c594630..46150c99 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_final_update.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_final_update.py @@ -1,11 +1,10 @@ import logging -from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol -from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider from form_filler_skill.guided_conversation.artifact import Artifact from form_filler_skill.guided_conversation.conversation_helpers import Conversation from form_filler_skill.guided_conversation.definition import GCDefinition from openai import AsyncAzureOpenAI, AsyncOpenAI +from openai_client.chat_driver import ChatDriver, ChatDriverConfig, InMemoryMessageHistoryProvider logger = logging.getLogger(__name__) @@ -56,7 +55,6 @@ async def final_update( - context: ContextProtocol, open_ai_client: AsyncOpenAI | AsyncAzureOpenAI, definition: GCDefinition, chat_history: Conversation, diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_fix_agenda_error.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_fix_agenda_error.py index fc6a17dd..8498d854 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_fix_agenda_error.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_fix_agenda_error.py @@ -1,12 +1,11 @@ import logging -from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol -from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider from form_filler_skill.guided_conversation.conversation_helpers import ( Conversation, ConversationMessageType, ) from openai import AsyncAzureOpenAI, AsyncOpenAI +from openai_client.chat_driver import ChatDriver, ChatDriverConfig, InMemoryMessageHistoryProvider logger = logging.getLogger(__name__) @@ -36,7 +35,6 @@ async def fix_agenda_error( - context: ContextProtocol, openai_client: AsyncOpenAI | AsyncAzureOpenAI, previous_attempts: str, conversation: Conversation, diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_agenda.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_agenda.py index 42f72860..805af525 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_agenda.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_agenda.py @@ -1,7 +1,5 @@ import logging -from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol -from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider from form_filler_skill.agenda import Agenda, AgendaItem from form_filler_skill.guided_conversation.definition import GCDefinition from form_filler_skill.message import Conversation @@ -12,6 +10,7 @@ format_resource, ) from openai import AsyncAzureOpenAI, AsyncOpenAI +from openai_client.chat_driver import ChatDriver, ChatDriverConfig, InMemoryMessageHistoryProvider from pydantic import ValidationError from ...artifact import Artifact @@ -62,7 +61,6 @@ def _get_termination_instructions(resource: GCResource): async def update_agenda( - context: ContextProtocol, openai_client: AsyncOpenAI | AsyncAzureOpenAI, definition: GCDefinition, chat_history: Conversation, diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_artifact.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_artifact.py index a44372e6..c43f9e85 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_artifact.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation/chat_drivers/gc_update_artifact.py @@ -1,8 +1,7 @@ import logging -from chat_driver import ChatDriver, ChatDriverConfig, ContextProtocol -from chat_driver.in_memory_message_history_provider import InMemoryMessageHistoryProvider from openai import AsyncAzureOpenAI, AsyncOpenAI +from openai_client.chat_driver import ChatDriver, ChatDriverConfig, InMemoryMessageHistoryProvider logger = logging.getLogger(__name__) @@ -34,7 +33,6 @@ async def update_artifact( - context: ContextProtocol, open_ai_client: AsyncOpenAI | AsyncAzureOpenAI, reasoning: str, artifact_schema: str, diff --git a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py index 819df19d..f17aa673 100644 --- a/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py +++ b/libraries/python/skills/skills/form-filler-skill/form_filler_skill/guided_conversation_skill.py @@ -3,7 +3,7 @@ from typing import Any, Optional -from chat_driver import ChatDriverConfig +from openai_client.chat_driver import ChatDriverConfig from events import BaseEvent, MessageEvent from skill_library import EmitterType, FunctionRoutine, RoutineTypes, Skill from skill_library.run_context import RunContext @@ -148,7 +148,7 @@ async def update_agenda(self, items: str) -> tuple[Agenda, bool]: ) async def execute_reasoning(self, context: RunContext, reasoning: str) -> BaseEvent: - return await execute_reasoning(context, self.openai_client, reasoning, self.artifact.get_schema_for_prompt()) + return await execute_reasoning(self.openai_client, reasoning, self.artifact.get_schema_for_prompt()) async def final_update(self, context: RunContext, definition: GCDefinition): await final_update(self.openai_client, definition, self.chat_history, self.artifact) diff --git a/libraries/python/skills/skills/form-filler-skill/pyproject.toml b/libraries/python/skills/skills/form-filler-skill/pyproject.toml index 5ea6b681..c7a4adc1 100644 --- a/libraries/python/skills/skills/form-filler-skill/pyproject.toml +++ b/libraries/python/skills/skills/form-filler-skill/pyproject.toml @@ -7,7 +7,6 @@ readme = "README.md" requires-python = ">=3.11" dependencies = [ "skill-library>=0.1.0", - "chat-driver>=0.1.0", "context>=0.1.0", "events>=0.1.0", "openai-client>=0.1.0", @@ -19,7 +18,6 @@ package = true [tool.uv.sources] skill-library = { path = "../../skill-library", editable= true } -chat-driver = { path = "../../../chat-driver", editable = true } context = { path = "../../../context", editable = true } events = { path = "../../../events", editable = true } openai-client = { path = "../../../openai-client", editable = true } diff --git a/libraries/python/skills/skills/form-filler-skill/uv.lock b/libraries/python/skills/skills/form-filler-skill/uv.lock index 61609fd5..cfb79cfc 100644 --- a/libraries/python/skills/skills/form-filler-skill/uv.lock +++ b/libraries/python/skills/skills/form-filler-skill/uv.lock @@ -306,37 +306,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/28/76/e6222113b83e3622caa4bb41032d0b1bf785250607392e1b778aca0b8a7d/charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", size = 48543 }, ] -[[package]] -name = "chat-driver" -version = "0.1.0" -source = { editable = "../../../chat-driver" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "events" }, - { name = "openai" }, - { name = "openai-client" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../../context" }, - { name = "events", editable = "../../../events" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "openai-client", editable = "../../../openai-client" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - [[package]] name = "click" version = "8.1.7" @@ -503,7 +472,6 @@ name = "form-filler-skill" version = "0.1.0" source = { editable = "." } dependencies = [ - { name = "chat-driver" }, { name = "context" }, { name = "events" }, { name = "openai-client" }, @@ -512,7 +480,6 @@ dependencies = [ [package.metadata] requires-dist = [ - { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, { name = "openai-client", editable = "../../../openai-client" }, @@ -888,6 +855,7 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, + { name = "events" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -900,6 +868,7 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "events", editable = "../../../events" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, @@ -1399,10 +1368,10 @@ version = "0.1.0" source = { editable = "../../skill-library" } dependencies = [ { name = "assistant-drive" }, - { name = "chat-driver" }, { name = "context" }, { name = "events" }, { name = "openai" }, + { name = "openai-client" }, { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, @@ -1413,10 +1382,10 @@ dependencies = [ [package.metadata] requires-dist = [ { name = "assistant-drive", editable = "../../../assistant-drive" }, - { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, { name = "openai", specifier = ">=1.16.1" }, + { name = "openai-client", editable = "../../../openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, diff --git a/libraries/python/skills/skills/posix-skill/posix_skill/posix_skill.py b/libraries/python/skills/skills/posix-skill/posix_skill/posix_skill.py index 41071655..571bfb51 100644 --- a/libraries/python/skills/skills/posix-skill/posix_skill/posix_skill.py +++ b/libraries/python/skills/skills/posix-skill/posix_skill/posix_skill.py @@ -1,6 +1,6 @@ from pathlib import Path -from chat_driver import ChatDriverConfig +from openai_client.chat_driver import ChatDriverConfig from skill_library import InstructionRoutine, RoutineTypes, Skill from .sandbox_shell import SandboxShell diff --git a/libraries/python/skills/skills/posix-skill/pyproject.toml b/libraries/python/skills/skills/posix-skill/pyproject.toml index b72e1bb0..9729f258 100644 --- a/libraries/python/skills/skills/posix-skill/pyproject.toml +++ b/libraries/python/skills/skills/posix-skill/pyproject.toml @@ -6,10 +6,10 @@ authors = [{name="MADE:Explorers"}] readme = "README.md" requires-python = ">=3.11" dependencies = [ - "skill-library>=0.1.0", - "chat-driver>=0.1.0", "context>=0.1.0", "events>=0.1.0", + "openai-client>=0.1.0", + "skill-library>=0.1.0", ] [tool.uv] @@ -17,9 +17,10 @@ package = true [tool.uv.sources] skill-library = { path = "../../skill-library", editable= true } -chat-driver = { path = "../../../chat-driver", editable = true } context = { path = "../../../context", editable = true } events = { path = "../../../events", editable = true } +openai-client = { path = "../../../openai-client", editable = true } + [build-system] requires = ["hatchling"] diff --git a/libraries/python/skills/skills/posix-skill/uv.lock b/libraries/python/skills/skills/posix-skill/uv.lock index f3305ad5..854eeaec 100644 --- a/libraries/python/skills/skills/posix-skill/uv.lock +++ b/libraries/python/skills/skills/posix-skill/uv.lock @@ -306,37 +306,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/28/76/e6222113b83e3622caa4bb41032d0b1bf785250607392e1b778aca0b8a7d/charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", size = 48543 }, ] -[[package]] -name = "chat-driver" -version = "0.1.0" -source = { editable = "../../../chat-driver" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "events" }, - { name = "openai" }, - { name = "openai-client" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../../context" }, - { name = "events", editable = "../../../events" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "openai-client", editable = "../../../openai-client" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - [[package]] name = "click" version = "8.1.7" @@ -867,6 +836,7 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, + { name = "events" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -879,6 +849,7 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "events", editable = "../../../events" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, @@ -964,17 +935,17 @@ name = "posix-skill" version = "0.1.0" source = { editable = "." } dependencies = [ - { name = "chat-driver" }, { name = "context" }, { name = "events" }, + { name = "openai-client" }, { name = "skill-library" }, ] [package.metadata] requires-dist = [ - { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, + { name = "openai-client", editable = "../../../openai-client" }, { name = "skill-library", editable = "../../skill-library" }, ] @@ -1397,10 +1368,10 @@ version = "0.1.0" source = { editable = "../../skill-library" } dependencies = [ { name = "assistant-drive" }, - { name = "chat-driver" }, { name = "context" }, { name = "events" }, { name = "openai" }, + { name = "openai-client" }, { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, @@ -1411,10 +1382,10 @@ dependencies = [ [package.metadata] requires-dist = [ { name = "assistant-drive", editable = "../../../assistant-drive" }, - { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, { name = "openai", specifier = ">=1.16.1" }, + { name = "openai-client", editable = "../../../openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, diff --git a/libraries/python/skills/skills/prospector-skill/prospector_skill/skill.py b/libraries/python/skills/skills/prospector-skill/prospector_skill/skill.py index 84def677..13046820 100644 --- a/libraries/python/skills/skills/prospector-skill/prospector_skill/skill.py +++ b/libraries/python/skills/skills/prospector-skill/prospector_skill/skill.py @@ -1,5 +1,5 @@ -from chat_driver import ChatDriverConfig from context import ContextProtocol +from openai_client.chat_driver import ChatDriverConfig from skill_library import InstructionRoutine, RoutineTypes, Skill NAME = "prospector" diff --git a/libraries/python/skills/skills/prospector-skill/pyproject.toml b/libraries/python/skills/skills/prospector-skill/pyproject.toml index 344d128f..f33f3862 100644 --- a/libraries/python/skills/skills/prospector-skill/pyproject.toml +++ b/libraries/python/skills/skills/prospector-skill/pyproject.toml @@ -6,20 +6,21 @@ authors = [{name="MADE:Explorers"}] readme = "README.md" requires-python = ">=3.11" dependencies = [ - "skill-library>=0.1.0", - "chat-driver>=0.1.0", "context>=0.1.0", "events>=0.1.0", + "openai-client>=0.1.0", + "skill-library>=0.1.0", ] [tool.uv] package = true [tool.uv.sources] -skill-library = { path = "../../skill-library", editable = true } -chat-driver = { path = "../../../chat-driver", editable = true } context = { path = "../../../context", editable = true } events = { path = "../../../events", editable = true } +openai-client = { path = "../../../openai-client", editable = true } +skill-library = { path = "../../skill-library", editable = true } + [build-system] requires = ["hatchling"] diff --git a/libraries/python/skills/skills/prospector-skill/uv.lock b/libraries/python/skills/skills/prospector-skill/uv.lock index d5405071..e79c712b 100644 --- a/libraries/python/skills/skills/prospector-skill/uv.lock +++ b/libraries/python/skills/skills/prospector-skill/uv.lock @@ -306,37 +306,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/28/76/e6222113b83e3622caa4bb41032d0b1bf785250607392e1b778aca0b8a7d/charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", size = 48543 }, ] -[[package]] -name = "chat-driver" -version = "0.1.0" -source = { editable = "../../../chat-driver" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "events" }, - { name = "openai" }, - { name = "openai-client" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../../context" }, - { name = "events", editable = "../../../events" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "openai-client", editable = "../../../openai-client" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - [[package]] name = "click" version = "8.1.7" @@ -867,6 +836,7 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, + { name = "events" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -879,6 +849,7 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "events", editable = "../../../events" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, @@ -1021,17 +992,17 @@ name = "prospector-skill" version = "0.1.0" source = { editable = "." } dependencies = [ - { name = "chat-driver" }, { name = "context" }, { name = "events" }, + { name = "openai-client" }, { name = "skill-library" }, ] [package.metadata] requires-dist = [ - { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, + { name = "openai-client", editable = "../../../openai-client" }, { name = "skill-library", editable = "../../skill-library" }, ] @@ -1397,10 +1368,10 @@ version = "0.1.0" source = { editable = "../../skill-library" } dependencies = [ { name = "assistant-drive" }, - { name = "chat-driver" }, { name = "context" }, { name = "events" }, { name = "openai" }, + { name = "openai-client" }, { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, @@ -1411,10 +1382,10 @@ dependencies = [ [package.metadata] requires-dist = [ { name = "assistant-drive", editable = "../../../assistant-drive" }, - { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, { name = "openai", specifier = ">=1.16.1" }, + { name = "openai-client", editable = "../../../openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, diff --git a/libraries/python/skills/skills/skill-template/pyproject.toml b/libraries/python/skills/skills/skill-template/pyproject.toml index 42fdc2bb..4af2e4e6 100644 --- a/libraries/python/skills/skills/skill-template/pyproject.toml +++ b/libraries/python/skills/skills/skill-template/pyproject.toml @@ -5,20 +5,20 @@ description = "MADE:Exploration skill" readme = "README.md" requires-python = ">=3.11" dependencies = [ - "skill-library>=0.1.0", - "chat-driver>=0.1.0", "context>=0.1.0", "events>=0.1.0", + "openai-client>=0.1.0", + "skill-library>=0.1.0", ] [tool.uv] package = true [tool.uv.sources] -skill-library = { path = "../../skill-library", editable = true } -chat-driver = { path = "../../../chat-driver", editable = true } context = { path = "../../../context", editable = true } events = { path = "../../../events", editable = true } +skill-library = { path = "../../skill-library", editable = true } + [build-system] requires = ["hatchling"] diff --git a/libraries/python/skills/skills/skill-template/uv.lock b/libraries/python/skills/skills/skill-template/uv.lock index 16119c5b..e5cadbc6 100644 --- a/libraries/python/skills/skills/skill-template/uv.lock +++ b/libraries/python/skills/skills/skill-template/uv.lock @@ -306,37 +306,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/28/76/e6222113b83e3622caa4bb41032d0b1bf785250607392e1b778aca0b8a7d/charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", size = 48543 }, ] -[[package]] -name = "chat-driver" -version = "0.1.0" -source = { editable = "../../../chat-driver" } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "events" }, - { name = "openai" }, - { name = "openai-client" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../../../context" }, - { name = "events", editable = "../../../events" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "openai-client", editable = "../../../openai-client" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - [[package]] name = "click" version = "8.1.7" @@ -867,6 +836,7 @@ dependencies = [ { name = "azure-ai-contentsafety" }, { name = "azure-core", extra = ["aio"] }, { name = "azure-identity" }, + { name = "events" }, { name = "openai" }, { name = "pillow" }, { name = "python-liquid" }, @@ -879,6 +849,7 @@ requires-dist = [ { name = "azure-ai-contentsafety", specifier = ">=1.0.0" }, { name = "azure-core", extras = ["aio"], specifier = ">=1.30.0" }, { name = "azure-identity", specifier = ">=1.17.1" }, + { name = "events", editable = "../../../events" }, { name = "openai", specifier = ">=1.3.9" }, { name = "pillow", specifier = ">=11.0.0" }, { name = "python-liquid", specifier = ">=1.12.1" }, @@ -1378,10 +1349,10 @@ version = "0.1.0" source = { editable = "../../skill-library" } dependencies = [ { name = "assistant-drive" }, - { name = "chat-driver" }, { name = "context" }, { name = "events" }, { name = "openai" }, + { name = "openai-client" }, { name = "pydantic" }, { name = "pydantic-settings" }, { name = "python-dotenv" }, @@ -1392,10 +1363,10 @@ dependencies = [ [package.metadata] requires-dist = [ { name = "assistant-drive", editable = "../../../assistant-drive" }, - { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, { name = "openai", specifier = ">=1.16.1" }, + { name = "openai-client", editable = "../../../openai-client" }, { name = "pydantic", specifier = ">=2.6.1" }, { name = "pydantic-settings", specifier = ">=2.3.4" }, { name = "python-dotenv", specifier = ">=1.0.1" }, @@ -1710,16 +1681,16 @@ name = "your-skill" version = "0.1.0" source = { editable = "." } dependencies = [ - { name = "chat-driver" }, { name = "context" }, { name = "events" }, + { name = "openai-client" }, { name = "skill-library" }, ] [package.metadata] requires-dist = [ - { name = "chat-driver", editable = "../../../chat-driver" }, { name = "context", editable = "../../../context" }, { name = "events", editable = "../../../events" }, + { name = "openai-client", specifier = ">=0.1.0" }, { name = "skill-library", editable = "../../skill-library" }, ] diff --git a/libraries/python/skills/skills/skill-template/your_skill/skill.py b/libraries/python/skills/skills/skill-template/your_skill/skill.py index 67c47d95..95a22957 100644 --- a/libraries/python/skills/skills/skill-template/your_skill/skill.py +++ b/libraries/python/skills/skills/skill-template/your_skill/skill.py @@ -1,5 +1,5 @@ -from chat_driver import ChatDriverConfig from context import ContextProtocol +from openai_client.chat_driver import ChatDriverConfig from skill_library import InstructionRoutine, RoutineTypes, Skill NAME = "your" diff --git a/semantic-workbench.code-workspace b/semantic-workbench.code-workspace index 545f9f4a..aa838b42 100644 --- a/semantic-workbench.code-workspace +++ b/semantic-workbench.code-workspace @@ -75,10 +75,6 @@ "name": "libraries:assistant-extensions", "path": "libraries/python/assistant-extensions" }, - { - "name": "libraries:chat-driver", - "path": "libraries/python/chat-driver" - }, { "name": "libraries:content-safety", "path": "libraries/python/content-safety" From 5d0e5a8abf5d1ad433e62680ffddf09f120259f0 Mon Sep 17 00:00:00 2001 From: Paul Payne Date: Tue, 12 Nov 2024 22:20:17 +0000 Subject: [PATCH 14/14] Removes function-registry directory. --- .../function-registry/.vscode/extensions.json | 7 - .../function-registry/.vscode/settings.json | 60 -- libraries/python/function-registry/Makefile | 2 - libraries/python/function-registry/README.md | 9 - .../python/function-registry/pyproject.toml | 32 - libraries/python/function-registry/pytest.ini | 13 - libraries/python/function-registry/uv.lock | 732 ------------------ 7 files changed, 855 deletions(-) delete mode 100644 libraries/python/function-registry/.vscode/extensions.json delete mode 100644 libraries/python/function-registry/.vscode/settings.json delete mode 100644 libraries/python/function-registry/Makefile delete mode 100644 libraries/python/function-registry/README.md delete mode 100644 libraries/python/function-registry/pyproject.toml delete mode 100644 libraries/python/function-registry/pytest.ini delete mode 100644 libraries/python/function-registry/uv.lock diff --git a/libraries/python/function-registry/.vscode/extensions.json b/libraries/python/function-registry/.vscode/extensions.json deleted file mode 100644 index 3b812215..00000000 --- a/libraries/python/function-registry/.vscode/extensions.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "recommendations": [ - "aarontamasfe.even-better-toml", - "charliermarsh.ruff", - "ms-python.python" - ] -} diff --git a/libraries/python/function-registry/.vscode/settings.json b/libraries/python/function-registry/.vscode/settings.json deleted file mode 100644 index e930c1dc..00000000 --- a/libraries/python/function-registry/.vscode/settings.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "editor.bracketPairColorization.enabled": true, - "editor.codeActionsOnSave": { - "source.fixAll": "always", - "source.organizeImports": "always" - }, - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnPaste": true, - "editor.formatOnSave": true, - "editor.formatOnType": true, - "editor.guides.bracketPairs": "active", - "files.eol": "\n", - "files.trimTrailingWhitespace": true, - "flake8.ignorePatterns": ["**/*.py"], // disable flake8 in favor of ruff - "jupyter.debugJustMyCode": false, - "python.analysis.autoFormatStrings": true, - "python.analysis.autoImportCompletions": true, - "python.analysis.diagnosticMode": "workspace", - "python.analysis.fixAll": ["source.unusedImports"], - "python.analysis.inlayHints.functionReturnTypes": true, - "python.analysis.typeCheckingMode": "basic", - "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python", - "python.testing.cwd": "${workspaceFolder}", - "python.testing.pytestArgs": ["--color", "yes"], - "python.testing.pytestEnabled": true, - "search.exclude": { - "**/.venv": true, - "**/data": true - }, - "[json]": { - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true - }, - "[jsonc]": { - "editor.defaultFormatter": "esbenp.prettier-vscode", - "editor.formatOnSave": true - }, - "[python]": { - "editor.defaultFormatter": "charliermarsh.ruff", - "editor.formatOnSave": true, - "editor.codeActionsOnSave": { - "source.fixAll": "explicit", - "source.unusedImports": "explicit", - "source.organizeImports": "explicit", - "source.formatDocument": "explicit" - } - }, - "ruff.nativeServer": "on", - "cSpell.words": [ - "dotenv", - "elts", - "httpx", - "jsonschema", - "openai", - "pydantic", - "pypdf", - "runtimes", - "tiktoken" - ] -} diff --git a/libraries/python/function-registry/Makefile b/libraries/python/function-registry/Makefile deleted file mode 100644 index 1ad4520a..00000000 --- a/libraries/python/function-registry/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -repo_root = $(shell git rev-parse --show-toplevel) -include $(repo_root)/tools/makefiles/python.mk diff --git a/libraries/python/function-registry/README.md b/libraries/python/function-registry/README.md deleted file mode 100644 index 4ad6fe6a..00000000 --- a/libraries/python/function-registry/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Function Registry - -This library contains classes and utilities helpful for managing the registration of functions to [chat drivers](../chat-driver/README.md) and [skills](../skills/skill-library/README.md). - -These other components generally need utilities such as generating JSON-Schema -of functions, converting strings into function calls, -[context](../context/README.md) passing. These are all generally useful -functions to have when working with "agentic systems" (systems using language -models). diff --git a/libraries/python/function-registry/pyproject.toml b/libraries/python/function-registry/pyproject.toml deleted file mode 100644 index 4f2d9e91..00000000 --- a/libraries/python/function-registry/pyproject.toml +++ /dev/null @@ -1,32 +0,0 @@ -[project] -name = "function-registry" -version = "0.1.0" -description = "MADE:Exploration Function Registry" -authors = [{name="MADE:Explorers"}] -readme = "README.md" -requires-python = ">=3.11" -dependencies = [ - "openai>=1.16.1", - "pydantic>=2.6.1", - "pydantic-settings>=2.3.4", - "python-dotenv>=1.0.1", - "requests>=2.32.0", - "tiktoken>=0.7.0", - "azure-identity>=1.17.1", - "context>=0.1.0", -] - -[tool.uv] -package = true -dev-dependencies = [ - "pytest>=8.3.1", - "pytest-asyncio>=0.23.8", - "pytest-repeat>=0.9.3", -] - -[tool.uv.sources] -context = { path = "../context", editable = true } - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" diff --git a/libraries/python/function-registry/pytest.ini b/libraries/python/function-registry/pytest.ini deleted file mode 100644 index 02bae23f..00000000 --- a/libraries/python/function-registry/pytest.ini +++ /dev/null @@ -1,13 +0,0 @@ -# pytest.ini -[pytest] -minversion = 6.0 -addopts = -vv -rP -pythonpath = . -testpaths = **/tests -filterwarnings = - ignore::DeprecationWarning - ignore::PendingDeprecationWarning -asyncio_mode = auto -log_cli = true -log_cli_level = INFO -log_cli_format = %(asctime)s | %(levelname)-7s | %(name)s | %(message)s diff --git a/libraries/python/function-registry/uv.lock b/libraries/python/function-registry/uv.lock deleted file mode 100644 index 4e4e8c94..00000000 --- a/libraries/python/function-registry/uv.lock +++ /dev/null @@ -1,732 +0,0 @@ -version = 1 -requires-python = ">=3.11" -resolution-markers = [ - "python_full_version < '3.13'", - "python_full_version >= '3.13'", -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, -] - -[[package]] -name = "anyio" -version = "4.6.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "sniffio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/78/49/f3f17ec11c4a91fe79275c426658e509b07547f874b14c1a526d86a83fc8/anyio-4.6.0.tar.gz", hash = "sha256:137b4559cbb034c477165047febb6ff83f390fc3b20bf181c1fc0a728cb8beeb", size = 170983 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9e/ef/7a4f225581a0d7886ea28359179cb861d7fbcdefad29663fc1167b86f69f/anyio-4.6.0-py3-none-any.whl", hash = "sha256:c7d2e9d63e31599eeb636c8c5c03a7e108d73b345f064f1c19fdc87b79036a9a", size = 89631 }, -] - -[[package]] -name = "azure-core" -version = "1.31.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "requests" }, - { name = "six" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/03/7a/f79ad135a276a37e61168495697c14ba1721a52c3eab4dae2941929c79f8/azure_core-1.31.0.tar.gz", hash = "sha256:656a0dd61e1869b1506b7c6a3b31d62f15984b1a573d6326f6aa2f3e4123284b", size = 277147 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/01/8e/fcb6a77d3029d2a7356f38dbc77cf7daa113b81ddab76b5593d23321e44c/azure_core-1.31.0-py3-none-any.whl", hash = "sha256:22954de3777e0250029360ef31d80448ef1be13b80a459bff80ba7073379e2cd", size = 197399 }, -] - -[[package]] -name = "azure-identity" -version = "1.18.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "azure-core" }, - { name = "cryptography" }, - { name = "msal" }, - { name = "msal-extensions" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b3/5d/1c7da35dd640b4a95a38f980bb6b0b56c4e91d5b3d518ac11a2c4ebf5f62/azure_identity-1.18.0.tar.gz", hash = "sha256:f567579a65d8932fa913c76eddf3305101a15e5727a5e4aa5df649a0f553d4c3", size = 263322 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b0/71/1d1bb387b6acaa5daa3e703c70dde3d54823ccd229bd6730de6e724f296e/azure_identity-1.18.0-py3-none-any.whl", hash = "sha256:bccf6106245b49ff41d0c4cd7b72851c5a2ba3a32cef7589da246f5727f26f02", size = 187179 }, -] - -[[package]] -name = "certifi" -version = "2024.8.30" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/ee/9b19140fe824b367c04c5e1b369942dd754c4c5462d5674002f75c4dedc1/certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9", size = 168507 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8", size = 167321 }, -] - -[[package]] -name = "cffi" -version = "1.17.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pycparser" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264 }, - { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651 }, - { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259 }, - { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200 }, - { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235 }, - { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721 }, - { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242 }, - { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999 }, - { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242 }, - { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604 }, - { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727 }, - { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400 }, - { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178 }, - { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840 }, - { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803 }, - { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850 }, - { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729 }, - { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256 }, - { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424 }, - { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568 }, - { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736 }, - { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448 }, - { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976 }, - { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989 }, - { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802 }, - { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792 }, - { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893 }, - { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810 }, - { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200 }, - { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447 }, - { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358 }, - { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469 }, - { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475 }, - { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009 }, -] - -[[package]] -name = "charset-normalizer" -version = "3.3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/63/09/c1bc53dab74b1816a00d8d030de5bf98f724c52c1635e07681d312f20be8/charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5", size = 104809 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/77/02839016f6fbbf808e8b38601df6e0e66c17bbab76dff4613f7511413597/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db", size = 191647 }, - { url = "https://files.pythonhosted.org/packages/3e/33/21a875a61057165e92227466e54ee076b73af1e21fe1b31f1e292251aa1e/charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96", size = 121434 }, - { url = "https://files.pythonhosted.org/packages/dd/51/68b61b90b24ca35495956b718f35a9756ef7d3dd4b3c1508056fa98d1a1b/charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e", size = 118979 }, - { url = "https://files.pythonhosted.org/packages/e4/a6/7ee57823d46331ddc37dd00749c95b0edec2c79b15fc0d6e6efb532e89ac/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f", size = 136582 }, - { url = "https://files.pythonhosted.org/packages/74/f1/0d9fe69ac441467b737ba7f48c68241487df2f4522dd7246d9426e7c690e/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574", size = 146645 }, - { url = "https://files.pythonhosted.org/packages/05/31/e1f51c76db7be1d4aef220d29fbfa5dbb4a99165d9833dcbf166753b6dc0/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4", size = 139398 }, - { url = "https://files.pythonhosted.org/packages/40/26/f35951c45070edc957ba40a5b1db3cf60a9dbb1b350c2d5bef03e01e61de/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8", size = 140273 }, - { url = "https://files.pythonhosted.org/packages/07/07/7e554f2bbce3295e191f7e653ff15d55309a9ca40d0362fcdab36f01063c/charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc", size = 142577 }, - { url = "https://files.pythonhosted.org/packages/d8/b5/eb705c313100defa57da79277d9207dc8d8e45931035862fa64b625bfead/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae", size = 137747 }, - { url = "https://files.pythonhosted.org/packages/19/28/573147271fd041d351b438a5665be8223f1dd92f273713cb882ddafe214c/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887", size = 143375 }, - { url = "https://files.pythonhosted.org/packages/cf/7c/f3b682fa053cc21373c9a839e6beba7705857075686a05c72e0f8c4980ca/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae", size = 148474 }, - { url = "https://files.pythonhosted.org/packages/1e/49/7ab74d4ac537ece3bc3334ee08645e231f39f7d6df6347b29a74b0537103/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce", size = 140232 }, - { url = "https://files.pythonhosted.org/packages/2d/dc/9dacba68c9ac0ae781d40e1a0c0058e26302ea0660e574ddf6797a0347f7/charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f", size = 140859 }, - { url = "https://files.pythonhosted.org/packages/6c/c2/4a583f800c0708dd22096298e49f887b49d9746d0e78bfc1d7e29816614c/charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab", size = 92509 }, - { url = "https://files.pythonhosted.org/packages/57/ec/80c8d48ac8b1741d5b963797b7c0c869335619e13d4744ca2f67fc11c6fc/charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77", size = 99870 }, - { url = "https://files.pythonhosted.org/packages/d1/b2/fcedc8255ec42afee97f9e6f0145c734bbe104aac28300214593eb326f1d/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8", size = 192892 }, - { url = "https://files.pythonhosted.org/packages/2e/7d/2259318c202f3d17f3fe6438149b3b9e706d1070fe3fcbb28049730bb25c/charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b", size = 122213 }, - { url = "https://files.pythonhosted.org/packages/3a/52/9f9d17c3b54dc238de384c4cb5a2ef0e27985b42a0e5cc8e8a31d918d48d/charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6", size = 119404 }, - { url = "https://files.pythonhosted.org/packages/99/b0/9c365f6d79a9f0f3c379ddb40a256a67aa69c59609608fe7feb6235896e1/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a", size = 137275 }, - { url = "https://files.pythonhosted.org/packages/91/33/749df346e93d7a30cdcb90cbfdd41a06026317bfbfb62cd68307c1a3c543/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389", size = 147518 }, - { url = "https://files.pythonhosted.org/packages/72/1a/641d5c9f59e6af4c7b53da463d07600a695b9824e20849cb6eea8a627761/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa", size = 140182 }, - { url = "https://files.pythonhosted.org/packages/ee/fb/14d30eb4956408ee3ae09ad34299131fb383c47df355ddb428a7331cfa1e/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b", size = 141869 }, - { url = "https://files.pythonhosted.org/packages/df/3e/a06b18788ca2eb6695c9b22325b6fde7dde0f1d1838b1792a0076f58fe9d/charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed", size = 144042 }, - { url = "https://files.pythonhosted.org/packages/45/59/3d27019d3b447a88fe7e7d004a1e04be220227760264cc41b405e863891b/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26", size = 138275 }, - { url = "https://files.pythonhosted.org/packages/7b/ef/5eb105530b4da8ae37d506ccfa25057961b7b63d581def6f99165ea89c7e/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d", size = 144819 }, - { url = "https://files.pythonhosted.org/packages/a2/51/e5023f937d7f307c948ed3e5c29c4b7a3e42ed2ee0b8cdf8f3a706089bf0/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068", size = 149415 }, - { url = "https://files.pythonhosted.org/packages/24/9d/2e3ef673dfd5be0154b20363c5cdcc5606f35666544381bee15af3778239/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143", size = 141212 }, - { url = "https://files.pythonhosted.org/packages/5b/ae/ce2c12fcac59cb3860b2e2d76dc405253a4475436b1861d95fe75bdea520/charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4", size = 142167 }, - { url = "https://files.pythonhosted.org/packages/ed/3a/a448bf035dce5da359daf9ae8a16b8a39623cc395a2ffb1620aa1bce62b0/charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7", size = 93041 }, - { url = "https://files.pythonhosted.org/packages/b6/7c/8debebb4f90174074b827c63242c23851bdf00a532489fba57fef3416e40/charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001", size = 100397 }, - { url = "https://files.pythonhosted.org/packages/28/76/e6222113b83e3622caa4bb41032d0b1bf785250607392e1b778aca0b8a7d/charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc", size = 48543 }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, -] - -[[package]] -name = "context" -version = "0.1.0" -source = { editable = "../context" } -dependencies = [ - { name = "events" }, -] - -[package.metadata] -requires-dist = [{ name = "events", editable = "../events" }] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - -[[package]] -name = "cryptography" -version = "43.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/de/ba/0664727028b37e249e73879348cc46d45c5c1a2a2e81e8166462953c5755/cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d", size = 686927 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/28/b92c98a04ba762f8cdeb54eba5c4c84e63cac037a7c5e70117d337b15ad6/cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d", size = 6223222 }, - { url = "https://files.pythonhosted.org/packages/33/13/1193774705783ba364121aa2a60132fa31a668b8ababd5edfa1662354ccd/cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062", size = 3794751 }, - { url = "https://files.pythonhosted.org/packages/5e/4b/39bb3c4c8cfb3e94e736b8d8859ce5c81536e91a1033b1d26770c4249000/cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962", size = 3981827 }, - { url = "https://files.pythonhosted.org/packages/ce/dc/1471d4d56608e1013237af334b8a4c35d53895694fbb73882d1c4fd3f55e/cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277", size = 3780034 }, - { url = "https://files.pythonhosted.org/packages/ad/43/7a9920135b0d5437cc2f8f529fa757431eb6a7736ddfadfdee1cc5890800/cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a", size = 3993407 }, - { url = "https://files.pythonhosted.org/packages/cc/42/9ab8467af6c0b76f3d9b8f01d1cf25b9c9f3f2151f4acfab888d21c55a72/cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042", size = 3886457 }, - { url = "https://files.pythonhosted.org/packages/a4/65/430509e31700286ec02868a2457d2111d03ccefc20349d24e58d171ae0a7/cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494", size = 4081499 }, - { url = "https://files.pythonhosted.org/packages/bb/18/a04b6467e6e09df8c73b91dcee8878f4a438a43a3603dc3cd6f8003b92d8/cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2", size = 2616504 }, - { url = "https://files.pythonhosted.org/packages/cc/73/0eacbdc437202edcbdc07f3576ed8fb8b0ab79d27bf2c5d822d758a72faa/cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d", size = 3067456 }, - { url = "https://files.pythonhosted.org/packages/8a/b6/bc54b371f02cffd35ff8dc6baba88304d7cf8e83632566b4b42e00383e03/cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d", size = 6225263 }, - { url = "https://files.pythonhosted.org/packages/00/0e/8217e348a1fa417ec4c78cd3cdf24154f5e76fd7597343a35bd403650dfd/cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806", size = 3794368 }, - { url = "https://files.pythonhosted.org/packages/3d/ed/38b6be7254d8f7251fde8054af597ee8afa14f911da67a9410a45f602fc3/cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85", size = 3981750 }, - { url = "https://files.pythonhosted.org/packages/64/f3/b7946c3887cf7436f002f4cbb1e6aec77b8d299b86be48eeadfefb937c4b/cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c", size = 3778925 }, - { url = "https://files.pythonhosted.org/packages/ac/7e/ebda4dd4ae098a0990753efbb4b50954f1d03003846b943ea85070782da7/cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1", size = 3993152 }, - { url = "https://files.pythonhosted.org/packages/43/f6/feebbd78a3e341e3913846a3bb2c29d0b09b1b3af1573c6baabc2533e147/cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa", size = 3886392 }, - { url = "https://files.pythonhosted.org/packages/bd/4c/ab0b9407d5247576290b4fd8abd06b7f51bd414f04eef0f2800675512d61/cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4", size = 4082606 }, - { url = "https://files.pythonhosted.org/packages/05/36/e532a671998d6fcfdb9122da16434347a58a6bae9465e527e450e0bc60a5/cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47", size = 2617948 }, - { url = "https://files.pythonhosted.org/packages/b3/c6/c09cee6968add5ff868525c3815e5dccc0e3c6e89eec58dc9135d3c40e88/cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb", size = 3070445 }, -] - -[[package]] -name = "distro" -version = "1.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277 }, -] - -[[package]] -name = "events" -version = "0.1.0" -source = { editable = "../events" } -dependencies = [ - { name = "pydantic" }, -] - -[package.metadata] -requires-dist = [{ name = "pydantic", specifier = ">=2.6.1" }] - -[[package]] -name = "function-registry" -version = "0.1.0" -source = { editable = "." } -dependencies = [ - { name = "azure-identity" }, - { name = "context" }, - { name = "openai" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "requests" }, - { name = "tiktoken" }, -] - -[package.dev-dependencies] -dev = [ - { name = "pytest" }, - { name = "pytest-asyncio" }, - { name = "pytest-repeat" }, -] - -[package.metadata] -requires-dist = [ - { name = "azure-identity", specifier = ">=1.17.1" }, - { name = "context", editable = "../context" }, - { name = "openai", specifier = ">=1.16.1" }, - { name = "pydantic", specifier = ">=2.6.1" }, - { name = "pydantic-settings", specifier = ">=2.3.4" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "requests", specifier = ">=2.32.0" }, - { name = "tiktoken", specifier = ">=0.7.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.1" }, - { name = "pytest-asyncio", specifier = ">=0.23.8" }, - { name = "pytest-repeat", specifier = ">=0.9.3" }, -] - -[[package]] -name = "h11" -version = "0.14.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 }, -] - -[[package]] -name = "httpcore" -version = "1.0.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b6/44/ed0fa6a17845fb033bd885c03e842f08c1b9406c86a2e60ac1ae1b9206a6/httpcore-1.0.6.tar.gz", hash = "sha256:73f6dbd6eb8c21bbf7ef8efad555481853f5f6acdeaff1edb0694289269ee17f", size = 85180 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/06/89/b161908e2f51be56568184aeb4a880fd287178d176fd1c860d2217f41106/httpcore-1.0.6-py3-none-any.whl", hash = "sha256:27b59625743b85577a8c0e10e55b50b5368a4f2cfe8cc7bcfa9cf00829c2682f", size = 78011 }, -] - -[[package]] -name = "httpx" -version = "0.27.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, - { name = "sniffio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/78/82/08f8c936781f67d9e6b9eeb8a0c8b4e406136ea4c3d1f89a5db71d42e0e6/httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2", size = 144189 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0", size = 76395 }, -] - -[[package]] -name = "idna" -version = "3.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, -] - -[[package]] -name = "iniconfig" -version = "2.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 }, -] - -[[package]] -name = "jiter" -version = "0.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d7/1a/aa64be757afc614484b370a4d9fc1747dc9237b37ce464f7f9d9ca2a3d38/jiter-0.5.0.tar.gz", hash = "sha256:1d916ba875bcab5c5f7d927df998c4cb694d27dceddf3392e58beaf10563368a", size = 158300 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/5f/3ac960ed598726aae46edea916e6df4df7ff6fe084bc60774b95cf3154e6/jiter-0.5.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d4c8e1ed0ef31ad29cae5ea16b9e41529eb50a7fba70600008e9f8de6376d553", size = 284131 }, - { url = "https://files.pythonhosted.org/packages/03/eb/2308fa5f5c14c97c4c7720fef9465f1fa0771826cddb4eec9866bdd88846/jiter-0.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6f16e21276074a12d8421692515b3fd6d2ea9c94fd0734c39a12960a20e85f3", size = 299310 }, - { url = "https://files.pythonhosted.org/packages/3c/f6/dba34ca10b44715fa5302b8e8d2113f72eb00a9297ddf3fa0ae4fd22d1d1/jiter-0.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5280e68e7740c8c128d3ae5ab63335ce6d1fb6603d3b809637b11713487af9e6", size = 332282 }, - { url = "https://files.pythonhosted.org/packages/69/f7/64e0a7439790ec47f7681adb3871c9d9c45fff771102490bbee5e92c00b7/jiter-0.5.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:583c57fc30cc1fec360e66323aadd7fc3edeec01289bfafc35d3b9dcb29495e4", size = 342370 }, - { url = "https://files.pythonhosted.org/packages/55/31/1efbfff2ae8e4d919144c53db19b828049ad0622a670be3bbea94a86282c/jiter-0.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26351cc14507bdf466b5f99aba3df3143a59da75799bf64a53a3ad3155ecded9", size = 363591 }, - { url = "https://files.pythonhosted.org/packages/30/c3/7ab2ca2276426a7398c6dfb651e38dbc81954c79a3bfbc36c514d8599499/jiter-0.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4829df14d656b3fb87e50ae8b48253a8851c707da9f30d45aacab2aa2ba2d614", size = 378551 }, - { url = "https://files.pythonhosted.org/packages/47/e7/5d88031cd743c62199b125181a591b1671df3ff2f6e102df85c58d8f7d31/jiter-0.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a42a4bdcf7307b86cb863b2fb9bb55029b422d8f86276a50487982d99eed7c6e", size = 319152 }, - { url = "https://files.pythonhosted.org/packages/4c/2d/09ea58e1adca9f0359f3d41ef44a1a18e59518d7c43a21f4ece9e72e28c0/jiter-0.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04d461ad0aebf696f8da13c99bc1b3e06f66ecf6cfd56254cc402f6385231c06", size = 357377 }, - { url = "https://files.pythonhosted.org/packages/7d/2f/83ff1058cb56fc3ff73e0d3c6440703ddc9cdb7f759b00cfbde8228fc435/jiter-0.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e6375923c5f19888c9226582a124b77b622f8fd0018b843c45eeb19d9701c403", size = 511091 }, - { url = "https://files.pythonhosted.org/packages/ae/c9/4f85f97c9894382ab457382337aea0012711baaa17f2ed55c0ff25f3668a/jiter-0.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2cec323a853c24fd0472517113768c92ae0be8f8c384ef4441d3632da8baa646", size = 492948 }, - { url = "https://files.pythonhosted.org/packages/4d/f2/2e987e0eb465e064c5f52c2f29c8d955452e3b316746e326269263bfb1b7/jiter-0.5.0-cp311-none-win32.whl", hash = "sha256:aa1db0967130b5cab63dfe4d6ff547c88b2a394c3410db64744d491df7f069bb", size = 195183 }, - { url = "https://files.pythonhosted.org/packages/ab/59/05d1c3203c349b37c4dd28b02b9b4e5915a7bcbd9319173b4548a67d2e93/jiter-0.5.0-cp311-none-win_amd64.whl", hash = "sha256:aa9d2b85b2ed7dc7697597dcfaac66e63c1b3028652f751c81c65a9f220899ae", size = 191032 }, - { url = "https://files.pythonhosted.org/packages/aa/bd/c3950e2c478161e131bed8cb67c36aed418190e2a961a1c981e69954e54b/jiter-0.5.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9f664e7351604f91dcdd557603c57fc0d551bc65cc0a732fdacbf73ad335049a", size = 283511 }, - { url = "https://files.pythonhosted.org/packages/80/1c/8ce58d8c37a589eeaaa5d07d131fd31043886f5e77ab50c00a66d869a361/jiter-0.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:044f2f1148b5248ad2c8c3afb43430dccf676c5a5834d2f5089a4e6c5bbd64df", size = 296974 }, - { url = "https://files.pythonhosted.org/packages/4d/b8/6faeff9eed8952bed93a77ea1cffae7b946795b88eafd1a60e87a67b09e0/jiter-0.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:702e3520384c88b6e270c55c772d4bd6d7b150608dcc94dea87ceba1b6391248", size = 331897 }, - { url = "https://files.pythonhosted.org/packages/4f/54/1d9a2209b46d39ce6f0cef3ad87c462f9c50312ab84585e6bd5541292b35/jiter-0.5.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:528d742dcde73fad9d63e8242c036ab4a84389a56e04efd854062b660f559544", size = 342962 }, - { url = "https://files.pythonhosted.org/packages/2a/de/90360be7fc54b2b4c2dfe79eb4ed1f659fce9c96682e6a0be4bbe71371f7/jiter-0.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8cf80e5fe6ab582c82f0c3331df27a7e1565e2dcf06265afd5173d809cdbf9ba", size = 363844 }, - { url = "https://files.pythonhosted.org/packages/ba/ad/ef32b173191b7a53ea8a6757b80723cba321f8469834825e8c71c96bde17/jiter-0.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:44dfc9ddfb9b51a5626568ef4e55ada462b7328996294fe4d36de02fce42721f", size = 378709 }, - { url = "https://files.pythonhosted.org/packages/07/de/353ce53743c0defbbbd652e89c106a97dbbac4eb42c95920b74b5056b93a/jiter-0.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c451f7922992751a936b96c5f5b9bb9312243d9b754c34b33d0cb72c84669f4e", size = 319038 }, - { url = "https://files.pythonhosted.org/packages/3f/92/42d47310bf9530b9dece9e2d7c6d51cf419af5586ededaf5e66622d160e2/jiter-0.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:308fce789a2f093dca1ff91ac391f11a9f99c35369117ad5a5c6c4903e1b3e3a", size = 357763 }, - { url = "https://files.pythonhosted.org/packages/bd/8c/2bb76a9a84474d48fdd133d3445db8a4413da4e87c23879d917e000a9d87/jiter-0.5.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7f5ad4a7c6b0d90776fdefa294f662e8a86871e601309643de30bf94bb93a64e", size = 511031 }, - { url = "https://files.pythonhosted.org/packages/33/4f/9f23d79c0795e0a8e56e7988e8785c2dcda27e0ed37977256d50c77c6a19/jiter-0.5.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ea189db75f8eca08807d02ae27929e890c7d47599ce3d0a6a5d41f2419ecf338", size = 493042 }, - { url = "https://files.pythonhosted.org/packages/df/67/8a4f975aa834b8aecdb6b131422390173928fd47f42f269dcc32034ab432/jiter-0.5.0-cp312-none-win32.whl", hash = "sha256:e3bbe3910c724b877846186c25fe3c802e105a2c1fc2b57d6688b9f8772026e4", size = 195405 }, - { url = "https://files.pythonhosted.org/packages/15/81/296b1e25c43db67848728cdab34ac3eb5c5cbb4955ceb3f51ae60d4a5e3d/jiter-0.5.0-cp312-none-win_amd64.whl", hash = "sha256:a586832f70c3f1481732919215f36d41c59ca080fa27a65cf23d9490e75b2ef5", size = 189720 }, -] - -[[package]] -name = "msal" -version = "1.31.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cryptography" }, - { name = "pyjwt", extra = ["crypto"] }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/59/04/8d7aa5c671a26ca5612257fd419f97380ba89cdd231b2eb67df58483796d/msal-1.31.0.tar.gz", hash = "sha256:2c4f189cf9cc8f00c80045f66d39b7c0f3ed45873fd3d1f2af9f22db2e12ff4b", size = 144950 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cd/40/0a5d743484e1ad00493bdffa8d10d7dbc6a51fec95290ad396e47e79fa43/msal-1.31.0-py3-none-any.whl", hash = "sha256:96bc37cff82ebe4b160d5fc0f1196f6ca8b50e274ecd0ec5bf69c438514086e7", size = 113109 }, -] - -[[package]] -name = "msal-extensions" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "msal" }, - { name = "portalocker" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2d/38/ad49272d0a5af95f7a0cb64a79bbd75c9c187f3b789385a143d8d537a5eb/msal_extensions-1.2.0.tar.gz", hash = "sha256:6f41b320bfd2933d631a215c91ca0dd3e67d84bd1a2f50ce917d5874ec646bef", size = 22391 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2c/69/314d887a01599669fb330da14e5c6ff5f138609e322812a942a74ef9b765/msal_extensions-1.2.0-py3-none-any.whl", hash = "sha256:cf5ba83a2113fa6dc011a254a72f1c223c88d7dfad74cc30617c4679a417704d", size = 19254 }, -] - -[[package]] -name = "openai" -version = "1.51.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "distro" }, - { name = "httpx" }, - { name = "jiter" }, - { name = "pydantic" }, - { name = "sniffio" }, - { name = "tqdm" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/28/af/cc59b1447f5a02bb1f25b9b0cd94b607aa2c969a81d9a244d4067f91f6fe/openai-1.51.0.tar.gz", hash = "sha256:8dc4f9d75ccdd5466fc8c99a952186eddceb9fd6ba694044773f3736a847149d", size = 306880 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/08/9f22356d4fbd273f734db1e6663b7ca6987943080567f5580471022e57ca/openai-1.51.0-py3-none-any.whl", hash = "sha256:d9affafb7e51e5a27dce78589d4964ce4d6f6d560307265933a94b2e3f3c5d2c", size = 383533 }, -] - -[[package]] -name = "packaging" -version = "24.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/51/65/50db4dda066951078f0a96cf12f4b9ada6e4b811516bf0262c0f4f7064d4/packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", size = 148788 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/08/aa/cc0199a5f0ad350994d660967a8efb233fe0416e4639146c089643407ce6/packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124", size = 53985 }, -] - -[[package]] -name = "pluggy" -version = "1.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, -] - -[[package]] -name = "portalocker" -version = "2.10.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pywin32", marker = "platform_system == 'Windows'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ed/d3/c6c64067759e87af98cc668c1cc75171347d0f1577fab7ca3749134e3cd4/portalocker-2.10.1.tar.gz", hash = "sha256:ef1bf844e878ab08aee7e40184156e1151f228f103aa5c6bd0724cc330960f8f", size = 40891 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/fb/a70a4214956182e0d7a9099ab17d50bfcba1056188e9b14f35b9e2b62a0d/portalocker-2.10.1-py3-none-any.whl", hash = "sha256:53a5984ebc86a025552264b459b46a2086e269b21823cb572f8f28ee759e45bf", size = 18423 }, -] - -[[package]] -name = "pycparser" -version = "2.22" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, -] - -[[package]] -name = "pydantic" -version = "2.9.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a9/b7/d9e3f12af310e1120c21603644a1cd86f59060e040ec5c3a80b8f05fae30/pydantic-2.9.2.tar.gz", hash = "sha256:d155cef71265d1e9807ed1c32b4c8deec042a44a50a4188b25ac67ecd81a9c0f", size = 769917 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/df/e4/ba44652d562cbf0bf320e0f3810206149c8a4e99cdbf66da82e97ab53a15/pydantic-2.9.2-py3-none-any.whl", hash = "sha256:f048cec7b26778210e28a0459867920654d48e5e62db0958433636cde4254f12", size = 434928 }, -] - -[[package]] -name = "pydantic-core" -version = "2.23.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e2/aa/6b6a9b9f8537b872f552ddd46dd3da230367754b6f707b8e1e963f515ea3/pydantic_core-2.23.4.tar.gz", hash = "sha256:2584f7cf844ac4d970fba483a717dbe10c1c1c96a969bf65d61ffe94df1b2863", size = 402156 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5d/30/890a583cd3f2be27ecf32b479d5d615710bb926d92da03e3f7838ff3e58b/pydantic_core-2.23.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:77733e3892bb0a7fa797826361ce8a9184d25c8dffaec60b7ffe928153680ba8", size = 1865160 }, - { url = "https://files.pythonhosted.org/packages/1d/9a/b634442e1253bc6889c87afe8bb59447f106ee042140bd57680b3b113ec7/pydantic_core-2.23.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b84d168f6c48fabd1f2027a3d1bdfe62f92cade1fb273a5d68e621da0e44e6d", size = 1776777 }, - { url = "https://files.pythonhosted.org/packages/75/9a/7816295124a6b08c24c96f9ce73085032d8bcbaf7e5a781cd41aa910c891/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df49e7a0861a8c36d089c1ed57d308623d60416dab2647a4a17fe050ba85de0e", size = 1799244 }, - { url = "https://files.pythonhosted.org/packages/a9/8f/89c1405176903e567c5f99ec53387449e62f1121894aa9fc2c4fdc51a59b/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff02b6d461a6de369f07ec15e465a88895f3223eb75073ffea56b84d9331f607", size = 1805307 }, - { url = "https://files.pythonhosted.org/packages/d5/a5/1a194447d0da1ef492e3470680c66048fef56fc1f1a25cafbea4bc1d1c48/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:996a38a83508c54c78a5f41456b0103c30508fed9abcad0a59b876d7398f25fd", size = 2000663 }, - { url = "https://files.pythonhosted.org/packages/13/a5/1df8541651de4455e7d587cf556201b4f7997191e110bca3b589218745a5/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d97683ddee4723ae8c95d1eddac7c192e8c552da0c73a925a89fa8649bf13eea", size = 2655941 }, - { url = "https://files.pythonhosted.org/packages/44/31/a3899b5ce02c4316865e390107f145089876dff7e1dfc770a231d836aed8/pydantic_core-2.23.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:216f9b2d7713eb98cb83c80b9c794de1f6b7e3145eef40400c62e86cee5f4e1e", size = 2052105 }, - { url = "https://files.pythonhosted.org/packages/1b/aa/98e190f8745d5ec831f6d5449344c48c0627ac5fed4e5340a44b74878f8e/pydantic_core-2.23.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6f783e0ec4803c787bcea93e13e9932edab72068f68ecffdf86a99fd5918878b", size = 1919967 }, - { url = "https://files.pythonhosted.org/packages/ae/35/b6e00b6abb2acfee3e8f85558c02a0822e9a8b2f2d812ea8b9079b118ba0/pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d0776dea117cf5272382634bd2a5c1b6eb16767c223c6a5317cd3e2a757c61a0", size = 1964291 }, - { url = "https://files.pythonhosted.org/packages/13/46/7bee6d32b69191cd649bbbd2361af79c472d72cb29bb2024f0b6e350ba06/pydantic_core-2.23.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d5f7a395a8cf1621939692dba2a6b6a830efa6b3cee787d82c7de1ad2930de64", size = 2109666 }, - { url = "https://files.pythonhosted.org/packages/39/ef/7b34f1b122a81b68ed0a7d0e564da9ccdc9a2924c8d6c6b5b11fa3a56970/pydantic_core-2.23.4-cp311-none-win32.whl", hash = "sha256:74b9127ffea03643e998e0c5ad9bd3811d3dac8c676e47db17b0ee7c3c3bf35f", size = 1732940 }, - { url = "https://files.pythonhosted.org/packages/2f/76/37b7e76c645843ff46c1d73e046207311ef298d3f7b2f7d8f6ac60113071/pydantic_core-2.23.4-cp311-none-win_amd64.whl", hash = "sha256:98d134c954828488b153d88ba1f34e14259284f256180ce659e8d83e9c05eaa3", size = 1916804 }, - { url = "https://files.pythonhosted.org/packages/74/7b/8e315f80666194b354966ec84b7d567da77ad927ed6323db4006cf915f3f/pydantic_core-2.23.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f3e0da4ebaef65158d4dfd7d3678aad692f7666877df0002b8a522cdf088f231", size = 1856459 }, - { url = "https://files.pythonhosted.org/packages/14/de/866bdce10ed808323d437612aca1ec9971b981e1c52e5e42ad9b8e17a6f6/pydantic_core-2.23.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f69a8e0b033b747bb3e36a44e7732f0c99f7edd5cea723d45bc0d6e95377ffee", size = 1770007 }, - { url = "https://files.pythonhosted.org/packages/dc/69/8edd5c3cd48bb833a3f7ef9b81d7666ccddd3c9a635225214e044b6e8281/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:723314c1d51722ab28bfcd5240d858512ffd3116449c557a1336cbe3919beb87", size = 1790245 }, - { url = "https://files.pythonhosted.org/packages/80/33/9c24334e3af796ce80d2274940aae38dd4e5676298b4398eff103a79e02d/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bb2802e667b7051a1bebbfe93684841cc9351004e2badbd6411bf357ab8d5ac8", size = 1801260 }, - { url = "https://files.pythonhosted.org/packages/a5/6f/e9567fd90104b79b101ca9d120219644d3314962caa7948dd8b965e9f83e/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d18ca8148bebe1b0a382a27a8ee60350091a6ddaf475fa05ef50dc35b5df6327", size = 1996872 }, - { url = "https://files.pythonhosted.org/packages/2d/ad/b5f0fe9e6cfee915dd144edbd10b6e9c9c9c9d7a56b69256d124b8ac682e/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33e3d65a85a2a4a0dc3b092b938a4062b1a05f3a9abde65ea93b233bca0e03f2", size = 2661617 }, - { url = "https://files.pythonhosted.org/packages/06/c8/7d4b708f8d05a5cbfda3243aad468052c6e99de7d0937c9146c24d9f12e9/pydantic_core-2.23.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:128585782e5bfa515c590ccee4b727fb76925dd04a98864182b22e89a4e6ed36", size = 2071831 }, - { url = "https://files.pythonhosted.org/packages/89/4d/3079d00c47f22c9a9a8220db088b309ad6e600a73d7a69473e3a8e5e3ea3/pydantic_core-2.23.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:68665f4c17edcceecc112dfed5dbe6f92261fb9d6054b47d01bf6371a6196126", size = 1917453 }, - { url = "https://files.pythonhosted.org/packages/e9/88/9df5b7ce880a4703fcc2d76c8c2d8eb9f861f79d0c56f4b8f5f2607ccec8/pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:20152074317d9bed6b7a95ade3b7d6054845d70584216160860425f4fbd5ee9e", size = 1968793 }, - { url = "https://files.pythonhosted.org/packages/e3/b9/41f7efe80f6ce2ed3ee3c2dcfe10ab7adc1172f778cc9659509a79518c43/pydantic_core-2.23.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9261d3ce84fa1d38ed649c3638feefeae23d32ba9182963e465d58d62203bd24", size = 2116872 }, - { url = "https://files.pythonhosted.org/packages/63/08/b59b7a92e03dd25554b0436554bf23e7c29abae7cce4b1c459cd92746811/pydantic_core-2.23.4-cp312-none-win32.whl", hash = "sha256:4ba762ed58e8d68657fc1281e9bb72e1c3e79cc5d464be146e260c541ec12d84", size = 1738535 }, - { url = "https://files.pythonhosted.org/packages/88/8d/479293e4d39ab409747926eec4329de5b7129beaedc3786eca070605d07f/pydantic_core-2.23.4-cp312-none-win_amd64.whl", hash = "sha256:97df63000f4fea395b2824da80e169731088656d1818a11b95f3b173747b6cd9", size = 1917992 }, - { url = "https://files.pythonhosted.org/packages/ad/ef/16ee2df472bf0e419b6bc68c05bf0145c49247a1095e85cee1463c6a44a1/pydantic_core-2.23.4-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7530e201d10d7d14abce4fb54cfe5b94a0aefc87da539d0346a484ead376c3cc", size = 1856143 }, - { url = "https://files.pythonhosted.org/packages/da/fa/bc3dbb83605669a34a93308e297ab22be82dfb9dcf88c6cf4b4f264e0a42/pydantic_core-2.23.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:df933278128ea1cd77772673c73954e53a1c95a4fdf41eef97c2b779271bd0bd", size = 1770063 }, - { url = "https://files.pythonhosted.org/packages/4e/48/e813f3bbd257a712303ebdf55c8dc46f9589ec74b384c9f652597df3288d/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cb3da3fd1b6a5d0279a01877713dbda118a2a4fc6f0d821a57da2e464793f05", size = 1790013 }, - { url = "https://files.pythonhosted.org/packages/b4/e0/56eda3a37929a1d297fcab1966db8c339023bcca0b64c5a84896db3fcc5c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42c6dcb030aefb668a2b7009c85b27f90e51e6a3b4d5c9bc4c57631292015b0d", size = 1801077 }, - { url = "https://files.pythonhosted.org/packages/04/be/5e49376769bfbf82486da6c5c1683b891809365c20d7c7e52792ce4c71f3/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:696dd8d674d6ce621ab9d45b205df149399e4bb9aa34102c970b721554828510", size = 1996782 }, - { url = "https://files.pythonhosted.org/packages/bc/24/e3ee6c04f1d58cc15f37bcc62f32c7478ff55142b7b3e6d42ea374ea427c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2971bb5ffe72cc0f555c13e19b23c85b654dd2a8f7ab493c262071377bfce9f6", size = 2661375 }, - { url = "https://files.pythonhosted.org/packages/c1/f8/11a9006de4e89d016b8de74ebb1db727dc100608bb1e6bbe9d56a3cbbcce/pydantic_core-2.23.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8394d940e5d400d04cad4f75c0598665cbb81aecefaca82ca85bd28264af7f9b", size = 2071635 }, - { url = "https://files.pythonhosted.org/packages/7c/45/bdce5779b59f468bdf262a5bc9eecbae87f271c51aef628d8c073b4b4b4c/pydantic_core-2.23.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0dff76e0602ca7d4cdaacc1ac4c005e0ce0dcfe095d5b5259163a80d3a10d327", size = 1916994 }, - { url = "https://files.pythonhosted.org/packages/d8/fa/c648308fe711ee1f88192cad6026ab4f925396d1293e8356de7e55be89b5/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7d32706badfe136888bdea71c0def994644e09fff0bfe47441deaed8e96fdbc6", size = 1968877 }, - { url = "https://files.pythonhosted.org/packages/16/16/b805c74b35607d24d37103007f899abc4880923b04929547ae68d478b7f4/pydantic_core-2.23.4-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ed541d70698978a20eb63d8c5d72f2cc6d7079d9d90f6b50bad07826f1320f5f", size = 2116814 }, - { url = "https://files.pythonhosted.org/packages/d1/58/5305e723d9fcdf1c5a655e6a4cc2a07128bf644ff4b1d98daf7a9dbf57da/pydantic_core-2.23.4-cp313-none-win32.whl", hash = "sha256:3d5639516376dce1940ea36edf408c554475369f5da2abd45d44621cb616f769", size = 1738360 }, - { url = "https://files.pythonhosted.org/packages/a5/ae/e14b0ff8b3f48e02394d8acd911376b7b66e164535687ef7dc24ea03072f/pydantic_core-2.23.4-cp313-none-win_amd64.whl", hash = "sha256:5a1504ad17ba4210df3a045132a7baeeba5a200e930f57512ee02909fc5c4cb5", size = 1919411 }, -] - -[[package]] -name = "pydantic-settings" -version = "2.5.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/68/27/0bed9dd26b93328b60a1402febc780e7be72b42847fa8b5c94b7d0aeb6d1/pydantic_settings-2.5.2.tar.gz", hash = "sha256:f90b139682bee4d2065273d5185d71d37ea46cfe57e1b5ae184fc6a0b2484ca0", size = 70938 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/29/8d/29e82e333f32d9e2051c10764b906c2a6cd140992910b5f49762790911ba/pydantic_settings-2.5.2-py3-none-any.whl", hash = "sha256:2c912e55fd5794a59bf8c832b9de832dcfdf4778d79ff79b708744eed499a907", size = 26864 }, -] - -[[package]] -name = "pyjwt" -version = "2.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fb/68/ce067f09fca4abeca8771fe667d89cc347d1e99da3e093112ac329c6020e/pyjwt-2.9.0.tar.gz", hash = "sha256:7e1e5b56cc735432a7369cbfa0efe50fa113ebecdc04ae6922deba8b84582d0c", size = 78825 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/84/0fdf9b18ba31d69877bd39c9cd6052b47f3761e9910c15de788e519f079f/PyJWT-2.9.0-py3-none-any.whl", hash = "sha256:3b02fb0f44517787776cf48f2ae25d8e14f300e6d7545a4315cee571a415e850", size = 22344 }, -] - -[package.optional-dependencies] -crypto = [ - { name = "cryptography" }, -] - -[[package]] -name = "pytest" -version = "8.3.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "iniconfig" }, - { name = "packaging" }, - { name = "pluggy" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/8b/6c/62bbd536103af674e227c41a8f3dcd022d591f6eed5facb5a0f31ee33bbc/pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181", size = 1442487 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/77/7440a06a8ead44c7757a64362dd22df5760f9b12dc5f11b6188cd2fc27a0/pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2", size = 342341 }, -] - -[[package]] -name = "pytest-asyncio" -version = "0.24.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pytest" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/52/6d/c6cf50ce320cf8611df7a1254d86233b3df7cc07f9b5f5cbcb82e08aa534/pytest_asyncio-0.24.0.tar.gz", hash = "sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276", size = 49855 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/96/31/6607dab48616902f76885dfcf62c08d929796fc3b2d2318faf9fd54dbed9/pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b", size = 18024 }, -] - -[[package]] -name = "pytest-repeat" -version = "0.9.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pytest" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/86/5e/99365eb229efff0b1bd475886150fc6db9937ab7e1bd21f6f65c1279e0eb/pytest_repeat-0.9.3.tar.gz", hash = "sha256:ffd3836dfcd67bb270bec648b330e20be37d2966448c4148c4092d1e8aba8185", size = 6272 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/49/a8/0a0aec0c2541b8baf4a0b95af2ba99abce217ee43534adf9cb7c908cf184/pytest_repeat-0.9.3-py3-none-any.whl", hash = "sha256:26ab2df18226af9d5ce441c858f273121e92ff55f5bb311d25755b8d7abdd8ed", size = 4196 }, -] - -[[package]] -name = "python-dotenv" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 }, -] - -[[package]] -name = "pywin32" -version = "306" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/1e/fc18ad83ca553e01b97aa8393ff10e33c1fb57801db05488b83282ee9913/pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407", size = 8507689 }, - { url = "https://files.pythonhosted.org/packages/7e/9e/ad6b1ae2a5ad1066dc509350e0fbf74d8d50251a51e420a2a8feaa0cecbd/pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e", size = 9227547 }, - { url = "https://files.pythonhosted.org/packages/91/20/f744bff1da8f43388498503634378dbbefbe493e65675f2cc52f7185c2c2/pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a", size = 10388324 }, - { url = "https://files.pythonhosted.org/packages/14/91/17e016d5923e178346aabda3dfec6629d1a26efe587d19667542105cf0a6/pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b", size = 8507705 }, - { url = "https://files.pythonhosted.org/packages/83/1c/25b79fc3ec99b19b0a0730cc47356f7e2959863bf9f3cd314332bddb4f68/pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e", size = 9227429 }, - { url = "https://files.pythonhosted.org/packages/1c/43/e3444dc9a12f8365d9603c2145d16bf0a2f8180f343cf87be47f5579e547/pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040", size = 10388145 }, -] - -[[package]] -name = "regex" -version = "2024.9.11" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f9/38/148df33b4dbca3bd069b963acab5e0fa1a9dbd6820f8c322d0dd6faeff96/regex-2024.9.11.tar.gz", hash = "sha256:6c188c307e8433bcb63dc1915022deb553b4203a70722fc542c363bf120a01fd", size = 399403 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/86/a1/d526b7b6095a0019aa360948c143aacfeb029919c898701ce7763bbe4c15/regex-2024.9.11-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2cce2449e5927a0bf084d346da6cd5eb016b2beca10d0013ab50e3c226ffc0df", size = 482483 }, - { url = "https://files.pythonhosted.org/packages/32/d9/bfdd153179867c275719e381e1e8e84a97bd186740456a0dcb3e7125c205/regex-2024.9.11-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3b37fa423beefa44919e009745ccbf353d8c981516e807995b2bd11c2c77d268", size = 287442 }, - { url = "https://files.pythonhosted.org/packages/33/c4/60f3370735135e3a8d673ddcdb2507a8560d0e759e1398d366e43d000253/regex-2024.9.11-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:64ce2799bd75039b480cc0360907c4fb2f50022f030bf9e7a8705b636e408fad", size = 284561 }, - { url = "https://files.pythonhosted.org/packages/b1/51/91a5ebdff17f9ec4973cb0aa9d37635efec1c6868654bbc25d1543aca4ec/regex-2024.9.11-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4cc92bb6db56ab0c1cbd17294e14f5e9224f0cc6521167ef388332604e92679", size = 791779 }, - { url = "https://files.pythonhosted.org/packages/07/4a/022c5e6f0891a90cd7eb3d664d6c58ce2aba48bff107b00013f3d6167069/regex-2024.9.11-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d05ac6fa06959c4172eccd99a222e1fbf17b5670c4d596cb1e5cde99600674c4", size = 832605 }, - { url = "https://files.pythonhosted.org/packages/ac/1c/3793990c8c83ca04e018151ddda83b83ecc41d89964f0f17749f027fc44d/regex-2024.9.11-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:040562757795eeea356394a7fb13076ad4f99d3c62ab0f8bdfb21f99a1f85664", size = 818556 }, - { url = "https://files.pythonhosted.org/packages/e9/5c/8b385afbfacb853730682c57be56225f9fe275c5bf02ac1fc88edbff316d/regex-2024.9.11-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6113c008a7780792efc80f9dfe10ba0cd043cbf8dc9a76ef757850f51b4edc50", size = 792808 }, - { url = "https://files.pythonhosted.org/packages/9b/8b/a4723a838b53c771e9240951adde6af58c829fb6a6a28f554e8131f53839/regex-2024.9.11-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8e5fb5f77c8745a60105403a774fe2c1759b71d3e7b4ca237a5e67ad066c7199", size = 781115 }, - { url = "https://files.pythonhosted.org/packages/83/5f/031a04b6017033d65b261259c09043c06f4ef2d4eac841d0649d76d69541/regex-2024.9.11-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:54d9ff35d4515debf14bc27f1e3b38bfc453eff3220f5bce159642fa762fe5d4", size = 778155 }, - { url = "https://files.pythonhosted.org/packages/fd/cd/4660756070b03ce4a66663a43f6c6e7ebc2266cc6b4c586c167917185eb4/regex-2024.9.11-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:df5cbb1fbc74a8305b6065d4ade43b993be03dbe0f8b30032cced0d7740994bd", size = 784614 }, - { url = "https://files.pythonhosted.org/packages/93/8d/65b9bea7df120a7be8337c415b6d256ba786cbc9107cebba3bf8ff09da99/regex-2024.9.11-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:7fb89ee5d106e4a7a51bce305ac4efb981536301895f7bdcf93ec92ae0d91c7f", size = 853744 }, - { url = "https://files.pythonhosted.org/packages/96/a7/fba1eae75eb53a704475baf11bd44b3e6ccb95b316955027eb7748f24ef8/regex-2024.9.11-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a738b937d512b30bf75995c0159c0ddf9eec0775c9d72ac0202076c72f24aa96", size = 855890 }, - { url = "https://files.pythonhosted.org/packages/45/14/d864b2db80a1a3358534392373e8a281d95b28c29c87d8548aed58813910/regex-2024.9.11-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e28f9faeb14b6f23ac55bfbbfd3643f5c7c18ede093977f1df249f73fd22c7b1", size = 781887 }, - { url = "https://files.pythonhosted.org/packages/4d/a9/bfb29b3de3eb11dc9b412603437023b8e6c02fb4e11311863d9bf62c403a/regex-2024.9.11-cp311-cp311-win32.whl", hash = "sha256:18e707ce6c92d7282dfce370cd205098384b8ee21544e7cb29b8aab955b66fa9", size = 261644 }, - { url = "https://files.pythonhosted.org/packages/c7/ab/1ad2511cf6a208fde57fafe49829cab8ca018128ab0d0b48973d8218634a/regex-2024.9.11-cp311-cp311-win_amd64.whl", hash = "sha256:313ea15e5ff2a8cbbad96ccef6be638393041b0a7863183c2d31e0c6116688cf", size = 274033 }, - { url = "https://files.pythonhosted.org/packages/6e/92/407531450762bed778eedbde04407f68cbd75d13cee96c6f8d6903d9c6c1/regex-2024.9.11-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:b0d0a6c64fcc4ef9c69bd5b3b3626cc3776520a1637d8abaa62b9edc147a58f7", size = 483590 }, - { url = "https://files.pythonhosted.org/packages/8e/a2/048acbc5ae1f615adc6cba36cc45734e679b5f1e4e58c3c77f0ed611d4e2/regex-2024.9.11-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:49b0e06786ea663f933f3710a51e9385ce0cba0ea56b67107fd841a55d56a231", size = 288175 }, - { url = "https://files.pythonhosted.org/packages/8a/ea/909d8620329ab710dfaf7b4adee41242ab7c9b95ea8d838e9bfe76244259/regex-2024.9.11-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5b513b6997a0b2f10e4fd3a1313568e373926e8c252bd76c960f96fd039cd28d", size = 284749 }, - { url = "https://files.pythonhosted.org/packages/ca/fa/521eb683b916389b4975337873e66954e0f6d8f91bd5774164a57b503185/regex-2024.9.11-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee439691d8c23e76f9802c42a95cfeebf9d47cf4ffd06f18489122dbb0a7ad64", size = 795181 }, - { url = "https://files.pythonhosted.org/packages/28/db/63047feddc3280cc242f9c74f7aeddc6ee662b1835f00046f57d5630c827/regex-2024.9.11-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a8f877c89719d759e52783f7fe6e1c67121076b87b40542966c02de5503ace42", size = 835842 }, - { url = "https://files.pythonhosted.org/packages/e3/94/86adc259ff8ec26edf35fcca7e334566c1805c7493b192cb09679f9c3dee/regex-2024.9.11-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:23b30c62d0f16827f2ae9f2bb87619bc4fba2044911e2e6c2eb1af0161cdb766", size = 823533 }, - { url = "https://files.pythonhosted.org/packages/29/52/84662b6636061277cb857f658518aa7db6672bc6d1a3f503ccd5aefc581e/regex-2024.9.11-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:85ab7824093d8f10d44330fe1e6493f756f252d145323dd17ab6b48733ff6c0a", size = 797037 }, - { url = "https://files.pythonhosted.org/packages/c3/2a/cd4675dd987e4a7505f0364a958bc41f3b84942de9efaad0ef9a2646681c/regex-2024.9.11-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8dee5b4810a89447151999428fe096977346cf2f29f4d5e29609d2e19e0199c9", size = 784106 }, - { url = "https://files.pythonhosted.org/packages/6f/75/3ea7ec29de0bbf42f21f812f48781d41e627d57a634f3f23947c9a46e303/regex-2024.9.11-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:98eeee2f2e63edae2181c886d7911ce502e1292794f4c5ee71e60e23e8d26b5d", size = 782468 }, - { url = "https://files.pythonhosted.org/packages/d3/67/15519d69b52c252b270e679cb578e22e0c02b8dd4e361f2b04efcc7f2335/regex-2024.9.11-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:57fdd2e0b2694ce6fc2e5ccf189789c3e2962916fb38779d3e3521ff8fe7a822", size = 790324 }, - { url = "https://files.pythonhosted.org/packages/9c/71/eff77d3fe7ba08ab0672920059ec30d63fa7e41aa0fb61c562726e9bd721/regex-2024.9.11-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:d552c78411f60b1fdaafd117a1fca2f02e562e309223b9d44b7de8be451ec5e0", size = 860214 }, - { url = "https://files.pythonhosted.org/packages/81/11/e1bdf84a72372e56f1ea4b833dd583b822a23138a616ace7ab57a0e11556/regex-2024.9.11-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a0b2b80321c2ed3fcf0385ec9e51a12253c50f146fddb2abbb10f033fe3d049a", size = 859420 }, - { url = "https://files.pythonhosted.org/packages/ea/75/9753e9dcebfa7c3645563ef5c8a58f3a47e799c872165f37c55737dadd3e/regex-2024.9.11-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:18406efb2f5a0e57e3a5881cd9354c1512d3bb4f5c45d96d110a66114d84d23a", size = 787333 }, - { url = "https://files.pythonhosted.org/packages/bc/4e/ba1cbca93141f7416624b3ae63573e785d4bc1834c8be44a8f0747919eca/regex-2024.9.11-cp312-cp312-win32.whl", hash = "sha256:e464b467f1588e2c42d26814231edecbcfe77f5ac414d92cbf4e7b55b2c2a776", size = 262058 }, - { url = "https://files.pythonhosted.org/packages/6e/16/efc5f194778bf43e5888209e5cec4b258005d37c613b67ae137df3b89c53/regex-2024.9.11-cp312-cp312-win_amd64.whl", hash = "sha256:9e8719792ca63c6b8340380352c24dcb8cd7ec49dae36e963742a275dfae6009", size = 273526 }, - { url = "https://files.pythonhosted.org/packages/93/0a/d1c6b9af1ff1e36832fe38d74d5c5bab913f2bdcbbd6bc0e7f3ce8b2f577/regex-2024.9.11-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c157bb447303070f256e084668b702073db99bbb61d44f85d811025fcf38f784", size = 483376 }, - { url = "https://files.pythonhosted.org/packages/a4/42/5910a050c105d7f750a72dcb49c30220c3ae4e2654e54aaaa0e9bc0584cb/regex-2024.9.11-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:4db21ece84dfeefc5d8a3863f101995de646c6cb0536952c321a2650aa202c36", size = 288112 }, - { url = "https://files.pythonhosted.org/packages/8d/56/0c262aff0e9224fa7ffce47b5458d373f4d3e3ff84e99b5ff0cb15e0b5b2/regex-2024.9.11-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:220e92a30b426daf23bb67a7962900ed4613589bab80382be09b48896d211e92", size = 284608 }, - { url = "https://files.pythonhosted.org/packages/b9/54/9fe8f9aec5007bbbbce28ba3d2e3eaca425f95387b7d1e84f0d137d25237/regex-2024.9.11-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb1ae19e64c14c7ec1995f40bd932448713d3c73509e82d8cd7744dc00e29e86", size = 795337 }, - { url = "https://files.pythonhosted.org/packages/b2/e7/6b2f642c3cded271c4f16cc4daa7231be544d30fe2b168e0223724b49a61/regex-2024.9.11-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f47cd43a5bfa48f86925fe26fbdd0a488ff15b62468abb5d2a1e092a4fb10e85", size = 835848 }, - { url = "https://files.pythonhosted.org/packages/cd/9e/187363bdf5d8c0e4662117b92aa32bf52f8f09620ae93abc7537d96d3311/regex-2024.9.11-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9d4a76b96f398697fe01117093613166e6aa8195d63f1b4ec3f21ab637632963", size = 823503 }, - { url = "https://files.pythonhosted.org/packages/f8/10/601303b8ee93589f879664b0cfd3127949ff32b17f9b6c490fb201106c4d/regex-2024.9.11-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ea51dcc0835eea2ea31d66456210a4e01a076d820e9039b04ae8d17ac11dee6", size = 797049 }, - { url = "https://files.pythonhosted.org/packages/ef/1c/ea200f61ce9f341763f2717ab4daebe4422d83e9fd4ac5e33435fd3a148d/regex-2024.9.11-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7aaa315101c6567a9a45d2839322c51c8d6e81f67683d529512f5bcfb99c802", size = 784144 }, - { url = "https://files.pythonhosted.org/packages/d8/5c/d2429be49ef3292def7688401d3deb11702c13dcaecdc71d2b407421275b/regex-2024.9.11-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c57d08ad67aba97af57a7263c2d9006d5c404d721c5f7542f077f109ec2a4a29", size = 782483 }, - { url = "https://files.pythonhosted.org/packages/12/d9/cbc30f2ff7164f3b26a7760f87c54bf8b2faed286f60efd80350a51c5b99/regex-2024.9.11-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:f8404bf61298bb6f8224bb9176c1424548ee1181130818fcd2cbffddc768bed8", size = 790320 }, - { url = "https://files.pythonhosted.org/packages/19/1d/43ed03a236313639da5a45e61bc553c8d41e925bcf29b0f8ecff0c2c3f25/regex-2024.9.11-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dd4490a33eb909ef5078ab20f5f000087afa2a4daa27b4c072ccb3cb3050ad84", size = 860435 }, - { url = "https://files.pythonhosted.org/packages/34/4f/5d04da61c7c56e785058a46349f7285ae3ebc0726c6ea7c5c70600a52233/regex-2024.9.11-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:eee9130eaad130649fd73e5cd92f60e55708952260ede70da64de420cdcad554", size = 859571 }, - { url = "https://files.pythonhosted.org/packages/12/7f/8398c8155a3c70703a8e91c29532558186558e1aea44144b382faa2a6f7a/regex-2024.9.11-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6a2644a93da36c784e546de579ec1806bfd2763ef47babc1b03d765fe560c9f8", size = 787398 }, - { url = "https://files.pythonhosted.org/packages/58/3a/f5903977647a9a7e46d5535e9e96c194304aeeca7501240509bde2f9e17f/regex-2024.9.11-cp313-cp313-win32.whl", hash = "sha256:e997fd30430c57138adc06bba4c7c2968fb13d101e57dd5bb9355bf8ce3fa7e8", size = 262035 }, - { url = "https://files.pythonhosted.org/packages/ff/80/51ba3a4b7482f6011095b3a036e07374f64de180b7d870b704ed22509002/regex-2024.9.11-cp313-cp313-win_amd64.whl", hash = "sha256:042c55879cfeb21a8adacc84ea347721d3d83a159da6acdf1116859e2427c43f", size = 273510 }, -] - -[[package]] -name = "requests" -version = "2.32.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, -] - -[[package]] -name = "six" -version = "1.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/71/39/171f1c67cd00715f190ba0b100d606d440a28c93c7714febeca8b79af85e/six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", size = 34041 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", size = 11053 }, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 }, -] - -[[package]] -name = "tiktoken" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "regex" }, - { name = "requests" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c4/4a/abaec53e93e3ef37224a4dd9e2fc6bb871e7a538c2b6b9d2a6397271daf4/tiktoken-0.7.0.tar.gz", hash = "sha256:1077266e949c24e0291f6c350433c6f0971365ece2b173a23bc3b9f9defef6b6", size = 33437 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/22/eb/57492b2568eea1d546da5cc1ae7559d924275280db80ba07e6f9b89a914b/tiktoken-0.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:10c7674f81e6e350fcbed7c09a65bca9356eaab27fb2dac65a1e440f2bcfe30f", size = 961468 }, - { url = "https://files.pythonhosted.org/packages/30/ef/e07dbfcb2f85c84abaa1b035a9279575a8da0236305491dc22ae099327f7/tiktoken-0.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:084cec29713bc9d4189a937f8a35dbdfa785bd1235a34c1124fe2323821ee93f", size = 907005 }, - { url = "https://files.pythonhosted.org/packages/ea/9b/f36db825b1e9904c3a2646439cb9923fc1e09208e2e071c6d9dd64ead131/tiktoken-0.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:811229fde1652fedcca7c6dfe76724d0908775b353556d8a71ed74d866f73f7b", size = 1049183 }, - { url = "https://files.pythonhosted.org/packages/61/b4/b80d1fe33015e782074e96bbbf4108ccd283b8deea86fb43c15d18b7c351/tiktoken-0.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86b6e7dc2e7ad1b3757e8a24597415bafcfb454cebf9a33a01f2e6ba2e663992", size = 1080830 }, - { url = "https://files.pythonhosted.org/packages/2a/40/c66ff3a21af6d62a7e0ff428d12002c4e0389f776d3ff96dcaa0bb354eee/tiktoken-0.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1063c5748be36344c7e18c7913c53e2cca116764c2080177e57d62c7ad4576d1", size = 1092967 }, - { url = "https://files.pythonhosted.org/packages/2e/80/f4c9e255ff236e6a69ce44b927629cefc1b63d3a00e2d1c9ed540c9492d2/tiktoken-0.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:20295d21419bfcca092644f7e2f2138ff947a6eb8cfc732c09cc7d76988d4a89", size = 1142682 }, - { url = "https://files.pythonhosted.org/packages/b1/10/c04b4ff592a5f46b28ebf4c2353f735c02ae7f0ce1b165d00748ced6467e/tiktoken-0.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:959d993749b083acc57a317cbc643fb85c014d055b2119b739487288f4e5d1cb", size = 799009 }, - { url = "https://files.pythonhosted.org/packages/1d/46/4cdda4186ce900608f522da34acf442363346688c71b938a90a52d7b84cc/tiktoken-0.7.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:71c55d066388c55a9c00f61d2c456a6086673ab7dec22dd739c23f77195b1908", size = 960446 }, - { url = "https://files.pythonhosted.org/packages/b6/30/09ced367d280072d7a3e21f34263dfbbf6378661e7a0f6414e7c18971083/tiktoken-0.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:09ed925bccaa8043e34c519fbb2f99110bd07c6fd67714793c21ac298e449410", size = 906652 }, - { url = "https://files.pythonhosted.org/packages/e6/7b/c949e4954441a879a67626963dff69096e3c774758b9f2bb0853f7b4e1e7/tiktoken-0.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03c6c40ff1db0f48a7b4d2dafeae73a5607aacb472fa11f125e7baf9dce73704", size = 1047904 }, - { url = "https://files.pythonhosted.org/packages/50/81/1842a22f15586072280364c2ab1e40835adaf64e42fe80e52aff921ee021/tiktoken-0.7.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d20b5c6af30e621b4aca094ee61777a44118f52d886dbe4f02b70dfe05c15350", size = 1079836 }, - { url = "https://files.pythonhosted.org/packages/6d/87/51a133a3d5307cf7ae3754249b0faaa91d3414b85c3d36f80b54d6817aa6/tiktoken-0.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d427614c3e074004efa2f2411e16c826f9df427d3c70a54725cae860f09e4bf4", size = 1092472 }, - { url = "https://files.pythonhosted.org/packages/a5/1f/c93517dc6d3b2c9e988b8e24f87a8b2d4a4ab28920a3a3f3ea338397ae0c/tiktoken-0.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8c46d7af7b8c6987fac9b9f61041b452afe92eb087d29c9ce54951280f899a97", size = 1141881 }, - { url = "https://files.pythonhosted.org/packages/bf/4b/48ca098cb580c099b5058bf62c4cb5e90ca6130fa43ef4df27088536245b/tiktoken-0.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:0bc603c30b9e371e7c4c7935aba02af5994a909fc3c0fe66e7004070858d3f8f", size = 799281 }, -] - -[[package]] -name = "tqdm" -version = "4.66.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "platform_system == 'Windows'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/58/83/6ba9844a41128c62e810fddddd72473201f3eacde02046066142a2d96cc5/tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad", size = 169504 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/48/5d/acf5905c36149bbaec41ccf7f2b68814647347b72075ac0b1fe3022fdc73/tqdm-4.66.5-py3-none-any.whl", hash = "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd", size = 78351 }, -] - -[[package]] -name = "typing-extensions" -version = "4.12.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, -] - -[[package]] -name = "urllib3" -version = "2.2.3" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9", size = 300677 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac", size = 126338 }, -]