diff --git a/ldp/llms/chat.py b/ldp/llms/chat.py index 44d745f..956125d 100644 --- a/ldp/llms/chat.py +++ b/ldp/llms/chat.py @@ -1,8 +1,8 @@ import asyncio import json -from collections.abc import AsyncGenerator, Callable, Iterable +from collections.abc import AsyncGenerator, Callable, Iterable, Mapping from datetime import datetime -from typing import Any, ClassVar, Self, cast +from typing import Any, ClassVar, Self, TypeAlias, cast from uuid import UUID, uuid4 import litellm @@ -15,6 +15,10 @@ ) from pydantic import BaseModel, ConfigDict, Field, ValidationError, model_validator +# Yes, this is a hack, it mostly matches +# https://github.com/python-jsonschema/referencing/blob/v0.35.1/referencing/jsonschema.py#L20-L21 +JSONSchema: TypeAlias = Mapping[str, Any] + class JSONSchemaValidationError(ValueError): """Raised when the completion does not match the specified schema.""" @@ -87,13 +91,13 @@ def sum_logprobs(choice: litellm.utils.Choices) -> float | None: def validate_json_completion( - completion: litellm.ModelResponse, output_type: type[BaseModel] + completion: litellm.ModelResponse, output_type: type[BaseModel] | JSONSchema ) -> None: """Validate a completion against a JSON schema. Args: completion: The completion to validate. - output_type: The Pydantic model to validate the completion against. + output_type: A JSON schema or a Pydantic model to validate the completion. """ try: for choice in completion.choices: @@ -105,7 +109,12 @@ def validate_json_completion( choice.message.content = ( choice.message.content.split("```json")[-1].split("```")[0] or "" ) - output_type.model_validate_json(choice.message.content) + if isinstance(output_type, Mapping): # JSON schema + litellm.litellm_core_utils.json_validation_rule.validate_schema( + schema=dict(output_type), response=choice.message.content + ) + else: + output_type.model_validate_json(choice.message.content) except ValidationError as err: raise JSONSchemaValidationError( "The completion does not match the specified schema." @@ -173,7 +182,7 @@ async def call( # noqa: C901, PLR0915 self, messages: list[Message], callbacks: list[Callable] | None = None, - output_type: type[BaseModel] | None = None, + output_type: type[BaseModel] | JSONSchema | None = None, tools: list[Tool] | None = None, tool_choice: Tool | str | None = TOOL_CHOICE_REQUIRED, **chat_kwargs, @@ -198,8 +207,17 @@ async def call( # noqa: C901, PLR0915 else tool_choice ) - # deal with specifying output type - if output_type is not None: + if isinstance(output_type, Mapping): # Use structured outputs + chat_kwargs["response_format"] = { + "type": "json_schema", + "json_schema": { + "strict": True, + # SEE: https://platform.openai.com/docs/guides/structured-outputs#additionalproperties-false-must-always-be-set-in-objects + "schema": dict(output_type) | {"additionalProperties": False}, + "name": output_type["title"], # Required by OpenAI as of 12/3/2024 + }, + } + elif output_type is not None: # Use JSON mode schema = json.dumps(output_type.model_json_schema(mode="serialization")) schema_msg = f"Respond following this JSON schema:\n\n{schema}" # Get the system prompt and its index, or the index to add it diff --git a/pyproject.toml b/pyproject.toml index 5918fd3..a046d47 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ requires = ["setuptools>=64", "setuptools_scm>=8"] [dependency-groups] codeflash = [ - "codeflash>=0.7", # Pin to keep recent + "codeflash>=0.8", # Pin for --verify-setup checking formatter-cmds "ldp[dev]", ] dev = ["ldp[dev]"] @@ -97,7 +97,7 @@ preview = true [tool.codeflash] disable-imports-sorting = true disable-telemetry = true -formatter-cmds = ["ruff check --exit-zero --fix $file", "ruff format $file"] +formatter-cmds = ["uv tool run ruff check --exit-zero --fix $file", "uv tool run ruff format $file"] module-root = "ldp" test-framework = "pytest" tests-root = "tests" diff --git a/tests/cassettes/TestLLMModel.test_output_schema.yaml b/tests/cassettes/TestLLMModel.test_output_schema[json-mode].yaml similarity index 52% rename from tests/cassettes/TestLLMModel.test_output_schema.yaml rename to tests/cassettes/TestLLMModel.test_output_schema[json-mode].yaml index 477de44..95223b7 100644 --- a/tests/cassettes/TestLLMModel.test_output_schema.yaml +++ b/tests/cassettes/TestLLMModel.test_output_schema[json-mode].yaml @@ -1,12 +1,11 @@ interactions: - request: body: - '{"messages": [{"role": "system", "content": "Respond following this JSON - schema:\n\n{\"properties\": {\"name\": {\"title\": \"Name\", \"type\": \"string\"}, - \"age\": {\"title\": \"Age\", \"type\": \"integer\"}}, \"required\": [\"name\", - \"age\"], \"title\": \"DummyOutputSchema\", \"type\": \"object\"}"}, {"role": - "user", "content": "My name is Claude and I am 1 year old. What is my name and - age?"}], "model": "gpt-3.5-turbo", "response_format": {"type": "json_object"}}' + '{"messages":[{"role":"system","content":"Respond following this JSON schema:\n\n{\"properties\": + {\"name\": {\"title\": \"Name\", \"type\": \"string\"}, \"age\": {\"title\": + \"Age\", \"type\": \"integer\"}}, \"required\": [\"name\", \"age\"], \"title\": + \"DummyOutputSchema\", \"type\": \"object\"}"},{"role":"user","content":"My + name is Claude and I am 1 year old. What is my name and age?"}],"model":"gpt-3.5-turbo","response_format":{"type":"json_object"}}' headers: accept: - application/json @@ -15,13 +14,13 @@ interactions: connection: - keep-alive content-length: - - "472" + - "459" content-type: - application/json host: - api.openai.com user-agent: - - AsyncOpenAI/Python 1.54.3 + - AsyncOpenAI/Python 1.55.3 x-stainless-arch: - arm64 x-stainless-async: @@ -31,11 +30,11 @@ interactions: x-stainless-os: - MacOS x-stainless-package-version: - - 1.54.3 + - 1.55.3 x-stainless-raw-response: - "true" x-stainless-retry-count: - - "1" + - "0" x-stainless-runtime: - CPython x-stainless-runtime-version: @@ -45,18 +44,18 @@ interactions: response: body: string: !!binary | - H4sIAAAAAAAAA4ySQYvbMBCF7/4VYs7JEm/Ybte3speytJTdPbSkLkaWJrZaWSOkMbSE/PcixYkd - 2kIvPrxv5vHeWIdCCDAaKgGql6wGb9fvXl71tm2fnvvnzy/vd/hp9+V19/ToPm74A8EqbVD7HRWf - t24UDd4iG3InrAJKxuRa3m/LcvP29s1DBgNptGmt87ze3tyteQwtrTfl7d202ZNRGKESXwshhDjk - b8roNP6ESmxWZ2XAGGWHUF2GhIBANikgYzSRpWNYzVCRY3Q59qF2SarByQFrqEQNj1aOGmtYnZHs - Milrd1y6BNyPUaYWbrR20o+XWJY6H6iNE7/oe+NM7JuAMpJLESKTh0yPhRDfcv3xqhH4QIPnhukH - umT4sD3ZwXzwGZb3E2RiaRd6Od3s2q7RyNLYuLgfKKl61PPqfGw5akMLUCxK/5nmb96n4sZ1/2M/ - A6XQM+rGB9RGXTeexwKm9/ivscuRc2CIvyLj0OyN6zD4YPKLyP/yWPwGAAD//wMAcNRyBBADAAA= + H4sIAAAAAAAAA4ySQWvjMBCF7/4VYs5JqR1Ktr5ld1lKC720lJa6GEWaOOrKkpBGdJeQ/75IcWKH + 7sJefHjfzOO9sXYFY6Ak1AzElpPonZ6v+PPdU/d++/0+fPmIq+opPt483/zAh/j1pYJZ2rDrdxR0 + 3LoQtncaSVlzwMIjJ0yu5XKxqJZldV1m0FuJOq11juaLi6s5Rb+288uyuho2t1YJDFCz14Ixxnb5 + mzIaib+gZpezo9JjCLxDqE9DjIG3OinAQ1CBuCGYjVBYQ2hy7F1jktSA4T02ULMGvmkeJTYwOyLe + ZVI2Zj918biJgacWJmo96PtTLG075+06DPykb5RRYdt65MGaFCGQdZDpvmDsLdePZ43Aeds7asn+ + RJMMrxcHOxgPPsJyOUCyxPVEL4ebndu1EokrHSb3A8HFFuW4Oh6bR6nsBBST0p/T/M37UFyZ7n/s + RyAEOkLZOo9SifPG45jH9B7/NXY6cg4M4Xcg7NuNMh1651V+Eflf7os/AAAA//8DAOtt/IcQAwAA headers: CF-Cache-Status: - DYNAMIC CF-RAY: - - 8df9511e2831942c-SJC + - 8ec79940487acf0a-SJC Connection: - keep-alive Content-Encoding: @@ -64,9 +63,15 @@ interactions: Content-Type: - application/json Date: - - Fri, 08 Nov 2024 23:24:30 GMT + - Wed, 04 Dec 2024 00:14:51 GMT Server: - cloudflare + Set-Cookie: + - __cf_bm=Jt74XtlzTIX4qJ2I6JWts_1PUt6239EzTEKob0gbMYI-1733271291-1.0.1.1-Q2lRwwtee9d00lyYx_vjY4jpuRYySoyrIe_R4yj2LqAaxIDQLNQ99FxRmToXDEeMUPk5tUL1416FgdY7MIAURA; + path=/; expires=Wed, 04-Dec-24 00:44:51 GMT; domain=.api.openai.com; HttpOnly; + Secure; SameSite=None + - _cfuvid=LgL7hRr_QJbzVlAiPhNhtvybE1Xb67FkF.lr0Cryt2I-1733271291893-0.0.1.1-604800000; + path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None Transfer-Encoding: - chunked X-Content-Type-Options: @@ -78,7 +83,7 @@ interactions: openai-organization: - future-house-xr4tdh openai-processing-ms: - - "335" + - "255" openai-version: - "2020-10-01" strict-transport-security: @@ -96,7 +101,7 @@ interactions: x-ratelimit-reset-tokens: - 5ms x-request-id: - - req_d402f5beca04001c51888e5bdd5b65e9 + - req_9f36e635cd12593e29892e9b24310fc6 status: code: 200 message: OK diff --git a/tests/cassettes/TestMultipleCompletionLLMModel.test_output_schema.yaml b/tests/cassettes/TestLLMModel.test_output_schema[structured-outputs].yaml similarity index 55% rename from tests/cassettes/TestMultipleCompletionLLMModel.test_output_schema.yaml rename to tests/cassettes/TestLLMModel.test_output_schema[structured-outputs].yaml index 0feb6d0..136d34a 100644 --- a/tests/cassettes/TestMultipleCompletionLLMModel.test_output_schema.yaml +++ b/tests/cassettes/TestLLMModel.test_output_schema[structured-outputs].yaml @@ -1,12 +1,8 @@ interactions: - request: body: - '{"messages": [{"role": "system", "content": "Respond following this JSON - schema:\n\n{\"properties\": {\"name\": {\"title\": \"Name\", \"type\": \"string\"}, - \"age\": {\"title\": \"Age\", \"type\": \"integer\"}}, \"required\": [\"name\", - \"age\"], \"title\": \"DummyOutputSchema\", \"type\": \"object\"}"}, {"role": - "user", "content": "My name is Claude and I am 1 year old. What is my name and - age?"}], "model": "gpt-3.5-turbo", "n": 2, "response_format": {"type": "json_object"}}' + '{"messages":[{"role":"user","content":"My name is Claude and I am 1 year + old. What is my name and age?"}],"model":"gpt-4o","response_format":{"type":"json_schema","json_schema":{"strict":true,"schema":{"properties":{"name":{"title":"Name","type":"string"},"age":{"title":"Age","type":"integer"}},"required":["name","age"],"title":"DummyOutputSchema","type":"object","additionalProperties":false},"name":"DummyOutputSchema"}}}' headers: accept: - application/json @@ -15,13 +11,13 @@ interactions: connection: - keep-alive content-length: - - "480" + - "425" content-type: - application/json host: - api.openai.com user-agent: - - AsyncOpenAI/Python 1.54.3 + - AsyncOpenAI/Python 1.55.3 x-stainless-arch: - arm64 x-stainless-async: @@ -31,11 +27,11 @@ interactions: x-stainless-os: - MacOS x-stainless-package-version: - - 1.54.3 + - 1.55.3 x-stainless-raw-response: - "true" x-stainless-retry-count: - - "1" + - "0" x-stainless-runtime: - CPython x-stainless-runtime-version: @@ -45,19 +41,18 @@ interactions: response: body: string: !!binary | - H4sIAAAAAAAAA9xTTU/jMBC951dYc05R0y50yW0BcUXABYmsIteepqaOx7In0kLV/46cfiQVrLTn - veTw3ryn9zyTbSYEGA2lALWWrFpvJ7+envX00bJe3ty+ULy7Xt0/LR7U483mQ3rIk4KWb6j4qLpQ - 1HqLbMjtaRVQMibXYjEviunP2dVVT7Sk0SZZ43kyv7iccBeWNJkWs8uDck1GYYRSvGZCCLHtvymj - 0/gHSjHNj0iLMcoGoTwNCQGBbEJAxmgiS8eQD6Qix+j62NvKJagCJ1usoBQV3FrZaawgP1Ky6Zmi - cruxS8BVF2Vq4TprD/juFMtS4wMt44E/4SvjTFzXAWUklyJEJg/ZSPyla/E/ds2E+N2vujtrBD5Q - 67lm2qBLhtfzvR0MxzWQ8x8HkomlHfBitsi/sas1sjQ2jt4PlFRr1IN0OCzZaUMjYryjr2m+894X - N675F/uBUAo9o659QG3UeeNhLGD69/42dnrkPjDE98jY1ivjGgw+mP4i+l3usk8AAAD//wMAxIib - wfwDAAA= + H4sIAAAAAAAAA4xSu07EMBDs8xXW1gkKCeKOdAgqKCgoeAVFPnuTMzhey3YE6HT/jpx75E6ARONi + Zmc8s/YqYQyUhIqBWPIgequzS/748PQh6AKL+5uebOvubuXl1/XzQKWFNCpo8YYi7FQngnqrMSgy + G1o45AGj6+msLItZkZfzkehJoo6yzobsjLIiL86yfJ7l51vhkpRADxV7SRhjbDWeMaKR+AkVy9Md + 0qP3vEOo9kOMgSMdEeDeKx+4CZBOpCAT0IypVzUY3mMNVQ1Xmg8Sa0hr4F2ETteHKoft4HkMbQat + t/h6H0NTZx0t/Jbf460yyi8bh9yTiVf6QBZGdp0w9jrWHY4agHXU29AEekcTDWcXGzuY9juROy5Q + 4HqC5/P0F7NGYuBK+4NtgeBiiXJSTqvlg1R0QCQHlX9m+c17U1uZ7j/2EyEE2oCysQ6lEsd9pzGH + 8fP9NbZf8RgY/JcP2DetMh0669Tm/VvbzNrzBZbYLnJI1sk3AAAA//8DAEganQUIAwAA headers: CF-Cache-Status: - DYNAMIC CF-RAY: - - 8df95108afcf67c1-SJC + - 8ec7ab7ffe551679-SJC Connection: - keep-alive Content-Encoding: @@ -65,7 +60,7 @@ interactions: Content-Type: - application/json Date: - - Fri, 08 Nov 2024 23:24:26 GMT + - Wed, 04 Dec 2024 00:27:18 GMT Server: - cloudflare Transfer-Encoding: @@ -79,25 +74,25 @@ interactions: openai-organization: - future-house-xr4tdh openai-processing-ms: - - "318" + - "367" openai-version: - "2020-10-01" strict-transport-security: - max-age=31536000; includeSubDomains; preload x-ratelimit-limit-requests: - - "12000" + - "10000" x-ratelimit-limit-tokens: - - "1000000" + - "30000000" x-ratelimit-remaining-requests: - - "11999" + - "9998" x-ratelimit-remaining-tokens: - - "999894" + - "29999967" x-ratelimit-reset-requests: - - 5ms - x-ratelimit-reset-tokens: - 6ms + x-ratelimit-reset-tokens: + - 0s x-request-id: - - req_61e43e008d14a5da07c312853987c183 + - req_b1f66bf72beec8f42091a30db5131d27 status: code: 200 message: OK diff --git a/tests/cassettes/TestMultipleCompletionLLMModel.test_output_schema[json-mode].yaml b/tests/cassettes/TestMultipleCompletionLLMModel.test_output_schema[json-mode].yaml new file mode 100644 index 0000000..c5ec433 --- /dev/null +++ b/tests/cassettes/TestMultipleCompletionLLMModel.test_output_schema[json-mode].yaml @@ -0,0 +1,109 @@ +interactions: + - request: + body: + '{"messages":[{"role":"system","content":"Respond following this JSON schema:\n\n{\"properties\": + {\"name\": {\"title\": \"Name\", \"type\": \"string\"}, \"age\": {\"title\": + \"Age\", \"type\": \"integer\"}}, \"required\": [\"name\", \"age\"], \"title\": + \"DummyOutputSchema\", \"type\": \"object\"}"},{"role":"user","content":"My + name is Claude and I am 1 year old. What is my name and age?"}],"model":"gpt-3.5-turbo","n":2,"response_format":{"type":"json_object"}}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - "465" + content-type: + - application/json + host: + - api.openai.com + user-agent: + - AsyncOpenAI/Python 1.55.3 + x-stainless-arch: + - arm64 + x-stainless-async: + - async:asyncio + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.55.3 + x-stainless-raw-response: + - "true" + x-stainless-retry-count: + - "0" + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.12.7 + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: !!binary | + H4sIAAAAAAAAA7RTwYrbMBS8+yvEOyfL2ma7xLel9NRDW1rKQl2MIr3Y2sp6QnqG7Ib8e5ETxw67 + hR7aiw8zb8YzetIhEwKMhkqA6iSr3tv1g3z8+P3xc/fu5Ss9Df2nb1+GZ958kPt98RJglRS0fULF + k+pGUe8tsiF3olVAyZhc8/uyLO7zYpOPRE8abZK1ntflzd2ah7Cl9W1e3J2VHRmFESrxIxNCiMP4 + TRmdxj1U4nY1IT3GKFuE6jIkBASyCQEZo4ksHcNqJhU5RjfGPtTgZI81VKKG91YOGmtYiRpkO4L5 + cSkMuBuiTMHdYO0ZP16SWGp9oG088xd8Z5yJXRNQRnLpr5HJQ7YQv6qX/6t6LkFvlpyoqWnt/nfX + TIif43aHq0bgA/WeG6Zf6JLhpjzZwXyfZrI8bx6YWNoZz4tJdWXXaGRpbFycHyipOtSzdL5LctCG + FsRyR6/TvOV9Km5c+zf2M6EUekbd+IDaqOvG81jA9Nz+NHY55DEwxOfI2Dc741oMPpjxRoy7PGa/ + AQAA//8DAL4bR47vAwAA + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 8ec799405a7ecfac-SJC + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Wed, 04 Dec 2024 00:14:51 GMT + Server: + - cloudflare + Set-Cookie: + - __cf_bm=br87AQInkCnSV_I9MXX5tYGv6_ZP_82Htl2IQun7srQ-1733271291-1.0.1.1-.r_ewngzuQkAkcKmG5atHV1LISuUrs2yVGfkZp0pxbuZa00Mqp.aWv.QYORcyr6VriqkQoJnjfJY99tvrd7rKw; + path=/; expires=Wed, 04-Dec-24 00:44:51 GMT; domain=.api.openai.com; HttpOnly; + Secure; SameSite=None + - _cfuvid=_yXi1Uk8mQKkHMlntTwGtMye1ID9VJRq.3psfLHacuU-1733271291921-0.0.1.1-604800000; + path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + alt-svc: + - h3=":443"; ma=86400 + openai-organization: + - future-house-xr4tdh + openai-processing-ms: + - "268" + openai-version: + - "2020-10-01" + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-ratelimit-limit-requests: + - "12000" + x-ratelimit-limit-tokens: + - "1000000" + x-ratelimit-remaining-requests: + - "11999" + x-ratelimit-remaining-tokens: + - "999894" + x-ratelimit-reset-requests: + - 5ms + x-ratelimit-reset-tokens: + - 6ms + x-request-id: + - req_2d64ba6207682b9086d527ac85f85959 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/cassettes/TestMultipleCompletionLLMModel.test_output_schema[structured-outputs].yaml b/tests/cassettes/TestMultipleCompletionLLMModel.test_output_schema[structured-outputs].yaml new file mode 100644 index 0000000..31f3a84 --- /dev/null +++ b/tests/cassettes/TestMultipleCompletionLLMModel.test_output_schema[structured-outputs].yaml @@ -0,0 +1,106 @@ +interactions: + - request: + body: + '{"messages":[{"role":"user","content":"My name is Claude and I am 1 year + old. What is my name and age?"}],"model":"gpt-4o","n":2,"response_format":{"type":"json_schema","json_schema":{"strict":true,"schema":{"properties":{"name":{"title":"Name","type":"string"},"age":{"title":"Age","type":"integer"}},"required":["name","age"],"title":"DummyOutputSchema","type":"object","additionalProperties":false},"name":"DummyOutputSchema"}}}' + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + connection: + - keep-alive + content-length: + - "431" + content-type: + - application/json + host: + - api.openai.com + user-agent: + - AsyncOpenAI/Python 1.55.3 + x-stainless-arch: + - arm64 + x-stainless-async: + - async:asyncio + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 1.55.3 + x-stainless-raw-response: + - "true" + x-stainless-retry-count: + - "0" + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.12.7 + method: POST + uri: https://api.openai.com/v1/chat/completions + response: + body: + string: !!binary | + H4sIAAAAAAAAA9xTTW+cMBS88yusd4YK2CgQbv26VZWiHpqoVOit/Zb1rrEt20iNVvvfK7NkIUoi + 9dwLh5k3w4z9fEoYAymgYcD3GPhgVfYRH34+Fsd79+U7Hp5+0P2nb1usvx6OD/SoIY0Ksz0QD8+q + D9wMVlGQZqa5IwwUXYtqsymrMt/UEzEYQSrKehuyG5OVeXmT5XWW387CvZGcPDTsV8IYY6fpGyNq + QX+gYXn6jAzkPfYEzXWIMXBGRQTQe+kD6gDpQnKjA+kp9akFjQO10LTwWeEoqIW0BewjVJzXKke7 + 0WMMrUelZvx8jaFMb53Z+pm/4juppd93jtAbHX/pg7GQrMSvuhX/Q7eEsd/TVY4vGoB1ZrChC+ZI + OhpWdxc7WHZnIYt6JoMJqBb8rkrfcOsEBZTKr44LOPI9iUW57A2OQpoVsb6S12He8r70lrr/F/uF + 4JxsINFZR0Lyl4WXMUfxZb03dj3jKTD4Jx9o6HZS9+Ssk5cF2Nmu3hSU31aiLiE5J38BAAD//wMA + vVnbbuUDAAA= + headers: + CF-Cache-Status: + - DYNAMIC + CF-RAY: + - 8ec7ab7fe966aaa5-SJC + Connection: + - keep-alive + Content-Encoding: + - gzip + Content-Type: + - application/json + Date: + - Wed, 04 Dec 2024 00:27:19 GMT + Server: + - cloudflare + Set-Cookie: + - __cf_bm=5AuGimsg2FH0ntBI.jKIdG9P._9c78WMhN9jaiVQGeM-1733272039-1.0.1.1-F92PupP7R_e1Usesjv3KlZUrgLh73lB5LXJjilxG5ZwkFDrI1tOZsZp0zhC5gY.WjprQpIckFtJxWsiUNww0kw; + path=/; expires=Wed, 04-Dec-24 00:57:19 GMT; domain=.api.openai.com; HttpOnly; + Secure; SameSite=None + - _cfuvid=.1wBj_f8n7gG1Go8qdTIwKV7Pk8XaH9yfTumfoAGccU-1733272039104-0.0.1.1-604800000; + path=/; domain=.api.openai.com; HttpOnly; Secure; SameSite=None + Transfer-Encoding: + - chunked + X-Content-Type-Options: + - nosniff + access-control-expose-headers: + - X-Request-ID + alt-svc: + - h3=":443"; ma=86400 + openai-organization: + - future-house-xr4tdh + openai-processing-ms: + - "610" + openai-version: + - "2020-10-01" + strict-transport-security: + - max-age=31536000; includeSubDomains; preload + x-ratelimit-limit-requests: + - "10000" + x-ratelimit-limit-tokens: + - "30000000" + x-ratelimit-remaining-requests: + - "9999" + x-ratelimit-remaining-tokens: + - "29999951" + x-ratelimit-reset-requests: + - 6ms + x-ratelimit-reset-tokens: + - 0s + x-request-id: + - req_86d20ee0ac20474675168c7b0c693f02 + status: + code: 200 + message: OK +version: 1 diff --git a/tests/test_llms.py b/tests/test_llms.py index c7e68b6..f903771 100644 --- a/tests/test_llms.py +++ b/tests/test_llms.py @@ -1,4 +1,4 @@ -from typing import ClassVar +from typing import Any, ClassVar from unittest.mock import Mock import litellm @@ -234,8 +234,19 @@ def play(move: int | None) -> None: @pytest.mark.asyncio @pytest.mark.vcr - async def test_output_schema(self) -> None: - model = self.MODEL_CLS(name="gpt-3.5-turbo", config=self.DEFAULT_CONFIG) + @pytest.mark.parametrize( + ("model_name", "output_type"), + [ + pytest.param("gpt-3.5-turbo", DummyOutputSchema, id="json-mode"), + pytest.param( + "gpt-4o", DummyOutputSchema.model_json_schema(), id="structured-outputs" + ), + ], + ) + async def test_output_schema( + self, model_name: str, output_type: type[BaseModel] | dict[str, Any] + ) -> None: + model = self.MODEL_CLS(name=model_name, config=self.DEFAULT_CONFIG) messages = [ Message( content=( @@ -243,7 +254,7 @@ async def test_output_schema(self) -> None: ) ), ] - results = await self.call_model(model, messages, output_type=DummyOutputSchema) + results = await self.call_model(model, messages, output_type=output_type) assert len(results) == self.NUM_COMPLETIONS for result in results: assert result.messages diff --git a/uv.lock b/uv.lock index e09a755..0cd4f0e 100644 --- a/uv.lock +++ b/uv.lock @@ -212,6 +212,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/76/98/584f211c3a4bb38f2871fa937ee0cc83c130de50c955d6c7e2334dbf4acb/blessed-1.20.0-py2.py3-none-any.whl", hash = "sha256:0c542922586a265e699188e52d5f5ac5ec0dd517e5a1041d90d2bbf23f906058", size = 58372 }, ] +[[package]] +name = "cattrs" +version = "24.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/64/65/af6d57da2cb32c076319b7489ae0958f746949d407109e3ccf4d115f147c/cattrs-24.1.2.tar.gz", hash = "sha256:8028cfe1ff5382df59dd36474a86e02d817b06eaf8af84555441bac915d2ef85", size = 426462 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/d5/867e75361fc45f6de75fe277dd085627a9db5ebb511a87f27dc1396b5351/cattrs-24.1.2-py3-none-any.whl", hash = "sha256:67c7495b760168d931a10233f979b28dc04daf853b30752246f4f8471c6d68d0", size = 66446 }, +] + [[package]] name = "certifi" version = "2024.8.30" @@ -298,11 +310,13 @@ wheels = [ [[package]] name = "codeflash" -version = "0.7.6" +version = "0.8.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "black" }, { name = "click" }, + { name = "coverage" }, + { name = "crosshair-tool" }, { name = "dill" }, { name = "gitpython" }, { name = "humanize" }, @@ -326,7 +340,7 @@ dependencies = [ { name = "unidiff" }, { name = "unittest-xml-reporting" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/bf/fc/dc2779a35c7ace8ec4196787c5f0b03bbb018233539e6c37fb95130138b6/codeflash-0.7.6.tar.gz", hash = "sha256:b69c8525ab17e12113c3e4e0873e3c8cf3a5cef05ae5305ca7064391045960dd", size = 89169 } +sdist = { url = "https://files.pythonhosted.org/packages/e2/95/942e9584d2a22c67bec3f01265061e6a776bd60872b8b791c4e2a1c3ddfa/codeflash-0.8.0.tar.gz", hash = "sha256:4ec61c3511a49a4cd03c6ab072a9a649cae4f29eef027d23ab97f01d883bcdc8", size = 95857 } [[package]] name = "colorama" @@ -388,6 +402,92 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/31/1ae946f11dfbd229222e6d6ad8e7bd1891d3d48bde5fbf7a0beb9491f8e3/contourpy-1.3.1-cp313-cp313t-win_amd64.whl", hash = "sha256:287ccc248c9e0d0566934e7d606201abd74761b5703d804ff3df8935f523d546", size = 236668 }, ] +[[package]] +name = "coverage" +version = "7.6.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ab/75/aecfd0a3adbec6e45753976bc2a9fed62b42cea9a206d10fd29244a77953/coverage-7.6.8.tar.gz", hash = "sha256:8b2b8503edb06822c86d82fa64a4a5cb0760bb8f31f26e138ec743f422f37cfc", size = 801425 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/9f/e98211980f6e2f439e251737482aa77906c9b9c507824c71a2ce7eea0402/coverage-7.6.8-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:86cffe9c6dfcfe22e28027069725c7f57f4b868a3f86e81d1c62462764dc46d4", size = 207093 }, + { url = "https://files.pythonhosted.org/packages/fd/c7/8bab83fb9c20f7f8163c5a20dcb62d591b906a214a6dc6b07413074afc80/coverage-7.6.8-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d82ab6816c3277dc962cfcdc85b1efa0e5f50fb2c449432deaf2398a2928ab94", size = 207536 }, + { url = "https://files.pythonhosted.org/packages/1e/d6/00243df625f1b282bb25c83ce153ae2c06f8e7a796a8d833e7235337b4d9/coverage-7.6.8-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:13690e923a3932e4fad4c0ebfb9cb5988e03d9dcb4c5150b5fcbf58fd8bddfc4", size = 239482 }, + { url = "https://files.pythonhosted.org/packages/1e/07/faf04b3eeb55ffc2a6f24b65dffe6e0359ec3b283e6efb5050ea0707446f/coverage-7.6.8-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4be32da0c3827ac9132bb488d331cb32e8d9638dd41a0557c5569d57cf22c9c1", size = 236886 }, + { url = "https://files.pythonhosted.org/packages/43/23/c79e497bf4d8fcacd316bebe1d559c765485b8ec23ac4e23025be6bfce09/coverage-7.6.8-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44e6c85bbdc809383b509d732b06419fb4544dca29ebe18480379633623baafb", size = 238749 }, + { url = "https://files.pythonhosted.org/packages/b5/e5/791bae13be3c6451e32ef7af1192e711c6a319f3c597e9b218d148fd0633/coverage-7.6.8-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:768939f7c4353c0fac2f7c37897e10b1414b571fd85dd9fc49e6a87e37a2e0d8", size = 237679 }, + { url = "https://files.pythonhosted.org/packages/05/c6/bbfdfb03aada601fb8993ced17468c8c8e0b4aafb3097026e680fabb7ce1/coverage-7.6.8-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e44961e36cb13c495806d4cac67640ac2866cb99044e210895b506c26ee63d3a", size = 236317 }, + { url = "https://files.pythonhosted.org/packages/67/f9/f8e5a4b2ce96d1b0e83ae6246369eb8437001dc80ec03bb51c87ff557cd8/coverage-7.6.8-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ea8bb1ab9558374c0ab591783808511d135a833c3ca64a18ec927f20c4030f0", size = 237084 }, + { url = "https://files.pythonhosted.org/packages/f0/70/b05328901e4debe76e033717e1452d00246c458c44e9dbd893e7619c2967/coverage-7.6.8-cp311-cp311-win32.whl", hash = "sha256:629a1ba2115dce8bf75a5cce9f2486ae483cb89c0145795603d6554bdc83e801", size = 209638 }, + { url = "https://files.pythonhosted.org/packages/70/55/1efa24f960a2fa9fbc44a9523d3f3c50ceb94dd1e8cd732168ab2dc41b07/coverage-7.6.8-cp311-cp311-win_amd64.whl", hash = "sha256:fb9fc32399dca861584d96eccd6c980b69bbcd7c228d06fb74fe53e007aa8ef9", size = 210506 }, + { url = "https://files.pythonhosted.org/packages/76/ce/3edf581c8fe429ed8ced6e6d9ac693c25975ef9093413276dab6ed68a80a/coverage-7.6.8-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e683e6ecc587643f8cde8f5da6768e9d165cd31edf39ee90ed7034f9ca0eefee", size = 207285 }, + { url = "https://files.pythonhosted.org/packages/09/9c/cf102ab046c9cf8895c3f7aadcde6f489a4b2ec326757e8c6e6581829b5e/coverage-7.6.8-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1defe91d41ce1bd44b40fabf071e6a01a5aa14de4a31b986aa9dfd1b3e3e414a", size = 207522 }, + { url = "https://files.pythonhosted.org/packages/39/06/42aa6dd13dbfca72e1fd8ffccadbc921b6e75db34545ebab4d955d1e7ad3/coverage-7.6.8-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7ad66e8e50225ebf4236368cc43c37f59d5e6728f15f6e258c8639fa0dd8e6d", size = 240543 }, + { url = "https://files.pythonhosted.org/packages/a0/20/2932971dc215adeca8eeff446266a7fef17a0c238e881ffedebe7bfa0669/coverage-7.6.8-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fe47da3e4fda5f1abb5709c156eca207eacf8007304ce3019eb001e7a7204cb", size = 237577 }, + { url = "https://files.pythonhosted.org/packages/ac/85/4323ece0cd5452c9522f4b6e5cc461e6c7149a4b1887c9e7a8b1f4e51146/coverage-7.6.8-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:202a2d645c5a46b84992f55b0a3affe4f0ba6b4c611abec32ee88358db4bb649", size = 239646 }, + { url = "https://files.pythonhosted.org/packages/77/52/b2537487d8f36241e518e84db6f79e26bc3343b14844366e35b090fae0d4/coverage-7.6.8-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4674f0daa1823c295845b6a740d98a840d7a1c11df00d1fd62614545c1583787", size = 239128 }, + { url = "https://files.pythonhosted.org/packages/7c/99/7f007762012186547d0ecc3d328da6b6f31a8c99f05dc1e13dcd929918cd/coverage-7.6.8-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:74610105ebd6f33d7c10f8907afed696e79c59e3043c5f20eaa3a46fddf33b4c", size = 237434 }, + { url = "https://files.pythonhosted.org/packages/97/53/e9b5cf0682a1cab9352adfac73caae0d77ae1d65abc88975d510f7816389/coverage-7.6.8-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:37cda8712145917105e07aab96388ae76e787270ec04bcb9d5cc786d7cbb8443", size = 239095 }, + { url = "https://files.pythonhosted.org/packages/0c/50/054f0b464fbae0483217186478eefa2e7df3a79917ed7f1d430b6da2cf0d/coverage-7.6.8-cp312-cp312-win32.whl", hash = "sha256:9e89d5c8509fbd6c03d0dd1972925b22f50db0792ce06324ba069f10787429ad", size = 209895 }, + { url = "https://files.pythonhosted.org/packages/df/d0/09ba870360a27ecf09e177ca2ff59d4337fc7197b456f22ceff85cffcfa5/coverage-7.6.8-cp312-cp312-win_amd64.whl", hash = "sha256:379c111d3558272a2cae3d8e57e6b6e6f4fe652905692d54bad5ea0ca37c5ad4", size = 210684 }, + { url = "https://files.pythonhosted.org/packages/9a/84/6f0ccf94a098ac3d6d6f236bd3905eeac049a9e0efcd9a63d4feca37ac4b/coverage-7.6.8-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0b0c69f4f724c64dfbfe79f5dfb503b42fe6127b8d479b2677f2b227478db2eb", size = 207313 }, + { url = "https://files.pythonhosted.org/packages/db/2b/e3b3a3a12ebec738c545897ac9f314620470fcbc368cdac88cf14974ba20/coverage-7.6.8-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c15b32a7aca8038ed7644f854bf17b663bc38e1671b5d6f43f9a2b2bd0c46f63", size = 207574 }, + { url = "https://files.pythonhosted.org/packages/db/c0/5bf95d42b6a8d21dfce5025ce187f15db57d6460a59b67a95fe8728162f1/coverage-7.6.8-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63068a11171e4276f6ece913bde059e77c713b48c3a848814a6537f35afb8365", size = 240090 }, + { url = "https://files.pythonhosted.org/packages/57/b8/d6fd17d1a8e2b0e1a4e8b9cb1f0f261afd422570735899759c0584236916/coverage-7.6.8-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6f4548c5ead23ad13fb7a2c8ea541357474ec13c2b736feb02e19a3085fac002", size = 237237 }, + { url = "https://files.pythonhosted.org/packages/d4/e4/a91e9bb46809c8b63e68fc5db5c4d567d3423b6691d049a4f950e38fbe9d/coverage-7.6.8-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b4b4299dd0d2c67caaaf286d58aef5e75b125b95615dda4542561a5a566a1e3", size = 239225 }, + { url = "https://files.pythonhosted.org/packages/31/9c/9b99b0591ec4555b7292d271e005f27b465388ce166056c435b288db6a69/coverage-7.6.8-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c9ebfb2507751f7196995142f057d1324afdab56db1d9743aab7f50289abd022", size = 238888 }, + { url = "https://files.pythonhosted.org/packages/a6/85/285c2df9a04bc7c31f21fd9d4a24d19e040ec5e2ff06e572af1f6514c9e7/coverage-7.6.8-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c1b4474beee02ede1eef86c25ad4600a424fe36cff01a6103cb4533c6bf0169e", size = 236974 }, + { url = "https://files.pythonhosted.org/packages/cb/a1/95ec8522206f76cdca033bf8bb61fff56429fb414835fc4d34651dfd29fc/coverage-7.6.8-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d9fd2547e6decdbf985d579cf3fc78e4c1d662b9b0ff7cc7862baaab71c9cc5b", size = 238815 }, + { url = "https://files.pythonhosted.org/packages/8d/ac/687e9ba5e6d0979e9dab5c02e01c4f24ac58260ef82d88d3b433b3f84f1e/coverage-7.6.8-cp313-cp313-win32.whl", hash = "sha256:8aae5aea53cbfe024919715eca696b1a3201886ce83790537d1c3668459c7146", size = 209957 }, + { url = "https://files.pythonhosted.org/packages/2f/a3/b61cc8e3fcf075293fb0f3dee405748453c5ba28ac02ceb4a87f52bdb105/coverage-7.6.8-cp313-cp313-win_amd64.whl", hash = "sha256:ae270e79f7e169ccfe23284ff5ea2d52a6f401dc01b337efb54b3783e2ce3f28", size = 210711 }, + { url = "https://files.pythonhosted.org/packages/ee/4b/891c8b9acf1b62c85e4a71dac142ab9284e8347409b7355de02e3f38306f/coverage-7.6.8-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:de38add67a0af869b0d79c525d3e4588ac1ffa92f39116dbe0ed9753f26eba7d", size = 208053 }, + { url = "https://files.pythonhosted.org/packages/18/a9/9e330409b291cc002723d339346452800e78df1ce50774ca439ade1d374f/coverage-7.6.8-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b07c25d52b1c16ce5de088046cd2432b30f9ad5e224ff17c8f496d9cb7d1d451", size = 208329 }, + { url = "https://files.pythonhosted.org/packages/9c/0d/33635fd429f6589c6e1cdfc7bf581aefe4c1792fbff06383f9d37f59db60/coverage-7.6.8-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62a66ff235e4c2e37ed3b6104d8b478d767ff73838d1222132a7a026aa548764", size = 251052 }, + { url = "https://files.pythonhosted.org/packages/23/32/8a08da0e46f3830bbb9a5b40614241b2e700f27a9c2889f53122486443ed/coverage-7.6.8-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09b9f848b28081e7b975a3626e9081574a7b9196cde26604540582da60235fdf", size = 246765 }, + { url = "https://files.pythonhosted.org/packages/56/3f/3b86303d2c14350fdb1c6c4dbf9bc76000af2382f42ca1d4d99c6317666e/coverage-7.6.8-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:093896e530c38c8e9c996901858ac63f3d4171268db2c9c8b373a228f459bbc5", size = 249125 }, + { url = "https://files.pythonhosted.org/packages/36/cb/c4f081b9023f9fd8646dbc4ef77be0df090263e8f66f4ea47681e0dc2cff/coverage-7.6.8-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a7b8ac36fd688c8361cbc7bf1cb5866977ece6e0b17c34aa0df58bda4fa18a4", size = 248615 }, + { url = "https://files.pythonhosted.org/packages/32/ee/53bdbf67760928c44b57b2c28a8c0a4bf544f85a9ee129a63ba5c78fdee4/coverage-7.6.8-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:38c51297b35b3ed91670e1e4efb702b790002e3245a28c76e627478aa3c10d83", size = 246507 }, + { url = "https://files.pythonhosted.org/packages/57/49/5a57910bd0af6d8e802b4ca65292576d19b54b49f81577fd898505dee075/coverage-7.6.8-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2e4e0f60cb4bd7396108823548e82fdab72d4d8a65e58e2c19bbbc2f1e2bfa4b", size = 247785 }, + { url = "https://files.pythonhosted.org/packages/bd/37/e450c9f6b297c79bb9858407396ed3e084dcc22990dd110ab01d5ceb9770/coverage-7.6.8-cp313-cp313t-win32.whl", hash = "sha256:6535d996f6537ecb298b4e287a855f37deaf64ff007162ec0afb9ab8ba3b8b71", size = 210605 }, + { url = "https://files.pythonhosted.org/packages/44/79/7d0c7dd237c6905018e2936cd1055fe1d42e7eba2ebab3c00f4aad2a27d7/coverage-7.6.8-cp313-cp313t-win_amd64.whl", hash = "sha256:c79c0685f142ca53256722a384540832420dff4ab15fec1863d7e5bc8691bdcc", size = 211777 }, +] + +[[package]] +name = "crosshair-tool" +version = "0.0.78" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-metadata" }, + { name = "packaging" }, + { name = "pygls" }, + { name = "typeshed-client" }, + { name = "typing-extensions" }, + { name = "typing-inspect" }, + { name = "z3-solver" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/44/2b/dda08eb6536f9555cd053b298257481086f303036369d31360f5a8296aaa/crosshair-tool-0.0.78.tar.gz", hash = "sha256:27d6863d4a3f287b1674d36071b0af1b75a42535871083478b8affdf8c03fb8a", size = 446672 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/d6/f061dabb51a47b0b20206fcdaf474b80c776fbb23100a66a27897747fc1b/crosshair_tool-0.0.78-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26be33e5b3b414a895c1c4a4198cd289b3c26a431eedb26a6514051ed8d0123a", size = 501587 }, + { url = "https://files.pythonhosted.org/packages/f6/e2/d6686ca189bc0123a5fa4b3496a3ff2e0a39f4346b12730325b256744726/crosshair_tool-0.0.78-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1bf8cc5d58413e6192bc326a9d132108a852b94383e7bca44a9d940a5ea23ad7", size = 523271 }, + { url = "https://files.pythonhosted.org/packages/fe/bf/705306bab1a9839819a828c8b55c5a5ac8bf1046bffdb853ced574c054c6/crosshair_tool-0.0.78-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa54c76c461e554511b44602af738feaebad6b82ae6ca189b9045edfc11ff96", size = 525554 }, + { url = "https://files.pythonhosted.org/packages/dc/5c/973b871189d149b49d0d56191987552613cd72457ff537b3a91defb8229a/crosshair_tool-0.0.78-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d335fd94d38b8c498e83b3c50cf31ef713be9c7eb042f8665555242ee50164e6", size = 523232 }, + { url = "https://files.pythonhosted.org/packages/85/23/c7fd2d53efe52a9b3d70857f2cf057cb910bd1d40fa1b425f56f562f2192/crosshair_tool-0.0.78-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d4b8c4a2904904e52a367f6e6917fcbde157d6556555d7444def1947a314d9ef", size = 524875 }, + { url = "https://files.pythonhosted.org/packages/c8/b7/5c34bce469f899ce09b509c08ca59b760e83a129b6f2c416c14a2fc76b0c/crosshair_tool-0.0.78-cp311-cp311-win32.whl", hash = "sha256:2c6220accf4c5d2655bffc78addbb73ea42641c1c5084be9a46309b627b4c84c", size = 503863 }, + { url = "https://files.pythonhosted.org/packages/f3/ed/9b63cb6d4654d634aa71e798d3db947fa65add360e13b7b389bf40c7bd88/crosshair_tool-0.0.78-cp311-cp311-win_amd64.whl", hash = "sha256:5728eea95f46c3b48e5b927f31f5523e6f856840d375d7885484efaf8783b6b1", size = 504829 }, + { url = "https://files.pythonhosted.org/packages/d6/07/7e4fccc48ada70f0d81e5d7e404a6ee7102dda2c0d77fe2f0874f3ca1441/crosshair_tool-0.0.78-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8b0523da916f4ea36402672e04e42c4811b6e215e858ff85224cdfe5388f1db8", size = 504093 }, + { url = "https://files.pythonhosted.org/packages/c3/c7/192d729721b7c2acd13c79c1ebd22dfe7a8a1df812f61b1800f74b99633d/crosshair_tool-0.0.78-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be9aaa181f12912a41ac44cbcc41b9b36f0315262903497d6d69866b7ee63a17", size = 532203 }, + { url = "https://files.pythonhosted.org/packages/7b/ac/c71bfe4ee5eb1f58fcb15ddf72ee73ce61c5b60438aae39e8497fefd6c78/crosshair_tool-0.0.78-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58b799da8d0287922a05085c7a51cd7e7985f2642ae576e7149431ee33ceb593", size = 534882 }, + { url = "https://files.pythonhosted.org/packages/d5/8c/02334bf1307c146bcfb6eb8074172e5b5b671d6de8dd9d77ee1cdf8d6277/crosshair_tool-0.0.78-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:906ca01cffaf71d43c6df677b9ea0ac19b67fc595e5d1850c925b5c16226a045", size = 532724 }, + { url = "https://files.pythonhosted.org/packages/a5/58/2c283c0b076c5d51c7991e46dafa6f6d360408888efc2a0edad1838b4baa/crosshair_tool-0.0.78-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d354bac480f479d2aa1f6acdc6f6d0bb30865ff086e8d8b27bee919aa711e2a5", size = 533755 }, + { url = "https://files.pythonhosted.org/packages/08/9a/277021dfffe296a2fcf3c69ddd266ce2ce3d7107fd0e4180b225dc392775/crosshair_tool-0.0.78-cp312-cp312-win32.whl", hash = "sha256:507733fcfbe2ee03248feb44784e3e2947222209f39ca83e219e437e587d5885", size = 505889 }, + { url = "https://files.pythonhosted.org/packages/35/fa/236742d164caebaaeffba86e56acdb7a41dcecc1167cff28cca0f5f1bf5c/crosshair_tool-0.0.78-cp312-cp312-win_amd64.whl", hash = "sha256:e6b23e3c28ea4660ca15e09d124a22998bc3ba9428912b22f313928d657c9d23", size = 507075 }, + { url = "https://files.pythonhosted.org/packages/2f/d6/5d700c055e4765b268cd57ea5b52a10bd4ba18648df46871728efa57b739/crosshair_tool-0.0.78-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:308a22aeb445e0a3605edd53aa83886397a3e6d4f174b9f076195ce438ef9e79", size = 504125 }, + { url = "https://files.pythonhosted.org/packages/3f/f3/de8e22a6883698cbfb76ce589a39eb279707330bb0ac3c64fd2ad551f18c/crosshair_tool-0.0.78-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef6cdcaa6042945459209693d3eeb9e9fdbf47060c3373ab873fbd98af8b3cea", size = 532443 }, + { url = "https://files.pythonhosted.org/packages/6f/18/a680f4ba98dcda4860dbd35a684aa53d2f834784686b4056a6d86e6cddd4/crosshair_tool-0.0.78-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71e1ec9304f243d79408252bcc71a1db88639ef670c174d75cf800769680a6cc", size = 535054 }, + { url = "https://files.pythonhosted.org/packages/2d/fb/e69fd0edd72343d618cc2c96c67cfd0b7bd32aed964af5bade5a07a9ba42/crosshair_tool-0.0.78-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:03814c414f56b9b0c813ed70b4ecd065c147ff555086cebbb8ee3c99b5f19c2d", size = 533097 }, + { url = "https://files.pythonhosted.org/packages/5b/a9/574de9733efe9b6841ded3f3ca70c12e1ab62734868028f6aea0ec47e8fa/crosshair_tool-0.0.78-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e01eeed86eeba8bd3949fc4e5f54fd404d74497094e6cb380e13dd51ee63ade9", size = 533999 }, + { url = "https://files.pythonhosted.org/packages/0b/6c/7ba0e72eeb42b38e0bb0b4eb62e6baf71fc88aa2a79653c556356ed1b12d/crosshair_tool-0.0.78-cp313-cp313-win32.whl", hash = "sha256:a3f3e5666998dd25f827776233dd37e6415bcf52d8a23ca95dfc7f87faec7b53", size = 505885 }, + { url = "https://files.pythonhosted.org/packages/fe/0d/dbd0cbb11527ef6d7228ab99efa139d4964d47b8b5668e80fa9179ac6fe9/crosshair_tool-0.0.78-cp313-cp313-win_amd64.whl", hash = "sha256:ee01b309abb9eb7060fa9fc067a9cbfd9a308c042025bd4179a2c8409d524d77", size = 507064 }, +] + [[package]] name = "cycler" version = "0.12.1" @@ -773,6 +873,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b", size = 26514 }, ] +[[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 = "iniconfig" version = "2.0.0" @@ -1002,7 +1111,7 @@ wheels = [ [[package]] name = "ldp" -version = "0.14.6.dev1+g823a2e1.d20241202" +version = "0.14.6.dev3+ga41aa47.d20241204" source = { editable = "." } dependencies = [ { name = "aiofiles" }, @@ -1074,10 +1183,62 @@ visualization = [ [package.dev-dependencies] codeflash = [ { name = "codeflash" }, - { name = "ldp", extra = ["dev"] }, + { name = "fastapi" }, + { name = "fhaviary", extra = ["xml"] }, + { name = "ipython" }, + { name = "litellm" }, + { name = "mypy" }, + { name = "pre-commit" }, + { name = "pydantic" }, + { name = "pydot" }, + { name = "pylint" }, + { name = "pylint-pydantic" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-mock" }, + { name = "pytest-recording" }, + { name = "pytest-rerunfailures" }, + { name = "pytest-subtests" }, + { name = "pytest-sugar" }, + { name = "pytest-timer", extra = ["colorama"] }, + { name = "pytest-xdist" }, + { name = "refurb" }, + { name = "rich" }, + { name = "torch" }, + { name = "tqdm" }, + { name = "types-aiofiles" }, + { name = "types-tqdm" }, + { name = "vcrpy" }, + { name = "wandb" }, ] dev = [ - { name = "ldp", extra = ["dev"] }, + { name = "fastapi" }, + { name = "fhaviary", extra = ["xml"] }, + { name = "ipython" }, + { name = "litellm" }, + { name = "mypy" }, + { name = "pre-commit" }, + { name = "pydantic" }, + { name = "pydot" }, + { name = "pylint" }, + { name = "pylint-pydantic" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "pytest-mock" }, + { name = "pytest-recording" }, + { name = "pytest-rerunfailures" }, + { name = "pytest-subtests" }, + { name = "pytest-sugar" }, + { name = "pytest-timer", extra = ["colorama"] }, + { name = "pytest-xdist" }, + { name = "refurb" }, + { name = "rich" }, + { name = "torch" }, + { name = "tqdm" }, + { name = "types-aiofiles" }, + { name = "types-tqdm" }, + { name = "vcrpy" }, + { name = "wandb" }, ] [package.metadata] @@ -1127,7 +1288,7 @@ requires-dist = [ [package.metadata.requires-dev] codeflash = [ - { name = "codeflash", specifier = ">=0.7" }, + { name = "codeflash", specifier = ">=0.8" }, { name = "ldp", extras = ["dev"] }, ] dev = [{ name = "ldp", extras = ["dev"] }] @@ -1189,6 +1350,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d5/a6/8a3b430d89b9935ef6d1e88e565f631038d3124788e6effa3c0c9ad4756e/litellm-1.53.1-py3-none-any.whl", hash = "sha256:7a0b480c0bd4f9236910a426d8d8f46a517af4daae2a61d57e42bff4b4daf9b0", size = 6418676 }, ] +[[package]] +name = "lsprotocol" +version = "2023.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "cattrs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/f6/6e80484ec078d0b50699ceb1833597b792a6c695f90c645fbaf54b947e6f/lsprotocol-2023.0.1.tar.gz", hash = "sha256:cc5c15130d2403c18b734304339e51242d3018a05c4f7d0f198ad6e0cd21861d", size = 69434 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/37/2351e48cb3309673492d3a8c59d407b75fb6630e560eb27ecd4da03adc9a/lsprotocol-2023.0.1-py3-none-any.whl", hash = "sha256:c75223c9e4af2f24272b14c6375787438279369236cd568f596d4951052a60f2", size = 70826 }, +] + [[package]] name = "lxml" version = "5.3.0" @@ -2086,6 +2260,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3e/1b/ef569ac44598b6b24bc0f80d5ac4f811af59d3f0d0d23b0216e014c0ec33/pydot-3.0.3-py3-none-any.whl", hash = "sha256:9b0b3081e0bd362d0c61148da10eb1281ec80089b02a28cf06f9093843986f3d", size = 35784 }, ] +[[package]] +name = "pygls" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cattrs" }, + { name = "lsprotocol" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/86/b9/41d173dad9eaa9db9c785a85671fc3d68961f08d67706dc2e79011e10b5c/pygls-1.3.1.tar.gz", hash = "sha256:140edceefa0da0e9b3c533547c892a42a7d2fd9217ae848c330c53d266a55018", size = 45527 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/19/b74a10dd24548e96e8c80226cbacb28b021bc3a168a7d2709fb0d0185348/pygls-1.3.1-py3-none-any.whl", hash = "sha256:6e00f11efc56321bdeb6eac04f6d86131f654c7d49124344a9ebb968da3dd91e", size = 56031 }, +] + [[package]] name = "pygments" version = "2.18.0" @@ -2985,6 +3172,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/11/7b/3fc711b2efea5e85a7a0bbfe269ea944aa767bbba5ec52f9ee45d362ccf3/types_urllib3-1.26.25.14-py3-none-any.whl", hash = "sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e", size = 15377 }, ] +[[package]] +name = "typeshed-client" +version = "2.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "importlib-resources" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/65/1e/f20e33447be772486acf028295cdd21437454a051adb602d52ddb5334f9e/typeshed_client-2.7.0.tar.gz", hash = "sha256:e63df1e738588ad39f1226de042f4407ab6a99c456f0837063afd83b1415447c", size = 433569 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/39/4702c2901899c018189b9aa7eb75aa8eb54527aed71c3f285895190dc664/typeshed_client-2.7.0-py3-none-any.whl", hash = "sha256:97084e5abc58a76ace2c4618ecaebd625f2d19bbd85aa1b3fb86216bf174bbea", size = 624417 }, +] + [[package]] name = "typing-extensions" version = "4.12.2" @@ -2994,6 +3194,19 @@ 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 = "typing-inspect" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/dc/74/1789779d91f1961fa9438e9a8710cdae6bd138c80d7303996933d117264a/typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78", size = 13825 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/65/f3/107a22063bf27bdccf2024833d3445f4eea42b2e598abfbd46f6a63b6cb0/typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f", size = 8827 }, +] + [[package]] name = "tzdata" version = "2024.2" @@ -3279,6 +3492,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f5/4b/a06e0ec3d155924f77835ed2d167ebd3b211a7b0853da1cf8d8414d784ef/yarl-1.18.3-py3-none-any.whl", hash = "sha256:b57f4f58099328dfb26c6a771d09fb20dbbae81d20cfb66141251ea063bd101b", size = 45109 }, ] +[[package]] +name = "z3-solver" +version = "4.13.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/fd/e3f5850fd04480a942aca9f9f7520d3fa5b57731335c221a11f55bb6d91a/z3-solver-4.13.0.0.tar.gz", hash = "sha256:52588e92aec7cb338fd6288ce93758ae01770f62ca0c80e8f4f2b2333feaf51b", size = 4848532 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/5b/934de9f1f31b1d0f3a8da0ff2e3092136fbffe737eca52965818464af4c3/z3_solver-4.13.0.0-py2.py3-none-macosx_11_0_arm64.whl", hash = "sha256:bca7d59a699a440247537c2180c519d682c9df3520a16ce288fced61a70d253d", size = 27144281 }, + { url = "https://files.pythonhosted.org/packages/9c/20/f28dfa982bc820760117e5615d59d695d12a6fb31660f53a749be27cccca/z3_solver-4.13.0.0-py2.py3-none-macosx_11_0_x86_64.whl", hash = "sha256:4a4731fded91b32e1861e1c7c96e500da743bb9431246cac51f7c3ffc0f21b5d", size = 30107615 }, + { url = "https://files.pythonhosted.org/packages/0e/8c/9058d3998fdc2148f3e6d3497e949d5dfc77c66b1cc1cb461554c0bba954/z3_solver-4.13.0.0-py2.py3-none-manylinux2014_aarch64.whl", hash = "sha256:9d622022a3511c059915c56b2c231c84b5c1be1b82f457d7560dda3d916474fe", size = 55585725 }, + { url = "https://files.pythonhosted.org/packages/c6/79/0255fe0efee7ea9db8987ced14c70028a0007d4d4aaaed8965310bbd7bb1/z3_solver-4.13.0.0-py2.py3-none-manylinux2014_x86_64.whl", hash = "sha256:8c42de82b6e3ff7ee61287d03c7af8a99f9f6554cdd1204c6b9bca96ff1cb7fb", size = 57305826 }, + { url = "https://files.pythonhosted.org/packages/b9/27/ca09e1f4642b42a2972047f508bc4ecb0c5acf975c910eb0fdeaf9ec21d0/z3_solver-4.13.0.0-py2.py3-none-win32.whl", hash = "sha256:13468e1018c817b7f794898d3100f02541d15c13ab56c0785c5acdea32a066cf", size = 55429050 }, + { url = "https://files.pythonhosted.org/packages/25/c0/dd978c813288f6860bcfb9e4d2d1d3b311a42a2237a4766e5a0adbcaa79b/z3_solver-4.13.0.0-py2.py3-none-win_amd64.whl", hash = "sha256:3555436cfe9a5fa2d1b432fb9a5e4460e487649c22e5e68a56f7d81594d043e9", size = 58378460 }, +] + [[package]] name = "zipp" version = "3.21.0"