diff --git a/.github/workflows/scripts/run_notebooks.sh b/.github/workflows/scripts/run_notebooks.sh index cd854ceb6..66075f5e8 100755 --- a/.github/workflows/scripts/run_notebooks.sh +++ b/.github/workflows/scripts/run_notebooks.sh @@ -11,7 +11,7 @@ cd docs/examples notebook="$1" # Check if the notebook should be processed -invalid_notebooks=("valid_chess_moves.ipynb" "llamaindex-output-parsing.ipynb" "competitors_check.ipynb") +invalid_notebooks=("llamaindex-output-parsing.ipynb" "competitors_check.ipynb" "guardrails_server.ipynb") if [[ ! " ${invalid_notebooks[@]} " =~ " ${notebook} " ]]; then echo "Processing $notebook..." # poetry run jupyter nbconvert --to notebook --execute "$notebook" diff --git a/docs/api_reference/async_guard.md b/docs/api_reference/async_guard.md new file mode 100644 index 000000000..9c27104a5 --- /dev/null +++ b/docs/api_reference/async_guard.md @@ -0,0 +1,22 @@ + + + +::: guardrails.guard.AsyncGuard + options: + members: + - "__init__" + - "from_rail" + - "from_rail_string" + - "from_pydantic" + - "from_string" + - "configure" + - "use" + - "use_many" + - "__call__" + - "parse" + - "validate" + - "error_spans_in_output" + - "add_json_function_calling_tool" + - "to_dict" + - "from_dict" + - "to_runnable" diff --git a/docs/api_reference/errors.md b/docs/api_reference/errors.md new file mode 100644 index 000000000..eb7b1e812 --- /dev/null +++ b/docs/api_reference/errors.md @@ -0,0 +1,7 @@ + + + +::: guardrails.errors + options: + members: + - "ValidationError" \ No newline at end of file diff --git a/docs/api_reference/guard.md b/docs/api_reference/guard.md index 1c4950e64..6f8873d91 100644 --- a/docs/api_reference/guard.md +++ b/docs/api_reference/guard.md @@ -9,12 +9,14 @@ - "from_rail_string" - "from_pydantic" - "from_string" + - "configure" - "use" - "use_many" - - "to_runnable" - - "configure" - "__call__" - "parse" - "validate" - - "history" - "error_spans_in_output" + - "add_json_function_calling_tool" + - "to_dict" + - "from_dict" + - "to_runnable" diff --git a/docs/api_reference/types.md b/docs/api_reference/types.md new file mode 100644 index 000000000..980475efb --- /dev/null +++ b/docs/api_reference/types.md @@ -0,0 +1 @@ +::: guardrails.types \ No newline at end of file diff --git a/docs/api_reference/validators.md b/docs/api_reference/validators.md deleted file mode 100644 index 447417a4d..000000000 --- a/docs/api_reference/validators.md +++ /dev/null @@ -1,18 +0,0 @@ - - -::: guardrails.validators - options: - filters: - - "!logger" - - "!types_to_validators" - - "!validators_registry" - - "!EventDetail" - - "!Validator" - - "!validate" - - "!register_validator" - - "!PydanticReAsk" - - "!Refrain" - - "!ValidationResult" - - "!PassResult" - - "!FailResult" - - "!__*" diff --git a/docs/examples/constrained_decoding.ipynb b/docs/examples/constrained_decoding.ipynb new file mode 100644 index 000000000..03cdf447a --- /dev/null +++ b/docs/examples/constrained_decoding.ipynb @@ -0,0 +1,93 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m24.0\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.1\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n", + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m24.0\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.1\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n" + ] + } + ], + "source": [ + "! pip install ipywidgets -q" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "81b91198c45249a2b0a7075d13ebf838", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "model.safetensors: 0%| | 10.5M/2.20G [00:00, ?B/s]" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from guardrails import Guard\n", + "from pydantic import BaseModel\n", + "\n", + "class Dog(BaseModel):\n", + " name: str\n", + " color: str\n", + " weight_kg: float\n", + "\n", + "class NewFriends(BaseModel):\n", + " dogs: list[Dog]\n", + "\n", + "guard = Guard.from_pydantic(NewFriends, output_formatter=\"jsonformer\")\n", + "\n", + "# JSONFormer is only compatible with HF Pipelines and HF Models:\n", + "from transformers import pipeline\n", + "tiny_llama_pipeline = pipeline(\"text-generation\", \"TinyLlama/TinyLlama-1.1B-Chat-v1.0\")\n", + "\n", + "# Inference is straightforward:\n", + "response = guard(tiny_llama_pipeline, prompt=\"Please enjoy this list of good dogs:\")\n", + "\n", + "# `out` is a dict. Format it as JSON for readability:\n", + "import json\n", + "print(json.dumps(response.validated_output, indent=2))" + ] + } + ], + "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.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/examples/data/config.py b/docs/examples/data/config.py new file mode 100644 index 000000000..d4e6913b7 --- /dev/null +++ b/docs/examples/data/config.py @@ -0,0 +1,70 @@ +""" +All guards defined here will be initialized, if and only if +the application is using in memory guards. + +The application will use in memory guards if pg_host is left +undefined. Otherwise, a postgres instance will be started +and guards will be persisted into postgres. In that case, +these guards will not be initialized. +""" + +from typing import Any, Callable, Dict, Optional, Union +from guardrails import Guard, OnFailAction +from guardrails.validators import ( + Validator, + register_validator, + FailResult, + PassResult, + ValidationResult, +) +from guardrails.hub import RegexMatch + +name_case = Guard( + name="name-case", description="Checks that a string is in Name Case format." +).use(RegexMatch(regex="^(?:[A-Z][^\s]*\s?)+$")) + +all_caps = Guard( + name="all-caps", description="Checks that a string is all capital." +).use(RegexMatch(regex="^[A-Z\\s]*$")) + + +@register_validator(name="custom/dynamic-enum", data_type="all") +class DynamicEnum(Validator): + def __init__( + self, + enum_fetcher: Callable, + on_fail: Optional[Union[Callable, OnFailAction]] = None, + ): + super().__init__(on_fail=on_fail, enum_fetcher=enum_fetcher) + self.enum_fetcher = enum_fetcher + + def validate(self, value: Any, metdata: Optional[Dict] = {}) -> ValidationResult: + enum_fetcher_args = metdata.get("enum_fetcher_args", []) + dynamic_enum = self.enum_fetcher(*enum_fetcher_args) + + if value not in dynamic_enum: + return FailResult( + error_message="Value must be in the dynamically chosen enum!", + fix_value=dynamic_enum[0], + ) + return PassResult() + + +valid_topics = ["music", "cooking", "camping", "outdoors"] +invalid_topics = ["sports", "work", "ai"] +all_topics = [*valid_topics, *invalid_topics] + + +def custom_enum_fetcher(*args): + topic_type = args[0] + if topic_type == "valid": + return valid_topics + elif topic_type == "invalid": + return invalid_topics + return all_topics + + +custom_code_guard = Guard( + name="custom", + description="Uses a custom callable init argument for dynamic enum checks", +).use(DynamicEnum(custom_enum_fetcher)) diff --git a/docs/examples/guard_use.ipynb b/docs/examples/guard_use.ipynb new file mode 100644 index 000000000..9f4b5230c --- /dev/null +++ b/docs/examples/guard_use.ipynb @@ -0,0 +1,125 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Installing hub:\u001b[35m/\u001b[0m\u001b[35m/guardrails/\u001b[0m\u001b[95mregex_match...\u001b[0m\n", + "✅Successfully installed guardrails/regex_match!\n", + "\n", + "\n", + "Installing hub:\u001b[35m/\u001b[0m\u001b[35m/guardrails/\u001b[0m\u001b[95mvalid_range...\u001b[0m\n", + "✅Successfully installed guardrails/valid_range!\n", + "\n", + "\n" + ] + } + ], + "source": [ + "! guardrails hub install hub://guardrails/regex_match --quiet\n", + "! guardrails hub install hub://guardrails/valid_range --quiet" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "from pydantic import BaseModel, Field\n", + "from guardrails import Guard, OnFailAction\n", + "from guardrails.hub import RegexMatch, ValidRange\n", + "\n", + "class Person(BaseModel):\n", + " name: str\n", + " # Existing way of assigning validators\n", + " age: int = Field(validators=[ValidRange(0, 100, on_fail=OnFailAction.EXCEPTION)])\n", + " is_employed: bool" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Validation failed for field with errors: Value 101 is greater than 100.\n" + ] + } + ], + "source": [ + "import json\n", + "from guardrails.errors import ValidationError\n", + "\n", + "\n", + "guard = Guard.from_pydantic(Person)\n", + "\n", + "try:\n", + " guard.validate(json.dumps({\n", + " \"name\": \"john doe\",\n", + " \"age\": 101,\n", + " \"is_employed\": False\n", + " }))\n", + "except ValidationError as e:\n", + " print(e)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Validation failed for field with errors: Result must match ^(?:[A-Z][^\\s]*\\s?)+$\n" + ] + } + ], + "source": [ + "# Now let's add a new validator to the name field\n", + "\n", + "guard.use(RegexMatch(\"^(?:[A-Z][^\\\\s]*\\\\s?)+$\", on_fail=OnFailAction.EXCEPTION), on=\"$.name\")\n", + "\n", + "try:\n", + " guard.validate(json.dumps({\n", + " \"name\": \"john doe\",\n", + " \"age\": 30,\n", + " \"is_employed\": True\n", + " }))\n", + "except ValidationError as e:\n", + " print(e)" + ] + } + ], + "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.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/examples/guardrails_server.ipynb b/docs/examples/guardrails_server.ipynb new file mode 100644 index 000000000..45d346808 --- /dev/null +++ b/docs/examples/guardrails_server.ipynb @@ -0,0 +1,336 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m24.0\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.1\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n" + ] + } + ], + "source": [ + "! pip install \"guardrails-ai[api]==0.5.0a9\" -q" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "/Users/calebcourier/Projects/gr-mono/guardrails/docs/.venv/bin/guardrails\n" + ] + } + ], + "source": [ + "! which guardrails" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Installing hub:\u001b[35m/\u001b[0m\u001b[35m/guardrails/\u001b[0m\u001b[95mregex_match...\u001b[0m\n", + "✅Successfully installed guardrails/regex_match!\n", + "\n", + "\n" + ] + } + ], + "source": [ + "! guardrails hub install hub://guardrails/regex_match --quiet" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# Run this in a terminal\n", + "# guardrails start --config=./data/config.py" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "some-token\n", + "http://localhost:8000\n" + ] + } + ], + "source": [ + "import os\n", + "\n", + "os.environ[\"GUARDRAILS_API_KEY\"] = \"some-token\"\n", + "os.environ[\"GUARDRAILS_BASE_URL\"] = \"http://localhost:8000\"\n", + "\n", + "\n", + "print(os.environ.get(\"GUARDRAILS_API_KEY\"))\n", + "print(os.environ.get(\"GUARDRAILS_BASE_URL\"))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
ValidationOutcome(\n", + " call_id='5103958320',\n", + " raw_llm_output='Guardrails AI',\n", + " validated_output='Guardrails AI',\n", + " reask=None,\n", + " validation_passed=True,\n", + " error=None\n", + ")\n", + "\n" + ], + "text/plain": [ + "\u001b[1;35mValidationOutcome\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mcall_id\u001b[0m=\u001b[32m'5103958320'\u001b[0m,\n", + " \u001b[33mraw_llm_output\u001b[0m=\u001b[32m'Guardrails AI'\u001b[0m,\n", + " \u001b[33mvalidated_output\u001b[0m=\u001b[32m'Guardrails AI'\u001b[0m,\n", + " \u001b[33mreask\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33mvalidation_passed\u001b[0m=\u001b[3;92mTrue\u001b[0m,\n", + " \u001b[33merror\u001b[0m=\u001b[3;35mNone\u001b[0m\n", + "\u001b[1m)\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import logging\n", + "from rich import print\n", + "from guardrails import configure_logging\n", + "from guardrails import Guard\n", + "\n", + "\n", + "configure_logging(None, log_level=logging.DEBUG)\n", + "\n", + "name_case = Guard(name='name-case')\n", + "\n", + "response = name_case.parse(\n", + " llm_output=\"Guardrails AI\"\n", + ")\n", + "\n", + "print(response)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
[\n", + " Call(\n", + " id='5103958320',\n", + " iterations=[\n", + " Iteration(\n", + " id='5107862496',\n", + " index=0,\n", + " call_id='5103958320',\n", + " inputs=Inputs(\n", + " llm_api=None,\n", + " llm_output='Guardrails AI',\n", + " instructions=None,\n", + " prompt=None,\n", + " msg_history=None,\n", + " prompt_params={},\n", + " num_reasks=0,\n", + " metadata={},\n", + " full_schema_reask=False,\n", + " stream=False\n", + " ),\n", + " outputs=Outputs(\n", + " llm_response_info=LLMResponse(\n", + " prompt_token_count=None,\n", + " response_token_count=None,\n", + " output='Guardrails AI',\n", + " stream_output=None,\n", + " async_stream_output=None\n", + " ),\n", + " raw_output=None,\n", + " parsed_output='Guardrails AI',\n", + " validation_response='Guardrails AI',\n", + " guarded_output='Guardrails AI',\n", + " reasks=[],\n", + " validator_logs=[\n", + " ValidatorLogs(\n", + " validator_name='RegexMatch',\n", + " registered_name='guardrails/regex_match',\n", + " instance_id=4636712336,\n", + " property_path='$',\n", + " value_before_validation='Guardrails AI',\n", + " value_after_validation='Guardrails AI',\n", + " validation_result=PassResult(\n", + " outcome='pass',\n", + " value_override=<class \n", + "'guardrails.classes.validation.validation_result.PassResult.ValueOverrideSentinel'>,\n", + " metadata=None,\n", + " validated_chunk=None\n", + " ),\n", + " start_time=datetime.datetime(2024, 6, 27, 14, 14, 20, 649099),\n", + " end_time=datetime.datetime(2024, 6, 27, 14, 14, 20, 651227)\n", + " )\n", + " ],\n", + " error=None,\n", + " exception=None\n", + " )\n", + " )\n", + " ],\n", + " inputs=CallInputs(\n", + " llm_api=None,\n", + " llm_output=None,\n", + " instructions=None,\n", + " prompt=None,\n", + " msg_history=None,\n", + " prompt_params={},\n", + " num_reasks=0,\n", + " metadata={},\n", + " full_schema_reask=False,\n", + " stream=False,\n", + " args=[],\n", + " kwargs={'api_key': '***********************************************69ck'}\n", + " ),\n", + " exception=None\n", + " )\n", + "]\n", + "\n" + ], + "text/plain": [ + "\u001b[1m[\u001b[0m\n", + " \u001b[1;35mCall\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mid\u001b[0m=\u001b[32m'5103958320'\u001b[0m,\n", + " \u001b[33miterations\u001b[0m=\u001b[1m[\u001b[0m\n", + " \u001b[1;35mIteration\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mid\u001b[0m=\u001b[32m'5107862496'\u001b[0m,\n", + " \u001b[33mindex\u001b[0m=\u001b[1;36m0\u001b[0m,\n", + " \u001b[33mcall_id\u001b[0m=\u001b[32m'5103958320'\u001b[0m,\n", + " \u001b[33minputs\u001b[0m=\u001b[1;35mInputs\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mllm_api\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33mllm_output\u001b[0m=\u001b[32m'Guardrails AI'\u001b[0m,\n", + " \u001b[33minstructions\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33mprompt\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33mmsg_history\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33mprompt_params\u001b[0m=\u001b[1m{\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[33mnum_reasks\u001b[0m=\u001b[1;36m0\u001b[0m,\n", + " \u001b[33mmetadata\u001b[0m=\u001b[1m{\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[33mfull_schema_reask\u001b[0m=\u001b[3;91mFalse\u001b[0m,\n", + " \u001b[33mstream\u001b[0m=\u001b[3;91mFalse\u001b[0m\n", + " \u001b[1m)\u001b[0m,\n", + " \u001b[33moutputs\u001b[0m=\u001b[1;35mOutputs\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mllm_response_info\u001b[0m=\u001b[1;35mLLMResponse\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mprompt_token_count\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33mresponse_token_count\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33moutput\u001b[0m=\u001b[32m'Guardrails AI'\u001b[0m,\n", + " \u001b[33mstream_output\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33masync_stream_output\u001b[0m=\u001b[3;35mNone\u001b[0m\n", + " \u001b[1m)\u001b[0m,\n", + " \u001b[33mraw_output\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33mparsed_output\u001b[0m=\u001b[32m'Guardrails AI'\u001b[0m,\n", + " \u001b[33mvalidation_response\u001b[0m=\u001b[32m'Guardrails AI'\u001b[0m,\n", + " \u001b[33mguarded_output\u001b[0m=\u001b[32m'Guardrails AI'\u001b[0m,\n", + " \u001b[33mreasks\u001b[0m=\u001b[1m[\u001b[0m\u001b[1m]\u001b[0m,\n", + " \u001b[33mvalidator_logs\u001b[0m=\u001b[1m[\u001b[0m\n", + " \u001b[1;35mValidatorLogs\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mvalidator_name\u001b[0m=\u001b[32m'RegexMatch'\u001b[0m,\n", + " \u001b[33mregistered_name\u001b[0m=\u001b[32m'guardrails/regex_match'\u001b[0m,\n", + " \u001b[33minstance_id\u001b[0m=\u001b[1;36m4636712336\u001b[0m,\n", + " \u001b[33mproperty_path\u001b[0m=\u001b[32m'$'\u001b[0m,\n", + " \u001b[33mvalue_before_validation\u001b[0m=\u001b[32m'Guardrails AI'\u001b[0m,\n", + " \u001b[33mvalue_after_validation\u001b[0m=\u001b[32m'Guardrails AI'\u001b[0m,\n", + " \u001b[33mvalidation_result\u001b[0m=\u001b[1;35mPassResult\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33moutcome\u001b[0m=\u001b[32m'pass'\u001b[0m,\n", + " \u001b[33mvalue_override\u001b[0m=\u001b[1m<\u001b[0m\u001b[1;95mclass\u001b[0m\u001b[39m \u001b[0m\n", + "\u001b[32m'guardrails.classes.validation.validation_result.PassResult.ValueOverrideSentinel'\u001b[0m\u001b[1m>\u001b[0m,\n", + " \u001b[33mmetadata\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33mvalidated_chunk\u001b[0m=\u001b[3;35mNone\u001b[0m\n", + " \u001b[1m)\u001b[0m,\n", + " \u001b[33mstart_time\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2024\u001b[0m, \u001b[1;36m6\u001b[0m, \u001b[1;36m27\u001b[0m, \u001b[1;36m14\u001b[0m, \u001b[1;36m14\u001b[0m, \u001b[1;36m20\u001b[0m, \u001b[1;36m649099\u001b[0m\u001b[1m)\u001b[0m,\n", + " \u001b[33mend_time\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2024\u001b[0m, \u001b[1;36m6\u001b[0m, \u001b[1;36m27\u001b[0m, \u001b[1;36m14\u001b[0m, \u001b[1;36m14\u001b[0m, \u001b[1;36m20\u001b[0m, \u001b[1;36m651227\u001b[0m\u001b[1m)\u001b[0m\n", + " \u001b[1m)\u001b[0m\n", + " \u001b[1m]\u001b[0m,\n", + " \u001b[33merror\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33mexception\u001b[0m=\u001b[3;35mNone\u001b[0m\n", + " \u001b[1m)\u001b[0m\n", + " \u001b[1m)\u001b[0m\n", + " \u001b[1m]\u001b[0m,\n", + " \u001b[33minputs\u001b[0m=\u001b[1;35mCallInputs\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mllm_api\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33mllm_output\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33minstructions\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33mprompt\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33mmsg_history\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33mprompt_params\u001b[0m=\u001b[1m{\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[33mnum_reasks\u001b[0m=\u001b[1;36m0\u001b[0m,\n", + " \u001b[33mmetadata\u001b[0m=\u001b[1m{\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[33mfull_schema_reask\u001b[0m=\u001b[3;91mFalse\u001b[0m,\n", + " \u001b[33mstream\u001b[0m=\u001b[3;91mFalse\u001b[0m,\n", + " \u001b[33margs\u001b[0m=\u001b[1m[\u001b[0m\u001b[1m]\u001b[0m,\n", + " \u001b[33mkwargs\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'api_key'\u001b[0m: \u001b[32m'***********************************************69ck'\u001b[0m\u001b[1m}\u001b[0m\n", + " \u001b[1m)\u001b[0m,\n", + " \u001b[33mexception\u001b[0m=\u001b[3;35mNone\u001b[0m\n", + " \u001b[1m)\u001b[0m\n", + "\u001b[1m]\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "print(name_case.history)" + ] + } + ], + "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.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/examples/json_function_calling_tools.ipynb b/docs/examples/json_function_calling_tools.ipynb new file mode 100644 index 000000000..d47f414d0 --- /dev/null +++ b/docs/examples/json_function_calling_tools.ipynb @@ -0,0 +1,989 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Installing hub:\u001b[35m/\u001b[0m\u001b[35m/guardrails/\u001b[0m\u001b[95mregex_match...\u001b[0m\n", + "✅Successfully installed guardrails/regex_match!\n", + "\n", + "\n" + ] + } + ], + "source": [ + "! guardrails hub install hub://guardrails/regex_match --quiet" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "chat_history=\"\"\"\n", + "nelson and murdock: i need a pickup 797 9th Avenue, manila envelope, June 3 10:00am with dropoff 10:30am Courthouse, 61 Center Street C/O frank james\n", + "operator: quote - $23.00\n", + "neslon and murdock: perfect, we accept the quote\n", + "operator: 797 9th ave, 10:00am pickup comfirmed\n", + "abc flowers: i need a pickup of a flowers from abc flowers at 21 3rd street at 11:00am on june 2 with a dropoff at 75th Ave at 5:30pm same day\n", + "operator: 21 3rd street flowers quote - $14.50\n", + "abc flowers: accepted\n", + "polk and wardell: i need a pickup of a bagels from Bakers Co at 331 5th street at 11:00am on june 3 with a dropoff at 75th Ave at 5:30pm same day\n", + "operator: 331 5th street bagels quote - $34.50\n", + "polk and wardell: accepted\n", + "\"\"\"\n", + "\n", + "prompt = \"\"\"\n", + "From the chat exchanges below extract a schedule of deliveries.\n", + "Chats:\n", + "${chat_history}\n", + "\"\"\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
[\n", + " {\n", + " 'type': 'function',\n", + " 'function': {\n", + " 'name': 'gd_response_tool',\n", + " 'description': 'A tool for generating responses to guardrails. It must be called last in every \n", + "response.',\n", + " 'parameters': {\n", + " '$defs': {\n", + " 'Delivery': {\n", + " 'properties': {\n", + " 'custome_name': {\n", + " 'description': 'customer name',\n", + " 'title': 'Custome Name',\n", + " 'type': 'string',\n", + " 'validators': [{'rail_alias': 'guardrails/regex_match'}]\n", + " },\n", + " 'pickup_time': {\n", + " 'description': 'date and time of pickup',\n", + " 'title': 'Pickup Time',\n", + " 'type': 'string'\n", + " },\n", + " 'pickup_location': {\n", + " 'description': 'address of pickup',\n", + " 'title': 'Pickup Location',\n", + " 'type': 'string'\n", + " },\n", + " 'dropoff_time': {\n", + " 'description': 'date and time of dropoff',\n", + " 'title': 'Dropoff Time',\n", + " 'type': 'string'\n", + " },\n", + " 'dropoff_location': {\n", + " 'description': 'address of dropoff',\n", + " 'title': 'Dropoff Location',\n", + " 'type': 'string'\n", + " },\n", + " 'price': {\n", + " 'description': 'price of delivery with currency symbol included',\n", + " 'title': 'Price',\n", + " 'type': 'string'\n", + " }\n", + " },\n", + " 'required': [\n", + " 'custome_name',\n", + " 'pickup_time',\n", + " 'pickup_location',\n", + " 'dropoff_time',\n", + " 'dropoff_location',\n", + " 'price'\n", + " ],\n", + " 'title': 'Delivery',\n", + " 'type': 'object'\n", + " }\n", + " },\n", + " 'properties': {\n", + " 'deliveries': {'items': {'$ref': '#/$defs/Delivery'}, 'title': 'Deliveries', 'type': 'array'}\n", + " },\n", + " 'required': ['deliveries'],\n", + " 'type': 'object',\n", + " 'title': 'Schedule'\n", + " },\n", + " 'required': ['deliveries']\n", + " }\n", + " }\n", + "]\n", + "\n" + ], + "text/plain": [ + "\u001b[1m[\u001b[0m\n", + " \u001b[1m{\u001b[0m\n", + " \u001b[32m'type'\u001b[0m: \u001b[32m'function'\u001b[0m,\n", + " \u001b[32m'function'\u001b[0m: \u001b[1m{\u001b[0m\n", + " \u001b[32m'name'\u001b[0m: \u001b[32m'gd_response_tool'\u001b[0m,\n", + " \u001b[32m'description'\u001b[0m: \u001b[32m'A tool for generating responses to guardrails. It must be called last in every \u001b[0m\n", + "\u001b[32mresponse.'\u001b[0m,\n", + " \u001b[32m'parameters'\u001b[0m: \u001b[1m{\u001b[0m\n", + " \u001b[32m'$defs'\u001b[0m: \u001b[1m{\u001b[0m\n", + " \u001b[32m'Delivery'\u001b[0m: \u001b[1m{\u001b[0m\n", + " \u001b[32m'properties'\u001b[0m: \u001b[1m{\u001b[0m\n", + " \u001b[32m'custome_name'\u001b[0m: \u001b[1m{\u001b[0m\n", + " \u001b[32m'description'\u001b[0m: \u001b[32m'customer name'\u001b[0m,\n", + " \u001b[32m'title'\u001b[0m: \u001b[32m'Custome Name'\u001b[0m,\n", + " \u001b[32m'type'\u001b[0m: \u001b[32m'string'\u001b[0m,\n", + " \u001b[32m'validators'\u001b[0m: \u001b[1m[\u001b[0m\u001b[1m{\u001b[0m\u001b[32m'rail_alias'\u001b[0m: \u001b[32m'guardrails/regex_match'\u001b[0m\u001b[1m}\u001b[0m\u001b[1m]\u001b[0m\n", + " \u001b[1m}\u001b[0m,\n", + " \u001b[32m'pickup_time'\u001b[0m: \u001b[1m{\u001b[0m\n", + " \u001b[32m'description'\u001b[0m: \u001b[32m'date and time of pickup'\u001b[0m,\n", + " \u001b[32m'title'\u001b[0m: \u001b[32m'Pickup Time'\u001b[0m,\n", + " \u001b[32m'type'\u001b[0m: \u001b[32m'string'\u001b[0m\n", + " \u001b[1m}\u001b[0m,\n", + " \u001b[32m'pickup_location'\u001b[0m: \u001b[1m{\u001b[0m\n", + " \u001b[32m'description'\u001b[0m: \u001b[32m'address of pickup'\u001b[0m,\n", + " \u001b[32m'title'\u001b[0m: \u001b[32m'Pickup Location'\u001b[0m,\n", + " \u001b[32m'type'\u001b[0m: \u001b[32m'string'\u001b[0m\n", + " \u001b[1m}\u001b[0m,\n", + " \u001b[32m'dropoff_time'\u001b[0m: \u001b[1m{\u001b[0m\n", + " \u001b[32m'description'\u001b[0m: \u001b[32m'date and time of dropoff'\u001b[0m,\n", + " \u001b[32m'title'\u001b[0m: \u001b[32m'Dropoff Time'\u001b[0m,\n", + " \u001b[32m'type'\u001b[0m: \u001b[32m'string'\u001b[0m\n", + " \u001b[1m}\u001b[0m,\n", + " \u001b[32m'dropoff_location'\u001b[0m: \u001b[1m{\u001b[0m\n", + " \u001b[32m'description'\u001b[0m: \u001b[32m'address of dropoff'\u001b[0m,\n", + " \u001b[32m'title'\u001b[0m: \u001b[32m'Dropoff Location'\u001b[0m,\n", + " \u001b[32m'type'\u001b[0m: \u001b[32m'string'\u001b[0m\n", + " \u001b[1m}\u001b[0m,\n", + " \u001b[32m'price'\u001b[0m: \u001b[1m{\u001b[0m\n", + " \u001b[32m'description'\u001b[0m: \u001b[32m'price of delivery with currency symbol included'\u001b[0m,\n", + " \u001b[32m'title'\u001b[0m: \u001b[32m'Price'\u001b[0m,\n", + " \u001b[32m'type'\u001b[0m: \u001b[32m'string'\u001b[0m\n", + " \u001b[1m}\u001b[0m\n", + " \u001b[1m}\u001b[0m,\n", + " \u001b[32m'required'\u001b[0m: \u001b[1m[\u001b[0m\n", + " \u001b[32m'custome_name'\u001b[0m,\n", + " \u001b[32m'pickup_time'\u001b[0m,\n", + " \u001b[32m'pickup_location'\u001b[0m,\n", + " \u001b[32m'dropoff_time'\u001b[0m,\n", + " \u001b[32m'dropoff_location'\u001b[0m,\n", + " \u001b[32m'price'\u001b[0m\n", + " \u001b[1m]\u001b[0m,\n", + " \u001b[32m'title'\u001b[0m: \u001b[32m'Delivery'\u001b[0m,\n", + " \u001b[32m'type'\u001b[0m: \u001b[32m'object'\u001b[0m\n", + " \u001b[1m}\u001b[0m\n", + " \u001b[1m}\u001b[0m,\n", + " \u001b[32m'properties'\u001b[0m: \u001b[1m{\u001b[0m\n", + " \u001b[32m'deliveries'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'items'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'$ref'\u001b[0m: \u001b[32m'#/$defs/Delivery'\u001b[0m\u001b[1m}\u001b[0m, \u001b[32m'title'\u001b[0m: \u001b[32m'Deliveries'\u001b[0m, \u001b[32m'type'\u001b[0m: \u001b[32m'array'\u001b[0m\u001b[1m}\u001b[0m\n", + " \u001b[1m}\u001b[0m,\n", + " \u001b[32m'required'\u001b[0m: \u001b[1m[\u001b[0m\u001b[32m'deliveries'\u001b[0m\u001b[1m]\u001b[0m,\n", + " \u001b[32m'type'\u001b[0m: \u001b[32m'object'\u001b[0m,\n", + " \u001b[32m'title'\u001b[0m: \u001b[32m'Schedule'\u001b[0m\n", + " \u001b[1m}\u001b[0m,\n", + " \u001b[32m'required'\u001b[0m: \u001b[1m[\u001b[0m\u001b[32m'deliveries'\u001b[0m\u001b[1m]\u001b[0m\n", + " \u001b[1m}\u001b[0m\n", + " \u001b[1m}\u001b[0m\n", + "\u001b[1m]\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from rich import print\n", + "from guardrails import Guard\n", + "from guardrails.hub import RegexMatch\n", + "from pydantic import BaseModel, Field\n", + "from typing import List\n", + "\n", + "NAME_REGEX = \"^[A-Z][a-z]+\\\\s[A-Z][a-z]+$\"\n", + "\n", + "class Delivery(BaseModel):\n", + " custome_name: str= Field(validators=[RegexMatch(regex=NAME_REGEX)], description=\"customer name\")\n", + " pickup_time: str= Field(description=\"date and time of pickup\")\n", + " pickup_location: str= Field(description=\"address of pickup\")\n", + " dropoff_time: str= Field(description=\"date and time of dropoff\")\n", + " dropoff_location: str= Field(description=\"address of dropoff\")\n", + " price: str = Field(description=\"price of delivery with currency symbol included\")\n", + "\n", + "class Schedule(BaseModel):\n", + " deliveries: List[Delivery]\n", + "\n", + "pydantic_guard = Guard.from_pydantic(Schedule)\n", + "\n", + "# Generate the function calling tool and add it to the list\n", + "pydantic_guard_tools = pydantic_guard.add_json_function_calling_tool([])\n", + "\n", + "print(pydantic_guard_tools)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
[\n", + " {\n", + " 'type': 'function',\n", + " 'function': {\n", + " 'name': 'gd_response_tool',\n", + " 'description': 'A tool for generating responses to guardrails. It must be called last in every \n", + "response.',\n", + " 'parameters': {\n", + " 'properties': {\n", + " 'deliveries': {\n", + " 'items': {\n", + " 'properties': {\n", + " 'customer_name': {'type': 'string', 'description': 'customer name'},\n", + " 'pickup_time': {'type': 'string', 'description': 'date and time of pickup'},\n", + " 'pickup_location': {'type': 'string', 'description': 'address of pickup'},\n", + " 'dropoff_time': {'type': 'string', 'description': 'date and time of dropoff'},\n", + " 'dropoff_location': {'type': 'string', 'description': 'address of dropoff'},\n", + " 'price': {\n", + " 'type': 'string',\n", + " 'description': 'price of delivery with currency symbol included'\n", + " }\n", + " },\n", + " 'required': [\n", + " 'customer_name',\n", + " 'pickup_time',\n", + " 'pickup_location',\n", + " 'dropoff_time',\n", + " 'dropoff_location',\n", + " 'price'\n", + " ],\n", + " 'type': 'object'\n", + " },\n", + " 'type': 'array'\n", + " }\n", + " },\n", + " 'required': ['deliveries'],\n", + " 'type': 'object'\n", + " },\n", + " 'required': ['deliveries']\n", + " }\n", + " }\n", + "]\n", + "\n" + ], + "text/plain": [ + "\u001b[1m[\u001b[0m\n", + " \u001b[1m{\u001b[0m\n", + " \u001b[32m'type'\u001b[0m: \u001b[32m'function'\u001b[0m,\n", + " \u001b[32m'function'\u001b[0m: \u001b[1m{\u001b[0m\n", + " \u001b[32m'name'\u001b[0m: \u001b[32m'gd_response_tool'\u001b[0m,\n", + " \u001b[32m'description'\u001b[0m: \u001b[32m'A tool for generating responses to guardrails. It must be called last in every \u001b[0m\n", + "\u001b[32mresponse.'\u001b[0m,\n", + " \u001b[32m'parameters'\u001b[0m: \u001b[1m{\u001b[0m\n", + " \u001b[32m'properties'\u001b[0m: \u001b[1m{\u001b[0m\n", + " \u001b[32m'deliveries'\u001b[0m: \u001b[1m{\u001b[0m\n", + " \u001b[32m'items'\u001b[0m: \u001b[1m{\u001b[0m\n", + " \u001b[32m'properties'\u001b[0m: \u001b[1m{\u001b[0m\n", + " \u001b[32m'customer_name'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'type'\u001b[0m: \u001b[32m'string'\u001b[0m, \u001b[32m'description'\u001b[0m: \u001b[32m'customer name'\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[32m'pickup_time'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'type'\u001b[0m: \u001b[32m'string'\u001b[0m, \u001b[32m'description'\u001b[0m: \u001b[32m'date and time of pickup'\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[32m'pickup_location'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'type'\u001b[0m: \u001b[32m'string'\u001b[0m, \u001b[32m'description'\u001b[0m: \u001b[32m'address of pickup'\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[32m'dropoff_time'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'type'\u001b[0m: \u001b[32m'string'\u001b[0m, \u001b[32m'description'\u001b[0m: \u001b[32m'date and time of dropoff'\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[32m'dropoff_location'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'type'\u001b[0m: \u001b[32m'string'\u001b[0m, \u001b[32m'description'\u001b[0m: \u001b[32m'address of dropoff'\u001b[0m\u001b[1m}\u001b[0m,\n", + " \u001b[32m'price'\u001b[0m: \u001b[1m{\u001b[0m\n", + " \u001b[32m'type'\u001b[0m: \u001b[32m'string'\u001b[0m,\n", + " \u001b[32m'description'\u001b[0m: \u001b[32m'price of delivery with currency symbol included'\u001b[0m\n", + " \u001b[1m}\u001b[0m\n", + " \u001b[1m}\u001b[0m,\n", + " \u001b[32m'required'\u001b[0m: \u001b[1m[\u001b[0m\n", + " \u001b[32m'customer_name'\u001b[0m,\n", + " \u001b[32m'pickup_time'\u001b[0m,\n", + " \u001b[32m'pickup_location'\u001b[0m,\n", + " \u001b[32m'dropoff_time'\u001b[0m,\n", + " \u001b[32m'dropoff_location'\u001b[0m,\n", + " \u001b[32m'price'\u001b[0m\n", + " \u001b[1m]\u001b[0m,\n", + " \u001b[32m'type'\u001b[0m: \u001b[32m'object'\u001b[0m\n", + " \u001b[1m}\u001b[0m,\n", + " \u001b[32m'type'\u001b[0m: \u001b[32m'array'\u001b[0m\n", + " \u001b[1m}\u001b[0m\n", + " \u001b[1m}\u001b[0m,\n", + " \u001b[32m'required'\u001b[0m: \u001b[1m[\u001b[0m\u001b[32m'deliveries'\u001b[0m\u001b[1m]\u001b[0m,\n", + " \u001b[32m'type'\u001b[0m: \u001b[32m'object'\u001b[0m\n", + " \u001b[1m}\u001b[0m,\n", + " \u001b[32m'required'\u001b[0m: \u001b[1m[\u001b[0m\u001b[32m'deliveries'\u001b[0m\u001b[1m]\u001b[0m\n", + " \u001b[1m}\u001b[0m\n", + " \u001b[1m}\u001b[0m\n", + "\u001b[1m]\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "rail = \"\"\"\n", + "
ValidationOutcome(\n", + " call_id='4801405536',\n", + " raw_llm_output='{\"deliveries\": [{\"customer_name\": \"Nelson Murdock\", \"pickup_time\": \"2022-01-15T10:00:00\", \n", + "\"pickup_location\": \"123 Main Street\", \"dropoff_time\": \"2022-01-15T12:00:00\", \"dropoff_location\": \"456 Elm Street\", \n", + "\"price\": \"$50\"}, {\"customer_name\": \"Abc Flowers\", \"pickup_time\": \"2022-01-16T11:00:00\", \"pickup_location\": \"456 Oak\n", + "Avenue\", \"dropoff_time\": \"2022-01-16T13:00:00\", \"dropoff_location\": \"789 Pine Road\", \"price\": \"$60\"}, \n", + "{\"customer_name\": \"Polk Wardell\", \"pickup_time\": \"2022-01-17T09:00:00\", \"pickup_location\": \"789 Maple Lane\", \n", + "\"dropoff_time\": \"2022-01-17T11:00:00\", \"dropoff_location\": \"234 Birch Boulevard\", \"price\": \"$70\"}]}',\n", + " validated_output={\n", + " 'deliveries': [\n", + " {\n", + " 'customer_name': 'Nelson Murdock',\n", + " 'pickup_time': 'June 3 10:00am',\n", + " 'pickup_location': '797 9th Avenue',\n", + " 'dropoff_time': 'June 3 10:30am',\n", + " 'dropoff_location': 'Courthouse, 61 Center Street C/O frank james',\n", + " 'price': '$23.00'\n", + " },\n", + " {\n", + " 'customer_name': 'Abc Flowers',\n", + " 'pickup_time': 'June 2 11:00am',\n", + " 'pickup_location': '21 3rd street',\n", + " 'dropoff_time': 'June 2 5:30pm',\n", + " 'dropoff_location': '75th Ave',\n", + " 'price': '$14.50'\n", + " },\n", + " {\n", + " 'customer_name': 'Polk Wardell',\n", + " 'pickup_time': 'June 3 11:00am',\n", + " 'pickup_location': '331 5th street',\n", + " 'dropoff_time': 'June 3 5:30pm',\n", + " 'dropoff_location': '75th Ave',\n", + " 'price': '$34.50'\n", + " }\n", + " ]\n", + " },\n", + " reask=None,\n", + " validation_passed=True,\n", + " error=None\n", + ")\n", + "\n" + ], + "text/plain": [ + "\u001b[1;35mValidationOutcome\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mcall_id\u001b[0m=\u001b[32m'4801405536'\u001b[0m,\n", + " \u001b[33mraw_llm_output\u001b[0m=\u001b[32m'\u001b[0m\u001b[32m{\u001b[0m\u001b[32m\"deliveries\": \u001b[0m\u001b[32m[\u001b[0m\u001b[32m{\u001b[0m\u001b[32m\"customer_name\": \"Nelson Murdock\", \"pickup_time\": \"2022-01-15T10:00:00\", \u001b[0m\n", + "\u001b[32m\"pickup_location\": \"123 Main Street\", \"dropoff_time\": \"2022-01-15T12:00:00\", \"dropoff_location\": \"456 Elm Street\", \u001b[0m\n", + "\u001b[32m\"price\": \"$50\"\u001b[0m\u001b[32m}\u001b[0m\u001b[32m, \u001b[0m\u001b[32m{\u001b[0m\u001b[32m\"customer_name\": \"Abc Flowers\", \"pickup_time\": \"2022-01-16T11:00:00\", \"pickup_location\": \"456 Oak\u001b[0m\n", + "\u001b[32mAvenue\", \"dropoff_time\": \"2022-01-16T13:00:00\", \"dropoff_location\": \"789 Pine Road\", \"price\": \"$60\"\u001b[0m\u001b[32m}\u001b[0m\u001b[32m, \u001b[0m\n", + "\u001b[32m{\u001b[0m\u001b[32m\"customer_name\": \"Polk Wardell\", \"pickup_time\": \"2022-01-17T09:00:00\", \"pickup_location\": \"789 Maple Lane\", \u001b[0m\n", + "\u001b[32m\"dropoff_time\": \"2022-01-17T11:00:00\", \"dropoff_location\": \"234 Birch Boulevard\", \"price\": \"$70\"\u001b[0m\u001b[32m}\u001b[0m\u001b[32m]\u001b[0m\u001b[32m}\u001b[0m\u001b[32m'\u001b[0m,\n", + " \u001b[33mvalidated_output\u001b[0m=\u001b[1m{\u001b[0m\n", + " \u001b[32m'deliveries'\u001b[0m: \u001b[1m[\u001b[0m\n", + " \u001b[1m{\u001b[0m\n", + " \u001b[32m'customer_name'\u001b[0m: \u001b[32m'Nelson Murdock'\u001b[0m,\n", + " \u001b[32m'pickup_time'\u001b[0m: \u001b[32m'June 3 10:00am'\u001b[0m,\n", + " \u001b[32m'pickup_location'\u001b[0m: \u001b[32m'797 9th Avenue'\u001b[0m,\n", + " \u001b[32m'dropoff_time'\u001b[0m: \u001b[32m'June 3 10:30am'\u001b[0m,\n", + " \u001b[32m'dropoff_location'\u001b[0m: \u001b[32m'Courthouse, 61 Center Street C/O frank james'\u001b[0m,\n", + " \u001b[32m'price'\u001b[0m: \u001b[32m'$23.00'\u001b[0m\n", + " \u001b[1m}\u001b[0m,\n", + " \u001b[1m{\u001b[0m\n", + " \u001b[32m'customer_name'\u001b[0m: \u001b[32m'Abc Flowers'\u001b[0m,\n", + " \u001b[32m'pickup_time'\u001b[0m: \u001b[32m'June 2 11:00am'\u001b[0m,\n", + " \u001b[32m'pickup_location'\u001b[0m: \u001b[32m'21 3rd street'\u001b[0m,\n", + " \u001b[32m'dropoff_time'\u001b[0m: \u001b[32m'June 2 5:30pm'\u001b[0m,\n", + " \u001b[32m'dropoff_location'\u001b[0m: \u001b[32m'75th Ave'\u001b[0m,\n", + " \u001b[32m'price'\u001b[0m: \u001b[32m'$14.50'\u001b[0m\n", + " \u001b[1m}\u001b[0m,\n", + " \u001b[1m{\u001b[0m\n", + " \u001b[32m'customer_name'\u001b[0m: \u001b[32m'Polk Wardell'\u001b[0m,\n", + " \u001b[32m'pickup_time'\u001b[0m: \u001b[32m'June 3 11:00am'\u001b[0m,\n", + " \u001b[32m'pickup_location'\u001b[0m: \u001b[32m'331 5th street'\u001b[0m,\n", + " \u001b[32m'dropoff_time'\u001b[0m: \u001b[32m'June 3 5:30pm'\u001b[0m,\n", + " \u001b[32m'dropoff_location'\u001b[0m: \u001b[32m'75th Ave'\u001b[0m,\n", + " \u001b[32m'price'\u001b[0m: \u001b[32m'$34.50'\u001b[0m\n", + " \u001b[1m}\u001b[0m\n", + " \u001b[1m]\u001b[0m\n", + " \u001b[1m}\u001b[0m,\n", + " \u001b[33mreask\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33mvalidation_passed\u001b[0m=\u001b[3;92mTrue\u001b[0m,\n", + " \u001b[33merror\u001b[0m=\u001b[3;35mNone\u001b[0m\n", + "\u001b[1m)\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import openai\n", + "\n", + "response = rail_guard(\n", + " openai.chat.completions.create,\n", + " model=\"gpt-3.5-turbo\",\n", + " instructions=\"You are a helpful assistant.\",\n", + " prompt=prompt,\n", + " prompt_params={\"chat_history\": chat_history},\n", + " tools=rail_guard_tools,\n", + " tool_choice=\"required\",\n", + ")\n", + "\n", + "print(response)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
Logs\n", + "├── ╭────────────────────────────────────────────────── Step 0 ───────────────────────────────────────────────────╮\n", + "│ │ ╭──────────────────────────────────────────────── Prompt ─────────────────────────────────────────────────╮ │\n", + "│ │ │ │ │\n", + "│ │ │ From the chat exchanges below extract a schedule of deliveries. │ │\n", + "│ │ │ Chats: │ │\n", + "│ │ │ │ │\n", + "│ │ │ nelson and murdock: i need a pickup 797 9th Avenue, manila envelope, June 3 10:00am with dropoff │ │\n", + "│ │ │ 10:30am Courthouse, 61 Center Street C/O frank james │ │\n", + "│ │ │ operator: quote - $23.00 │ │\n", + "│ │ │ neslon and murdock: perfect, we accept the quote │ │\n", + "│ │ │ operator: 797 9th ave, 10:00am pickup comfirmed │ │\n", + "│ │ │ abc flowers: i need a pickup of a flowers from abc flowers at 21 3rd street at 11:00am on june 2 with a │ │\n", + "│ │ │ dropoff at 75th Ave at 5:30pm same day │ │\n", + "│ │ │ operator: 21 3rd street flowers quote - $14.50 │ │\n", + "│ │ │ abc flowers: accepted │ │\n", + "│ │ │ polk and wardell: i need a pickup of a bagels from Bakers Co at 331 5th street at 11:00am on june 3 │ │\n", + "│ │ │ with a dropoff at 75th Ave at 5:30pm same day │ │\n", + "│ │ │ operator: 331 5th street bagels quote - $34.50 │ │\n", + "│ │ │ polk and wardell: accepted │ │\n", + "│ │ │ │ │\n", + "│ │ │ │ │\n", + "│ │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │\n", + "│ │ ╭───────────────────────────────────────────── Instructions ──────────────────────────────────────────────╮ │\n", + "│ │ │ You are a helpful assistant. │ │\n", + "│ │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │\n", + "│ │ ╭──────────────────────────────────────────── Message History ────────────────────────────────────────────╮ │\n", + "│ │ │ No message history. │ │\n", + "│ │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │\n", + "│ │ ╭──────────────────────────────────────────── Raw LLM Output ─────────────────────────────────────────────╮ │\n", + "│ │ │ {\"deliveries\":[{\"customer_name\":\"nelson and murdock\",\"pickup_time\":\"June 3 │ │\n", + "│ │ │ 10:00am\",\"pickup_location\":\"797 9th Avenue\",\"dropoff_time\":\"June 3 │ │\n", + "│ │ │ 10:30am\",\"dropoff_location\":\"Courthouse, 61 Center Street C/O frank │ │\n", + "│ │ │ james\",\"price\":\"$23.00\"},{\"customer_name\":\"abc flowers\",\"pickup_time\":\"June 2 │ │\n", + "│ │ │ 11:00am\",\"pickup_location\":\"21 3rd street\",\"dropoff_time\":\"June 2 5:30pm\",\"dropoff_location\":\"75th │ │\n", + "│ │ │ Ave\",\"price\":\"$14.50\"},{\"customer_name\":\"polk and wardell\",\"pickup_time\":\"June 3 │ │\n", + "│ │ │ 11:00am\",\"pickup_location\":\"331 5th street\",\"dropoff_time\":\"June 3 5:30pm\",\"dropoff_location\":\"75th │ │\n", + "│ │ │ Ave\",\"price\":\"$34.50\"}]} │ │\n", + "│ │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │\n", + "│ │ ╭─────────────────────────────────────────── Validated Output ────────────────────────────────────────────╮ │\n", + "│ │ │ { │ │\n", + "│ │ │ 'deliveries': [ │ │\n", + "│ │ │ { │ │\n", + "│ │ │ 'customer_name': FieldReAsk( │ │\n", + "│ │ │ incorrect_value='nelson and murdock', │ │\n", + "│ │ │ fail_results=[ │ │\n", + "│ │ │ FailResult( │ │\n", + "│ │ │ outcome='fail', │ │\n", + "│ │ │ error_message='Result must match ^[A-Z]+\\\\s[A-Z]+$', │ │\n", + "│ │ │ fix_value='Rdbuqatcsperioirtnincsfincsctvizmazkylbbhmrenbdyzkjeogozpyoiyvopuegv │ │\n", + "│ │ │ vudra\\x0cShvihshzagoeniiawwdumtstqwhanryigafmqrfulfwelkuaozbtuvwycgcjwxxvqbawhqvclb', │ │\n", + "│ │ │ error_spans=None, │ │\n", + "│ │ │ metadata=None, │ │\n", + "│ │ │ validated_chunk=None │ │\n", + "│ │ │ ) │ │\n", + "│ │ │ ], │ │\n", + "│ │ │ additional_properties={}, │ │\n", + "│ │ │ path=['deliveries', 0, 'customer_name'] │ │\n", + "│ │ │ ), │ │\n", + "│ │ │ 'pickup_time': 'June 3 10:00am', │ │\n", + "│ │ │ 'pickup_location': '797 9th Avenue', │ │\n", + "│ │ │ 'dropoff_time': 'June 3 10:30am', │ │\n", + "│ │ │ 'dropoff_location': 'Courthouse, 61 Center Street C/O frank james', │ │\n", + "│ │ │ 'price': '$23.00' │ │\n", + "│ │ │ }, │ │\n", + "│ │ │ { │ │\n", + "│ │ │ 'customer_name': FieldReAsk( │ │\n", + "│ │ │ incorrect_value='abc flowers', │ │\n", + "│ │ │ fail_results=[ │ │\n", + "│ │ │ FailResult( │ │\n", + "│ │ │ outcome='fail', │ │\n", + "│ │ │ error_message='Result must match ^[A-Z]+\\\\s[A-Z]+$', │ │\n", + "│ │ │ fix_value='Gzlawzbrtphaiwzdthhmmxiwwykhqnrsladoovnoryhvwazvhrqjzazeihkfplevvnej │ │\n", + "│ │ │ rqurkwin\\x0cMprzjamtwmz', │ │\n", + "│ │ │ error_spans=None, │ │\n", + "│ │ │ metadata=None, │ │\n", + "│ │ │ validated_chunk=None │ │\n", + "│ │ │ ) │ │\n", + "│ │ │ ], │ │\n", + "│ │ │ additional_properties={}, │ │\n", + "│ │ │ path=['deliveries', 1, 'customer_name'] │ │\n", + "│ │ │ ), │ │\n", + "│ │ │ 'pickup_time': 'June 2 11:00am', │ │\n", + "│ │ │ 'pickup_location': '21 3rd street', │ │\n", + "│ │ │ 'dropoff_time': 'June 2 5:30pm', │ │\n", + "│ │ │ 'dropoff_location': '75th Ave', │ │\n", + "│ │ │ 'price': '$14.50' │ │\n", + "│ │ │ }, │ │\n", + "│ │ │ { │ │\n", + "│ │ │ 'customer_name': FieldReAsk( │ │\n", + "│ │ │ incorrect_value='polk and wardell', │ │\n", + "│ │ │ fail_results=[ │ │\n", + "│ │ │ FailResult( │ │\n", + "│ │ │ outcome='fail', │ │\n", + "│ │ │ error_message='Result must match ^[A-Z]+\\\\s[A-Z]+$', │ │\n", + "│ │ │ fix_value='Rcznucwiwovoqjszkwmwbwtepefflvbeciylxkjkxdybjadslmdykapacufjpgolktvq │ │\n", + "│ │ │ lbsydhuqfzygsvckomowxbjwnnqzhy\\tXutiwlnafoyguxexopjwoxilwea', │ │\n", + "│ │ │ error_spans=None, │ │\n", + "│ │ │ metadata=None, │ │\n", + "│ │ │ validated_chunk=None │ │\n", + "│ │ │ ) │ │\n", + "│ │ │ ], │ │\n", + "│ │ │ additional_properties={}, │ │\n", + "│ │ │ path=['deliveries', 2, 'customer_name'] │ │\n", + "│ │ │ ), │ │\n", + "│ │ │ 'pickup_time': 'June 3 11:00am', │ │\n", + "│ │ │ 'pickup_location': '331 5th street', │ │\n", + "│ │ │ 'dropoff_time': 'June 3 5:30pm', │ │\n", + "│ │ │ 'dropoff_location': '75th Ave', │ │\n", + "│ │ │ 'price': '$34.50' │ │\n", + "│ │ │ } │ │\n", + "│ │ │ ] │ │\n", + "│ │ │ } │ │\n", + "│ │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │\n", + "│ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n", + "└── ╭────────────────────────────────────────────────── Step 1 ───────────────────────────────────────────────────╮\n", + " │ ╭──────────────────────────────────────────────── Prompt ─────────────────────────────────────────────────╮ │\n", + " │ │ │ │\n", + " │ │ I was given the following JSON response, which had problems due to incorrect values. │ │\n", + " │ │ │ │\n", + " │ │ { │ │\n", + " │ │ \"deliveries\": [ │ │\n", + " │ │ { │ │\n", + " │ │ \"customer_name\": { │ │\n", + " │ │ \"incorrect_value\": \"nelson and murdock\", │ │\n", + " │ │ \"error_messages\": [ │ │\n", + " │ │ \"Result must match ^[A-Z]+\\\\s[A-Z]+$\" │ │\n", + " │ │ ] │ │\n", + " │ │ } │ │\n", + " │ │ }, │ │\n", + " │ │ { │ │\n", + " │ │ \"customer_name\": { │ │\n", + " │ │ \"incorrect_value\": \"abc flowers\", │ │\n", + " │ │ \"error_messages\": [ │ │\n", + " │ │ \"Result must match ^[A-Z]+\\\\s[A-Z]+$\" │ │\n", + " │ │ ] │ │\n", + " │ │ } │ │\n", + " │ │ }, │ │\n", + " │ │ { │ │\n", + " │ │ \"customer_name\": { │ │\n", + " │ │ \"incorrect_value\": \"polk and wardell\", │ │\n", + " │ │ \"error_messages\": [ │ │\n", + " │ │ \"Result must match ^[A-Z]+\\\\s[A-Z]+$\" │ │\n", + " │ │ ] │ │\n", + " │ │ } │ │\n", + " │ │ } │ │\n", + " │ │ ] │ │\n", + " │ │ } │ │\n", + " │ │ │ │\n", + " │ │ Help me correct the incorrect values based on the given error messages. │ │\n", + " │ │ │ │\n", + " │ │ Given below is a JSON Schema that describes the output structure you should return. │ │\n", + " │ │ │ │\n", + " │ │ {\"properties\": {\"deliveries\": {\"items\": {\"properties\": {\"customer_name\": {\"type\": \"string\", │ │\n", + " │ │ \"description\": \"customer name\"}, \"pickup_time\": {\"type\": \"string\", \"description\": \"date and time of │ │\n", + " │ │ pickup\"}, \"pickup_location\": {\"type\": \"string\", \"description\": \"address of pickup\"}, \"dropoff_time\": │ │\n", + " │ │ {\"type\": \"string\", \"description\": \"date and time of dropoff\"}, \"dropoff_location\": {\"type\": \"string\", │ │\n", + " │ │ \"description\": \"address of dropoff\"}, \"price\": {\"type\": \"string\", \"description\": \"price of delivery │ │\n", + " │ │ with currency symbol included\"}}, \"required\": [\"customer_name\", \"pickup_time\", \"pickup_location\", │ │\n", + " │ │ \"dropoff_time\", \"dropoff_location\", \"price\"], \"type\": \"object\"}, \"type\": \"array\"}}, \"required\": │ │\n", + " │ │ [\"deliveries\"], \"type\": \"object\"} │ │\n", + " │ │ │ │\n", + " │ │ ONLY return a valid JSON object (no other text is necessary), where the key of the field in the JSON is │ │\n", + " │ │ the key of the entries within the schema's `properties`, and the value is of the type specified by the │ │\n", + " │ │ `type` property under that key. │ │\n", + " │ │ The JSON MUST conform to the structure described by the JSON Schema provided BUT SHOULD NOT BE A JSON │ │\n", + " │ │ Schema ITSELF. │ │\n", + " │ │ Be sure to include any types and format requests e.g. requests for lists, objects and specific types. │ │\n", + " │ │ Be correct and concise. │ │\n", + " │ │ If you are unsure anywhere, enter `null`. │ │\n", + " │ │ │ │\n", + " │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │\n", + " │ ╭───────────────────────────────────────────── Instructions ──────────────────────────────────────────────╮ │\n", + " │ │ │ │\n", + " │ │ You are a helpful assistant only capable of communicating with valid JSON, and no other text. │ │\n", + " │ │ │ │\n", + " │ │ ONLY return a valid JSON object (no other text is necessary). The JSON MUST conform to the JSON Schema │ │\n", + " │ │ provided, including any types and format requests e.g. requests for lists, objects and specific types. │ │\n", + " │ │ Be correct and concise. If you are unsure anywhere, enter `null`. │ │\n", + " │ │ │ │\n", + " │ │ Here are examples of simple (JSON Schema, JSON) pairs that show the expected behavior: │ │\n", + " │ │ - `{\"type\":\"object\",\"properties\":{\"foo\":{\"type\":\"string\",\"format\":\"two-words lower-case\"}}}` => │ │\n", + " │ │ `{'foo': 'example one'}` │ │\n", + " │ │ - │ │\n", + " │ │ `{\"type\":\"object\",\"properties\":{\"bar\":{\"type\":\"array\",\"items\":{\"type\":\"string\",\"format\":\"upper-case\"}}} │ │\n", + " │ │ }` => `{\"bar\": ['STRING ONE', 'STRING TWO']}` │ │\n", + " │ │ - │ │\n", + " │ │ `{\"type\":\"object\",\"properties\":{\"baz\":{\"type\":\"object\",\"properties\":{\"foo\":{\"type\":\"string\",\"format\":\"c │ │\n", + " │ │ apitalize two-words\"},\"index\":{\"type\":\"integer\",\"format\":\"1-indexed\"}}}}}` => `{'baz': {'foo': 'Some │ │\n", + " │ │ String', 'index': 1}}` │ │\n", + " │ │ - │ │\n", + " │ │ `{\"type\":\"object\",\"properties\":{\"bar\":{\"type\":\"array\",\"items\":{\"type\":\"string\",\"format\":\"upper-case\"}}, │ │\n", + " │ │ \"baz\":{\"type\":\"object\",\"properties\":{\"foo\":{\"type\":\"string\",\"format\":\"two-words lower-case\"}}}}}` => │ │\n", + " │ │ `{'bar': ['STRING ONE', 'STRING TWO'], 'baz': {'foo': 'example one'}}` │ │\n", + " │ │ │ │\n", + " │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │\n", + " │ ╭──────────────────────────────────────────── Message History ────────────────────────────────────────────╮ │\n", + " │ │ No message history. │ │\n", + " │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │\n", + " │ ╭──────────────────────────────────────────── Raw LLM Output ─────────────────────────────────────────────╮ │\n", + " │ │ {\"deliveries\": [{\"customer_name\": \"Nelson Murdock\", \"pickup_time\": \"2022-01-15T10:00:00\", │ │\n", + " │ │ \"pickup_location\": \"123 Main Street\", \"dropoff_time\": \"2022-01-15T12:00:00\", \"dropoff_location\": \"456 │ │\n", + " │ │ Elm Street\", \"price\": \"$50\"}, {\"customer_name\": \"Abc Flowers\", \"pickup_time\": \"2022-01-16T11:00:00\", │ │\n", + " │ │ \"pickup_location\": \"456 Oak Avenue\", \"dropoff_time\": \"2022-01-16T13:00:00\", \"dropoff_location\": \"789 │ │\n", + " │ │ Pine Road\", \"price\": \"$60\"}, {\"customer_name\": \"Polk Wardell\", \"pickup_time\": \"2022-01-17T09:00:00\", │ │\n", + " │ │ \"pickup_location\": \"789 Maple Lane\", \"dropoff_time\": \"2022-01-17T11:00:00\", \"dropoff_location\": \"234 │ │\n", + " │ │ Birch Boulevard\", \"price\": \"$70\"}]} │ │\n", + " │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │\n", + " │ ╭─────────────────────────────────────────── Validated Output ────────────────────────────────────────────╮ │\n", + " │ │ { │ │\n", + " │ │ 'deliveries': [ │ │\n", + " │ │ { │ │\n", + " │ │ 'customer_name': 'Nelson Murdock', │ │\n", + " │ │ 'pickup_time': 'June 3 10:00am', │ │\n", + " │ │ 'pickup_location': '797 9th Avenue', │ │\n", + " │ │ 'dropoff_time': 'June 3 10:30am', │ │\n", + " │ │ 'dropoff_location': 'Courthouse, 61 Center Street C/O frank james', │ │\n", + " │ │ 'price': '$23.00' │ │\n", + " │ │ }, │ │\n", + " │ │ { │ │\n", + " │ │ 'customer_name': 'Abc Flowers', │ │\n", + " │ │ 'pickup_time': 'June 2 11:00am', │ │\n", + " │ │ 'pickup_location': '21 3rd street', │ │\n", + " │ │ 'dropoff_time': 'June 2 5:30pm', │ │\n", + " │ │ 'dropoff_location': '75th Ave', │ │\n", + " │ │ 'price': '$14.50' │ │\n", + " │ │ }, │ │\n", + " │ │ { │ │\n", + " │ │ 'customer_name': 'Polk Wardell', │ │\n", + " │ │ 'pickup_time': 'June 3 11:00am', │ │\n", + " │ │ 'pickup_location': '331 5th street', │ │\n", + " │ │ 'dropoff_time': 'June 3 5:30pm', │ │\n", + " │ │ 'dropoff_location': '75th Ave', │ │\n", + " │ │ 'price': '$34.50' │ │\n", + " │ │ } │ │\n", + " │ │ ] │ │\n", + " │ │ } │ │\n", + " │ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯ │\n", + " ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n", + "\n" + ], + "text/plain": [ + "Logs\n", + "├── ╭────────────────────────────────────────────────── Step 0 ───────────────────────────────────────────────────╮\n", + "│ │ \u001b[48;2;240;248;255m╭─\u001b[0m\u001b[48;2;240;248;255m───────────────────────────────────────────────\u001b[0m\u001b[48;2;240;248;255m Prompt \u001b[0m\u001b[48;2;240;248;255m────────────────────────────────────────────────\u001b[0m\u001b[48;2;240;248;255m─╮\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mFrom the chat exchanges below extract a schedule of deliveries.\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mChats:\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mnelson and murdock: i need a pickup 797 9th Avenue, manila envelope, June 3 10:00am with dropoff \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m10:30am Courthouse, 61 Center Street C/O frank james\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255moperator: quote - $23.00\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mneslon and murdock: perfect, we accept the quote\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255moperator: 797 9th ave, 10:00am pickup comfirmed\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mabc flowers: i need a pickup of a flowers from abc flowers at 21 3rd street at 11:00am on june 2 with a\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mdropoff at 75th Ave at 5:30pm same day\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255moperator: 21 3rd street flowers quote - $14.50\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mabc flowers: accepted\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mpolk and wardell: i need a pickup of a bagels from Bakers Co at 331 5th street at 11:00am on june 3 \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mwith a dropoff at 75th Ave at 5:30pm same day\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255moperator: 331 5th street bagels quote - $34.50\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mpolk and wardell: accepted\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;248;255m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m │\n", + "│ │ \u001b[48;2;255;240;242m╭─\u001b[0m\u001b[48;2;255;240;242m────────────────────────────────────────────\u001b[0m\u001b[48;2;255;240;242m Instructions \u001b[0m\u001b[48;2;255;240;242m─────────────────────────────────────────────\u001b[0m\u001b[48;2;255;240;242m─╮\u001b[0m │\n", + "│ │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242mYou are a helpful assistant.\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + "│ │ \u001b[48;2;255;240;242m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m │\n", + "│ │ \u001b[48;2;231;223;235m╭─\u001b[0m\u001b[48;2;231;223;235m───────────────────────────────────────────\u001b[0m\u001b[48;2;231;223;235m Message History \u001b[0m\u001b[48;2;231;223;235m───────────────────────────────────────────\u001b[0m\u001b[48;2;231;223;235m─╮\u001b[0m │\n", + "│ │ \u001b[48;2;231;223;235m│\u001b[0m\u001b[48;2;231;223;235m \u001b[0m\u001b[48;2;231;223;235mNo message history.\u001b[0m\u001b[48;2;231;223;235m \u001b[0m\u001b[48;2;231;223;235m \u001b[0m\u001b[48;2;231;223;235m│\u001b[0m │\n", + "│ │ \u001b[48;2;231;223;235m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m │\n", + "│ │ \u001b[48;2;245;245;220m╭─\u001b[0m\u001b[48;2;245;245;220m───────────────────────────────────────────\u001b[0m\u001b[48;2;245;245;220m Raw LLM Output \u001b[0m\u001b[48;2;245;245;220m────────────────────────────────────────────\u001b[0m\u001b[48;2;245;245;220m─╮\u001b[0m │\n", + "│ │ \u001b[48;2;245;245;220m│\u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m{\"deliveries\":[{\"customer_name\":\"nelson and murdock\",\"pickup_time\":\"June 3 \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m│\u001b[0m │\n", + "│ │ \u001b[48;2;245;245;220m│\u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m10:00am\",\"pickup_location\":\"797 9th Avenue\",\"dropoff_time\":\"June 3 \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m│\u001b[0m │\n", + "│ │ \u001b[48;2;245;245;220m│\u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m10:30am\",\"dropoff_location\":\"Courthouse, 61 Center Street C/O frank \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m│\u001b[0m │\n", + "│ │ \u001b[48;2;245;245;220m│\u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220mjames\",\"price\":\"$23.00\"},{\"customer_name\":\"abc flowers\",\"pickup_time\":\"June 2 \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m│\u001b[0m │\n", + "│ │ \u001b[48;2;245;245;220m│\u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m11:00am\",\"pickup_location\":\"21 3rd street\",\"dropoff_time\":\"June 2 5:30pm\",\"dropoff_location\":\"75th \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m│\u001b[0m │\n", + "│ │ \u001b[48;2;245;245;220m│\u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220mAve\",\"price\":\"$14.50\"},{\"customer_name\":\"polk and wardell\",\"pickup_time\":\"June 3 \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m│\u001b[0m │\n", + "│ │ \u001b[48;2;245;245;220m│\u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m11:00am\",\"pickup_location\":\"331 5th street\",\"dropoff_time\":\"June 3 5:30pm\",\"dropoff_location\":\"75th \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m│\u001b[0m │\n", + "│ │ \u001b[48;2;245;245;220m│\u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220mAve\",\"price\":\"$34.50\"}]}\u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m│\u001b[0m │\n", + "│ │ \u001b[48;2;245;245;220m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m╭─\u001b[0m\u001b[48;2;240;255;240m──────────────────────────────────────────\u001b[0m\u001b[48;2;240;255;240m Validated Output \u001b[0m\u001b[48;2;240;255;240m───────────────────────────────────────────\u001b[0m\u001b[48;2;240;255;240m─╮\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m{\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'deliveries': [\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m {\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'customer_name': FieldReAsk(\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m incorrect_value='nelson and murdock',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m fail_results=[\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m FailResult(\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m outcome='fail',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m error_message='Result must match ^[A-Z]\u001b[0m\u001b[48;2;240;255;240m+\\\\s[A-Z]\u001b[0m\u001b[48;2;240;255;240m+$',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m fix_value='Rdbuqatcsperioirtnincsfincsctvizmazkylbbhmrenbdyzkjeogozpyoiyvopuegv\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240mvudra\\x0cShvihshzagoeniiawwdumtstqwhanryigafmqrfulfwelkuaozbtuvwycgcjwxxvqbawhqvclb',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m error_spans=None,\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m metadata=None,\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m validated_chunk=None\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m )\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m ],\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m additional_properties={},\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m path=['deliveries', 0, 'customer_name']\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m ),\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'pickup_time': 'June 3 10:00am',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'pickup_location': '797 9th Avenue',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'dropoff_time': 'June 3 10:30am',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'dropoff_location': 'Courthouse, 61 Center Street C/O frank james',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'price': '$23.00'\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m },\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m {\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'customer_name': FieldReAsk(\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m incorrect_value='abc flowers',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m fail_results=[\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m FailResult(\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m outcome='fail',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m error_message='Result must match ^[A-Z]\u001b[0m\u001b[48;2;240;255;240m+\\\\s[A-Z]\u001b[0m\u001b[48;2;240;255;240m+$',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m fix_value='Gzlawzbrtphaiwzdthhmmxiwwykhqnrsladoovnoryhvwazvhrqjzazeihkfplevvnej\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240mrqurkwin\\x0cMprzjamtwmz',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m error_spans=None,\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m metadata=None,\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m validated_chunk=None\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m )\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m ],\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m additional_properties={},\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m path=['deliveries', 1, 'customer_name']\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m ),\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'pickup_time': 'June 2 11:00am',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'pickup_location': '21 3rd street',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'dropoff_time': 'June 2 5:30pm',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'dropoff_location': '75th Ave',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'price': '$14.50'\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m },\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m {\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'customer_name': FieldReAsk(\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m incorrect_value='polk and wardell',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m fail_results=[\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m FailResult(\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m outcome='fail',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m error_message='Result must match ^[A-Z]\u001b[0m\u001b[48;2;240;255;240m+\\\\s[A-Z]\u001b[0m\u001b[48;2;240;255;240m+$',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m fix_value='Rcznucwiwovoqjszkwmwbwtepefflvbeciylxkjkxdybjadslmdykapacufjpgolktvq\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240mlbsydhuqfzygsvckomowxbjwnnqzhy\\tXutiwlnafoyguxexopjwoxilwea',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m error_spans=None,\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m metadata=None,\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m validated_chunk=None\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m )\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m ],\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m additional_properties={},\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m path=['deliveries', 2, 'customer_name']\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m ),\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'pickup_time': 'June 3 11:00am',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'pickup_location': '331 5th street',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'dropoff_time': 'June 3 5:30pm',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'dropoff_location': '75th Ave',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'price': '$34.50'\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m }\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m ]\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m}\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + "│ │ \u001b[48;2;240;255;240m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m │\n", + "│ ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n", + "└── ╭────────────────────────────────────────────────── Step 1 ───────────────────────────────────────────────────╮\n", + " │ \u001b[48;2;240;248;255m╭─\u001b[0m\u001b[48;2;240;248;255m───────────────────────────────────────────────\u001b[0m\u001b[48;2;240;248;255m Prompt \u001b[0m\u001b[48;2;240;248;255m────────────────────────────────────────────────\u001b[0m\u001b[48;2;240;248;255m─╮\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mI was given the following JSON response, which had problems due to incorrect values.\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m{\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \"deliveries\": [\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m {\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \"customer_name\": {\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \"incorrect_value\": \"nelson and murdock\",\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \"error_messages\": [\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \"Result must match ^[A-Z]\u001b[0m\u001b[48;2;240;248;255m+\\\\s[A-Z]\u001b[0m\u001b[48;2;240;248;255m+$\"\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m ]\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m }\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m },\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m {\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \"customer_name\": {\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \"incorrect_value\": \"abc flowers\",\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \"error_messages\": [\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \"Result must match ^[A-Z]\u001b[0m\u001b[48;2;240;248;255m+\\\\s[A-Z]\u001b[0m\u001b[48;2;240;248;255m+$\"\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m ]\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m }\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m },\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m {\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \"customer_name\": {\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \"incorrect_value\": \"polk and wardell\",\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \"error_messages\": [\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \"Result must match ^[A-Z]\u001b[0m\u001b[48;2;240;248;255m+\\\\s[A-Z]\u001b[0m\u001b[48;2;240;248;255m+$\"\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m ]\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m }\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m }\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m ]\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m}\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mHelp me correct the incorrect values based on the given error messages.\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mGiven below is a JSON Schema that describes the output structure you should return.\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m{\"properties\": {\"deliveries\": {\"items\": {\"properties\": {\"customer_name\": {\"type\": \"string\", \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m\"description\": \"customer name\"}, \"pickup_time\": {\"type\": \"string\", \"description\": \"date and time of \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mpickup\"}, \"pickup_location\": {\"type\": \"string\", \"description\": \"address of pickup\"}, \"dropoff_time\": \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m{\"type\": \"string\", \"description\": \"date and time of dropoff\"}, \"dropoff_location\": {\"type\": \"string\", \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m\"description\": \"address of dropoff\"}, \"price\": {\"type\": \"string\", \"description\": \"price of delivery \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mwith currency symbol included\"}}, \"required\": [\"customer_name\", \"pickup_time\", \"pickup_location\", \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m\"dropoff_time\", \"dropoff_location\", \"price\"], \"type\": \"object\"}, \"type\": \"array\"}}, \"required\": \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m[\"deliveries\"], \"type\": \"object\"}\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mONLY return a valid JSON object (no other text is necessary), where the key of the field in the JSON is\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mthe key of the entries within the schema's `properties`, and the value is of the type specified by the \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m`type` property under that key. \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mThe JSON MUST conform to the structure described by the JSON Schema provided BUT SHOULD NOT BE A JSON \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mSchema ITSELF.\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mBe sure to include any types and format requests e.g. requests for lists, objects and specific types. \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mBe correct and concise. \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255mIf you are unsure anywhere, enter `null`.\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m│\u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m \u001b[0m\u001b[48;2;240;248;255m│\u001b[0m │\n", + " │ \u001b[48;2;240;248;255m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m╭─\u001b[0m\u001b[48;2;255;240;242m────────────────────────────────────────────\u001b[0m\u001b[48;2;255;240;242m Instructions \u001b[0m\u001b[48;2;255;240;242m─────────────────────────────────────────────\u001b[0m\u001b[48;2;255;240;242m─╮\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242mYou are a helpful assistant only capable of communicating with valid JSON, and no other text.\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242mONLY return a valid JSON object (no other text is necessary). The JSON MUST conform to the JSON Schema \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242mprovided, including any types and format requests e.g. requests for lists, objects and specific types. \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242mBe correct and concise. If you are unsure anywhere, enter `null`.\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242mHere are examples of simple (JSON Schema, JSON) pairs that show the expected behavior:\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m- `{\"type\":\"object\",\"properties\":{\"foo\":{\"type\":\"string\",\"format\":\"two-words lower-case\"}}}` => \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m`{'foo': 'example one'}`\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m- \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m`{\"type\":\"object\",\"properties\":{\"bar\":{\"type\":\"array\",\"items\":{\"type\":\"string\",\"format\":\"upper-case\"}}}\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m}` => `{\"bar\": ['STRING ONE', 'STRING TWO']}`\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m- \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m`{\"type\":\"object\",\"properties\":{\"baz\":{\"type\":\"object\",\"properties\":{\"foo\":{\"type\":\"string\",\"format\":\"c\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242mapitalize two-words\"},\"index\":{\"type\":\"integer\",\"format\":\"1-indexed\"}}}}}` => `{'baz': {'foo': 'Some \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242mString', 'index': 1}}`\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m- \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m`{\"type\":\"object\",\"properties\":{\"bar\":{\"type\":\"array\",\"items\":{\"type\":\"string\",\"format\":\"upper-case\"}},\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m\"baz\":{\"type\":\"object\",\"properties\":{\"foo\":{\"type\":\"string\",\"format\":\"two-words lower-case\"}}}}}` => \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m`{'bar': ['STRING ONE', 'STRING TWO'], 'baz': {'foo': 'example one'}}`\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m│\u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m \u001b[0m\u001b[48;2;255;240;242m│\u001b[0m │\n", + " │ \u001b[48;2;255;240;242m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m │\n", + " │ \u001b[48;2;231;223;235m╭─\u001b[0m\u001b[48;2;231;223;235m───────────────────────────────────────────\u001b[0m\u001b[48;2;231;223;235m Message History \u001b[0m\u001b[48;2;231;223;235m───────────────────────────────────────────\u001b[0m\u001b[48;2;231;223;235m─╮\u001b[0m │\n", + " │ \u001b[48;2;231;223;235m│\u001b[0m\u001b[48;2;231;223;235m \u001b[0m\u001b[48;2;231;223;235mNo message history.\u001b[0m\u001b[48;2;231;223;235m \u001b[0m\u001b[48;2;231;223;235m \u001b[0m\u001b[48;2;231;223;235m│\u001b[0m │\n", + " │ \u001b[48;2;231;223;235m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m │\n", + " │ \u001b[48;2;245;245;220m╭─\u001b[0m\u001b[48;2;245;245;220m───────────────────────────────────────────\u001b[0m\u001b[48;2;245;245;220m Raw LLM Output \u001b[0m\u001b[48;2;245;245;220m────────────────────────────────────────────\u001b[0m\u001b[48;2;245;245;220m─╮\u001b[0m │\n", + " │ \u001b[48;2;245;245;220m│\u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m{\"deliveries\": [{\"customer_name\": \"Nelson Murdock\", \"pickup_time\": \"2022-01-15T10:00:00\", \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m│\u001b[0m │\n", + " │ \u001b[48;2;245;245;220m│\u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m\"pickup_location\": \"123 Main Street\", \"dropoff_time\": \"2022-01-15T12:00:00\", \"dropoff_location\": \"456 \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m│\u001b[0m │\n", + " │ \u001b[48;2;245;245;220m│\u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220mElm Street\", \"price\": \"$50\"}, {\"customer_name\": \"Abc Flowers\", \"pickup_time\": \"2022-01-16T11:00:00\", \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m│\u001b[0m │\n", + " │ \u001b[48;2;245;245;220m│\u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m\"pickup_location\": \"456 Oak Avenue\", \"dropoff_time\": \"2022-01-16T13:00:00\", \"dropoff_location\": \"789 \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m│\u001b[0m │\n", + " │ \u001b[48;2;245;245;220m│\u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220mPine Road\", \"price\": \"$60\"}, {\"customer_name\": \"Polk Wardell\", \"pickup_time\": \"2022-01-17T09:00:00\", \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m│\u001b[0m │\n", + " │ \u001b[48;2;245;245;220m│\u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m\"pickup_location\": \"789 Maple Lane\", \"dropoff_time\": \"2022-01-17T11:00:00\", \"dropoff_location\": \"234 \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m│\u001b[0m │\n", + " │ \u001b[48;2;245;245;220m│\u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220mBirch Boulevard\", \"price\": \"$70\"}]}\u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m \u001b[0m\u001b[48;2;245;245;220m│\u001b[0m │\n", + " │ \u001b[48;2;245;245;220m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m╭─\u001b[0m\u001b[48;2;240;255;240m──────────────────────────────────────────\u001b[0m\u001b[48;2;240;255;240m Validated Output \u001b[0m\u001b[48;2;240;255;240m───────────────────────────────────────────\u001b[0m\u001b[48;2;240;255;240m─╮\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m{\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'deliveries': [\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m {\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'customer_name': 'Nelson Murdock',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'pickup_time': 'June 3 10:00am',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'pickup_location': '797 9th Avenue',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'dropoff_time': 'June 3 10:30am',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'dropoff_location': 'Courthouse, 61 Center Street C/O frank james',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'price': '$23.00'\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m },\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m {\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'customer_name': 'Abc Flowers',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'pickup_time': 'June 2 11:00am',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'pickup_location': '21 3rd street',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'dropoff_time': 'June 2 5:30pm',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'dropoff_location': '75th Ave',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'price': '$14.50'\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m },\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m {\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'customer_name': 'Polk Wardell',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'pickup_time': 'June 3 11:00am',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'pickup_location': '331 5th street',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'dropoff_time': 'June 3 5:30pm',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'dropoff_location': '75th Ave',\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m 'price': '$34.50'\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m }\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m ]\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m│\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m}\u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m \u001b[0m\u001b[48;2;240;255;240m│\u001b[0m │\n", + " │ \u001b[48;2;240;255;240m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m │\n", + " ╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\n" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "rail_guard.history.last.tree" + ] + } + ], + "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.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/examples/lite_llm_defaults.ipynb b/docs/examples/lite_llm_defaults.ipynb new file mode 100644 index 000000000..06ec7641f --- /dev/null +++ b/docs/examples/lite_llm_defaults.ipynb @@ -0,0 +1,98 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "! guardrails hub install hub://guardrails/regex_match --quiet" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
ValidationOutcome(\n", + " call_id='4927013424',\n", + " raw_llm_output=\"As of my last update in 2023, Jupiter has 95 confirmed moons. The number of known moons can \n", + "change as new moons are discovered and confirmed, so it's always a good idea to check the latest information from \n", + "reliable sources such as NASA or other astronomical organizations.\",\n", + " validated_output=\"As of my last update in 2023, Jupiter has 95 confirmed moons. The number of known moons can \n", + "change as new moons are discovered and confirmed, so it's always a good idea to check the latest information from \n", + "reliable sources such as NASA or other astronomical organizations.\",\n", + " reask=None,\n", + " validation_passed=True,\n", + " error=None\n", + ")\n", + "\n" + ], + "text/plain": [ + "\u001b[1;35mValidationOutcome\u001b[0m\u001b[1m(\u001b[0m\n", + " \u001b[33mcall_id\u001b[0m=\u001b[32m'4927013424'\u001b[0m,\n", + " \u001b[33mraw_llm_output\u001b[0m=\u001b[32m\"As\u001b[0m\u001b[32m of my last update in 2023, Jupiter has 95 confirmed moons. The number of known moons can \u001b[0m\n", + "\u001b[32mchange as new moons are discovered and confirmed, so it's always a good idea to check the latest information from \u001b[0m\n", + "\u001b[32mreliable sources such as NASA or other astronomical organizations.\"\u001b[0m,\n", + " \u001b[33mvalidated_output\u001b[0m=\u001b[32m\"As\u001b[0m\u001b[32m of my last update in 2023, Jupiter has 95 confirmed moons. The number of known moons can \u001b[0m\n", + "\u001b[32mchange as new moons are discovered and confirmed, so it's always a good idea to check the latest information from \u001b[0m\n", + "\u001b[32mreliable sources such as NASA or other astronomical organizations.\"\u001b[0m,\n", + " \u001b[33mreask\u001b[0m=\u001b[3;35mNone\u001b[0m,\n", + " \u001b[33mvalidation_passed\u001b[0m=\u001b[3;92mTrue\u001b[0m,\n", + " \u001b[33merror\u001b[0m=\u001b[3;35mNone\u001b[0m\n", + "\u001b[1m)\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from rich import print\n", + "from guardrails import Guard\n", + "from guardrails.hub import RegexMatch\n", + "\n", + "guard = Guard().use(RegexMatch(\"95\", match_type=\"search\"))\n", + "\n", + "response = guard(\n", + " model=\"gpt-4o\",\n", + " instructions=\"You are a helpful assistant.\",\n", + " prompt=\"How many moons does jupiter have?\",\n", + " messages=[{\n", + " \"role\": \"system\",\n", + " \"content\": \"You are a helpful assistant.\"\n", + " },{\n", + " \"role\": \"user\",\n", + " \"content\": \"How many moons does jupiter have?\"\n", + " }]\n", + ")\n", + "\n", + "print(response)" + ] + } + ], + "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.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/pydocs/api_reference/actions.py b/docs/pydocs/api_reference/actions.py new file mode 100644 index 000000000..ee79107a0 --- /dev/null +++ b/docs/pydocs/api_reference/actions.py @@ -0,0 +1,60 @@ +from docspec_python import ParserOptions +from docs.pydocs.pydocs_markdown_impl import render_loader +from pydoc_markdown.contrib.loaders.python import PythonLoader +from pydoc_markdown.contrib.processors.filter import FilterProcessor +from pydoc_markdown.contrib.renderers.markdown import MarkdownRenderer +from docs.pydocs.helpers import write_to_file + + +exports = [ + "guardrails.actions.reask", + "ReAsk", + "FieldReAsk", + "SkeletonReAsk", + "NonParseableReAsk", + "guardrails.actions.filter", + "Filter", + "apply_filters", + "guardrails.actions.refrain", + "Refrain", + "apply_refrain", +] +export_string = ", ".join([f"'{export}'" for export in exports]) + +write_to_file( + str="# Actions\n\n" + + render_loader( + PythonLoader( + modules=[ + "guardrails.actions.reask", + "guardrails.actions.filter", + "guardrails.actions.refrain", + ], + parser=ParserOptions(print_function=False), + ), + processor=FilterProcessor( + expression=f"name in [{export_string}]", # noqa + skip_empty_modules=True, + ), + renderer=MarkdownRenderer( + # Custom + data_code_block=True, + data_expression_maxlength=250, + header_level_by_type={ + "Class": 2, + "Variable": 2, + }, + # Default + render_module_header=False, + insert_header_anchors=False, + descriptive_class_title=False, + signature_in_header=False, + classdef_code_block=True, + classdef_with_decorators=True, + signature_code_block=True, + signature_with_decorators=True, + render_typehint_in_data_header=True, + ), + ), + filename="docs/api_reference_markdown/actions.md", +) diff --git a/docs/pydocs/api_reference/errors.py b/docs/pydocs/api_reference/errors.py new file mode 100644 index 000000000..48d0b1795 --- /dev/null +++ b/docs/pydocs/api_reference/errors.py @@ -0,0 +1,24 @@ +from docspec_python import ParserOptions +from docs.pydocs.pydocs_markdown_impl import render_loader +from pydoc_markdown.contrib.loaders.python import PythonLoader +from pydoc_markdown.contrib.processors.filter import FilterProcessor +from docs.pydocs.helpers import write_to_file + + +exports = ["guardrails.errors.__init__", "guardrails.errors", "ValidationError"] +export_string = ", ".join([f"'{export}'" for export in exports]) + +write_to_file( + str="# Errors\n\n" + + render_loader( + PythonLoader( + modules=["guardrails.errors.__init__"], + parser=ParserOptions(print_function=False), + ), + processor=FilterProcessor( + expression=f"name in [{export_string}]", # noqa + skip_empty_modules=True, + ), + ), + filename="docs/api_reference_markdown/errors.md", +) diff --git a/docs/pydocs/api_reference/formatters.py b/docs/pydocs/api_reference/formatters.py new file mode 100644 index 000000000..fec945a93 --- /dev/null +++ b/docs/pydocs/api_reference/formatters.py @@ -0,0 +1,27 @@ +from docspec_python import ParserOptions +from docs.pydocs.pydocs_markdown_impl import render_loader +from pydoc_markdown.contrib.loaders.python import PythonLoader +from docs.pydocs.helpers import write_to_file + + +exports = [ + "guardrails.formatters.json_formatter", + "JsonFormatter", + "guardrails.formatters.base_formatter", + "BaseFormatter", +] +export_string = ", ".join([f"'{export}'" for export in exports]) + +write_to_file( + str="# Formatters\n\n" + + render_loader( + loader=PythonLoader( + modules=[ + "guardrails.formatters.base_formatter", + "guardrails.formatters.json_formatter", + ], + parser=ParserOptions(print_function=False), + ), + ), + filename="docs/api_reference_markdown/formatters.md", +) diff --git a/docs/pydocs/api_reference/generics_and_base_classes.py b/docs/pydocs/api_reference/generics_and_base_classes.py new file mode 100644 index 000000000..6b454fb59 --- /dev/null +++ b/docs/pydocs/api_reference/generics_and_base_classes.py @@ -0,0 +1,27 @@ +from docspec_python import ParserOptions +from docs.pydocs.pydocs_markdown_impl import render_loader +from pydoc_markdown.contrib.loaders.python import PythonLoader +from docs.pydocs.helpers import write_to_file + + +exports = [ + "guardrails.classes.generic.arbitrary_model", + "ArbitraryModel", + "guardrails.classes.generic.stack", + "Stack", +] +export_string = ", ".join([f"'{export}'" for export in exports]) + +write_to_file( + str="# Generics And Base Classes\n\n" + + render_loader( + loader=PythonLoader( + modules=[ + "guardrails.classes.generic.arbitrary_model", + "guardrails.classes.generic.stack", + ], + parser=ParserOptions(print_function=False), + ), + ), + filename="docs/api_reference_markdown/generics_and_base_classes.md", +) diff --git a/docs/pydocs/api_reference/guards.py b/docs/pydocs/api_reference/guards.py new file mode 100644 index 000000000..ad925fb80 --- /dev/null +++ b/docs/pydocs/api_reference/guards.py @@ -0,0 +1,84 @@ +from docspec_python import ParserOptions +from docs.pydocs.pydocs_markdown_impl import render_loader +from pydoc_markdown.contrib.loaders.python import PythonLoader +from pydoc_markdown.contrib.processors.filter import FilterProcessor +from docs.pydocs.helpers import write_to_file + + +export_map = { + "guardrails/guard.py": [ + "Guard", + "guardrails.guard", + "guard", + "__init__", + "from_rail", + "from_rail_string", + "from_pydantic", + "from_string", + "configure", + "use", + "use_many", + "__call__", + "parse", + "validate", + "error_spans_in_output", + "add_json_function_calling_tool", + "to_dict", + "from_dict", + "to_runnable", + ], + "guardrails/async_guard.py": [ + "AsyncGuard", + "guardrails.async_guard", + "async_guard", + "__init__", + "from_rail", + "from_rail_string", + "from_pydantic", + "from_string", + "configure", + "use", + "use_many", + "__call__", + "parse", + "validate", + "error_spans_in_output", + "add_json_function_calling_tool", + "to_dict", + "from_dict", + "to_runnable", + ], + "guardrails/classes/validation_outcome.py": [ + "guardrails.classes.validation_outcome", + "ValidationOutcome", + "from_guard_history", + ], +} + + +conditionals = [] +for k, v in export_map.items(): + conditionals.append( + f"((name in {v}) if ('{k}' in obj.location.filename) else False)" + ) + +export_string = " or ".join(conditionals) + +write_to_file( + str="# Guards\n\n" + + render_loader( + PythonLoader( + modules=[ + "guardrails.guard", + "guardrails.async_guard", + "guardrails.classes.validation_outcome", + ], + parser=ParserOptions(print_function=False), + ), + processor=FilterProcessor( + expression=f"({export_string})", + skip_empty_modules=True, + ), + ), + filename="docs/api_reference_markdown/guards.md", +) diff --git a/docs/pydocs/api_reference/history.py b/docs/pydocs/api_reference/history.py new file mode 100644 index 000000000..80437f12a --- /dev/null +++ b/docs/pydocs/api_reference/history.py @@ -0,0 +1,22 @@ +from docspec_python import ParserOptions +from docs.pydocs.pydocs_markdown_impl import render_loader +from pydoc_markdown.contrib.loaders.python import PythonLoader +from docs.pydocs.helpers import write_to_file + + +write_to_file( + str="# History and Logs\n\n" + + render_loader( + loader=PythonLoader( + modules=[ + "guardrails.classes.history.call", + "guardrails.classes.history.iteration", + "guardrails.classes.history.inputs", + "guardrails.classes.history.outputs", + "guardrails.classes.history.call_inputs", + ], + parser=ParserOptions(print_function=False), + ), + ), + filename="docs/api_reference_markdown/history_and_logs.md", +) diff --git a/docs/pydocs/api_reference/llm_interaction.py b/docs/pydocs/api_reference/llm_interaction.py new file mode 100644 index 000000000..317afb28e --- /dev/null +++ b/docs/pydocs/api_reference/llm_interaction.py @@ -0,0 +1,68 @@ +from docspec_python import ParserOptions +from docs.pydocs.pydocs_markdown_impl import render_loader +from pydoc_markdown.contrib.loaders.python import PythonLoader +from pydoc_markdown.contrib.processors.filter import FilterProcessor +from docs.pydocs.helpers import write_to_file + + +export_map = { + "guardrails/prompt/base_prompt.py": [ + "guardrails.prompt.base_prompt", + "BasePrompt", + "__init__", + "format", + "substitute_constants", + "get_prompt_variables", + "escape", + ], + "guardrails/prompt/prompt.py": [ + "guardrails.prompt.prompt", + "Prompt", + "format", + ], + "guardrails/prompt/instructions.py": [ + "guardrails.prompt.instructions", + "Instructions", + "format", + ], + "guardrails/llm_providers.py": [ + "guardrails.llm_providers", + "PromptCallableBase", + "_invoke_llm", + "__call__", + ], + "guardrails/classes/llm/llm_response.py": [ + "guardrails.classes.llm.llm_response", + "LLMResponse", + ], +} + + +conditionals = [] +for k, v in export_map.items(): + conditionals.append( + f"((name in {v}) if ('{k}' in obj.location.filename) else False)" + ) + +export_string = " or ".join(conditionals) + +write_to_file( + str="# Helpers for LLM Interactions\n\n" + + render_loader( + PythonLoader( + modules=[ + "guardrails.prompt.base_prompt", + "guardrails.prompt.prompt", + "guardrails.prompt.instructions", + "guardrails.llm_providers", + "guardrails.classes.llm.llm_response", + ], + parser=ParserOptions(print_function=False), + ), + processor=FilterProcessor( + expression=f"({export_string})", # noqa + skip_empty_modules=True, + ), + ), + filename="docs/api_reference_markdown/llm_interaction.md", +) diff --git a/docs/pydocs/api_reference/types.py b/docs/pydocs/api_reference/types.py new file mode 100644 index 000000000..7ddba4872 --- /dev/null +++ b/docs/pydocs/api_reference/types.py @@ -0,0 +1,73 @@ +from docspec_python import ParserOptions +from docs.pydocs.pydocs_markdown_impl import render_loader +from pydoc_markdown.contrib.loaders.python import PythonLoader +from pydoc_markdown.contrib.processors.filter import FilterProcessor +from pydoc_markdown.contrib.renderers.markdown import MarkdownRenderer +from docs.pydocs.helpers import write_to_file + + +exports = [ + "guardrails.types.on_fail", + "guardrails.types.rail", + "OnFailAction", + "RailTypes", + "guardrails.types.inputs", + "guardrails.types.pydantic", + "guardrails.types.validator", + "MessageHistory", + "ModelOrListOfModels", + "ModelOrListOrDict", + "ModelOrModelUnion", + "PydanticValidatorTuple", + "PydanticValidatorSpec", + "UseValidatorSpec", + "UseManyValidatorTuple", + "UseManyValidatorSpec", + "ValidatorMap", +] +export_string = ", ".join([f"'{export}'" for export in exports]) + +write_to_file( + str="# Types\n\n" + + render_loader( + PythonLoader( + modules=[ + "guardrails.types.on_fail", + "guardrails.types.primitives", + "guardrails.types.rail", + "guardrails.types.inputs", + "guardrails.types.pydantic", + "guardrails.types.validator", + ], + parser=ParserOptions( + print_function=False, treat_singleline_comment_blocks_as_docstrings=True + ), + ), + processor=FilterProcessor( + expression=f"name in [{export_string}]", # noqa + skip_empty_modules=True, + ), + renderer=MarkdownRenderer( + # Custom + data_code_block=True, + data_expression_maxlength=250, + header_level_by_type={ + "Class": 2, + "Method": 2, + "Function": 2, + "Variable": 2, + }, + # Default + render_module_header=False, + insert_header_anchors=False, + descriptive_class_title=False, + signature_in_header=False, + classdef_code_block=True, + classdef_with_decorators=True, + signature_code_block=True, + signature_with_decorators=True, + render_typehint_in_data_header=True, + ), + ), + filename="docs/api_reference_markdown/types.md", +) diff --git a/docs/pydocs/api_reference/validation.py b/docs/pydocs/api_reference/validation.py new file mode 100644 index 000000000..31c652c6b --- /dev/null +++ b/docs/pydocs/api_reference/validation.py @@ -0,0 +1,71 @@ +from docspec_python import ParserOptions +from docs.pydocs.pydocs_markdown_impl import render_loader +from pydoc_markdown.contrib.loaders.python import PythonLoader +from pydoc_markdown.contrib.processors.filter import FilterProcessor +from docs.pydocs.helpers import write_to_file + + +# exports = [ +# "docs.pydocs.api_reference.validator", +# "ValidatorReference", +# ] +# export_string = ", ".join([f"'{export}'" for export in exports]) + + +export_map = { + "guardrails/validator_base.py": [ + "guardrails.validator_base", + "Validator", + "__init__", + "chunking_function", + "validate", + "validate_stream", + "with_metadata", + "to_runnable", + "register_validator", + ], + "guardrails/classes/validation/validation_result.py": [ + "guardrails.classes.validation.validation_result", + "ValidationResult", + "PassResult", + "FailResult", + "ErrorSpan", + ], + "guardrails/classes/validation/validator_logs.py": [ + "guardrails.classes.validation.validator_logs", + "ValidatorLogs", + ], + "guardrails/classes/validation/validator_reference.py": [ + "guardrails.classes.validation.validator_reference", + "ValidatorReference", + ], +} + + +conditionals = [] +for k, v in export_map.items(): + conditionals.append( + f"((name in {v}) if ('{k}' in obj.location.filename) else False)" + ) + +export_string = " or ".join(conditionals) + +write_to_file( + str="# Validation\n\n" + + render_loader( + PythonLoader( + modules=[ + "guardrails.validator_base", + "guardrails.classes.validation.validation_result", + "guardrails.classes.validation.validator_logs", + "guardrails.classes.validation.validator_reference", + ], + parser=ParserOptions(print_function=False), + ), + processor=FilterProcessor( + expression=f"({export_string})", + skip_empty_modules=False, + ), + ), + filename="docs/api_reference_markdown/validator.md", +) diff --git a/docs/pydocs/generate_pydocs.py b/docs/pydocs/generate_pydocs.py index a0e428ad1..46e38cfbf 100644 --- a/docs/pydocs/generate_pydocs.py +++ b/docs/pydocs/generate_pydocs.py @@ -1,98 +1,29 @@ -import os -# from pydoc_markdown.interfaces import Context from docspec_python import ParserOptions +from docs.pydocs.helpers import write_to_file from docs.pydocs.pydocs_markdown_impl import render_loader from pydoc_markdown.contrib.loaders.python import PythonLoader -# from guardrails import Rail, Guard, validators, datatypes -# from guardrails.classes.validation_outcome import ValidationOutcome -from pydoc_markdown.contrib.renderers.markdown import MarkdownRenderer -# from guardrails.classes import generic -# from pydocs_to_md import class_to_string, module_to_string -from pydoc_markdown.contrib.processors.filter import FilterProcessor - - -def write_to_file(str, filename): - # if the directory where the filename does not exist, create it - if not os.path.exists(os.path.dirname(filename)): - os.makedirs(os.path.dirname(filename)) - with open(filename, "w") as f: - f.write(str) - f.close() - - -# write_to_file( -# # str=class_to_string(Rail, ignore_prefix_list=["load", "_"]), -# str="# Rail\n\n" + render_loader( -# PythonLoader( -# modules=['guardrails.rail'], -# parser=ParserOptions( -# print_function=False, -# ), -# ), -# processor = FilterProcessor( -# expression="not name.startswith('_') and not name.startswith('load') and default()", -# documented_only=True, - -# ) -# ), -# filename="docs/api_reference_markdown/rail.md", -# ) - - -write_to_file( - str="# Guard\n\n" + render_loader( - PythonLoader( - modules=['guardrails.guard'], - parser=ParserOptions( - print_function=False - ), - ), - processor = FilterProcessor( - expression="name in ['Guard', 'guardrails.guard', 'guard', 'from_rail', 'from_rail_string', 'from_pydantic', 'from_string', 'configure', '__call__', 'parse', 'state']", - skip_empty_modules=True - ) - ), - filename="docs/api_reference_markdown/guard.md", -) +from docs.pydocs.api_reference import actions # noqa +from docs.pydocs.api_reference import errors # noqa +from docs.pydocs.api_reference import formatters # noqa +from docs.pydocs.api_reference import generics_and_base_classes # noqa +from docs.pydocs.api_reference import guards # noqa +from docs.pydocs.api_reference import history # noqa +from docs.pydocs.api_reference import llm_interaction # noqa +from docs.pydocs.api_reference import types # noqa +from docs.pydocs.api_reference import validation # noqa write_to_file( - str="# Validators\n\n" + render_loader( + str="# Validators\n\n" + + render_loader( PythonLoader( - search_path=['validators'], - parser=ParserOptions( - print_function=False - ) + search_path=["validators"], parser=ParserOptions(print_function=False) ) ), filename="docs/hub/api_reference_markdown/validators.md", ) -write_to_file( - # str=class_to_string(ValidationOutcome, ignore_prefix_list=["load", "_"]), - str="# Validation Outcome\n\n" + render_loader( - PythonLoader( - modules=['guardrails.classes.validation_outcome'], - parser=ParserOptions( - print_function=False - ), - ), - processor = FilterProcessor( - documented_only=True, - ), - renderer = MarkdownRenderer( - render_module_header=False, - insert_header_anchors=False, - classdef_code_block=False, - descriptive_class_title=False, - classdef_with_decorators=False, - render_typehint_in_data_header=True, - data_code_block=True, - ) - ), - filename="docs/hub/api_reference_markdown/validation_outcome.md", -) # write_to_file( # str="# Response Structures\n\n" + render_loader( @@ -102,7 +33,7 @@ def write_to_file(str, filename): # processor = FilterProcessor( # expression="""\ # name in \ -# ['guardrails.validator_base', 'ValidationResult', 'PassResult', 'FailResult', 'ValidationError'] \ +# ['guardrails.validator_base', 'ValidationResult', 'PassResult', 'FailResult', 'ValidationError'] \ # noqa # or obj.parent.name in \ # ['ValidationResult', 'PassResult', 'FailResult', 'ValidationError']\ # """, @@ -121,7 +52,6 @@ def write_to_file(str, filename): # ) - # write_to_file( # str="# Schema\n\n" + render_loader(PythonLoader( # modules=['guardrails.schema'], @@ -158,25 +88,6 @@ def write_to_file(str, filename): # filename="docs/api_reference_markdown/datatypes.md", # ) -write_to_file( - str="# History and Logs\n\n" + render_loader( - PythonLoader( - packages=['classes.history'], - parser=ParserOptions( - print_function=False - ), - ), - renderer = MarkdownRenderer( - render_module_header=True, - insert_header_anchors=False, - descriptive_class_title=True, - signature_in_header=True, - classdef_code_block=False, - classdef_with_decorators=False, - ), - ), - filename="docs/api_reference_markdown/history_and_logs.md", -) # write_to_file( # str="# Helper Classes\n\n" + render_loader( diff --git a/docs/pydocs/helpers.py b/docs/pydocs/helpers.py new file mode 100644 index 000000000..23c460234 --- /dev/null +++ b/docs/pydocs/helpers.py @@ -0,0 +1,10 @@ +import os + + +def write_to_file(str, filename): + # if the directory where the filename does not exist, create it + if not os.path.exists(os.path.dirname(filename)): + os.makedirs(os.path.dirname(filename)) + with open(filename, "w") as f: + f.write(str) + f.close() diff --git a/docs/pydocs/pydocs_markdown_impl.py b/docs/pydocs/pydocs_markdown_impl.py index 16272c75a..67187e7a1 100644 --- a/docs/pydocs/pydocs_markdown_impl.py +++ b/docs/pydocs/pydocs_markdown_impl.py @@ -1,21 +1,30 @@ from pydoc_markdown.interfaces import Context -from pydoc_markdown.contrib.renderers.markdown import MarkdownRenderer, MarkdownReferenceResolver +from pydoc_markdown.contrib.renderers.markdown import ( + MarkdownRenderer, + MarkdownReferenceResolver, +) from pydoc_markdown.contrib.processors.filter import FilterProcessor from pydoc_markdown.contrib.processors.google import GoogleProcessor +# from pydoc_markdown.contrib.processors.crossref import CrossrefProcessor -def render_loader(loader, processor = None, renderer = None, context = None): + +def render_loader(loader, processor=None, renderer=None, context=None): if not context: - context = Context(directory='guardrails') + context = Context(directory="guardrails") if not renderer: - renderer = MarkdownRenderer( + new_renderer = MarkdownRenderer( render_module_header=False, insert_header_anchors=False, descriptive_class_title=False, - signature_in_header=True, - classdef_code_block=False, - classdef_with_decorators=False, + signature_in_header=False, + classdef_code_block=True, + classdef_with_decorators=True, + signature_code_block=True, + signature_with_decorators=True, + render_typehint_in_data_header=True, ) + renderer = new_renderer if not processor: processor = FilterProcessor( @@ -24,13 +33,15 @@ def render_loader(loader, processor = None, renderer = None, context = None): google_processor = GoogleProcessor() + # TODO: Add this for api reference + # cross_ref_processor = CrossrefProcessor() + loader.init(context) renderer.init(context) processor.init(context) - modules = list(loader.load()) processor.process(modules=modules, resolver=MarkdownReferenceResolver()) google_processor.process(modules=modules, resolver=MarkdownReferenceResolver()) - return renderer.render_to_string(modules) \ No newline at end of file + return renderer.render_to_string(modules) diff --git a/guardrails/__init__.py b/guardrails/__init__.py index dd3bf9b1c..742abecaf 100644 --- a/guardrails/__init__.py +++ b/guardrails/__init__.py @@ -12,7 +12,7 @@ __all__ = [ "Guard", "AsyncGuard", - "PromptCallableBase", + "PromptCallableBase", # FIXME: Why is this being exported? "Validator", "OnFailAction", "register_validator", diff --git a/guardrails/actions/filter.py b/guardrails/actions/filter.py index 8d25dd9ee..e11bb7d5d 100644 --- a/guardrails/actions/filter.py +++ b/guardrails/actions/filter.py @@ -6,6 +6,7 @@ class Filter: def apply_filters(value: Any) -> Any: + """Recursively filter out any values that are instances of Filter.""" if isinstance(value, Filter): pass elif isinstance(value, List): diff --git a/guardrails/actions/reask.py b/guardrails/actions/reask.py index 3ffa8b0ec..5ed0b8d73 100644 --- a/guardrails/actions/reask.py +++ b/guardrails/actions/reask.py @@ -17,6 +17,13 @@ ### Classes/Types ### class ReAsk(IReask): + """Base class for ReAsk objects. + + Attributes: + incorrect_value (Any): The value that failed validation. + fail_results (List[FailResult]): The results of the failed validations. + """ + incorrect_value: Any fail_results: List[FailResult] @@ -60,16 +67,36 @@ def from_dict(cls, obj: Dict[str, Any]) -> Optional["ReAsk"]: class FieldReAsk(ReAsk): + """An implementation of ReAsk that is used to reask for a specific field. + Inherits from ReAsk. + + Attributes: + path (Optional[List[Any]]): a list of keys that + designated the path to the field that failed validation. + """ + # FIXME: This shouldn't be optional # We should be able to assign it on init now path: Optional[List[Any]] = None class SkeletonReAsk(ReAsk): + """An implementation of ReAsk that is used to reask for structured data + when the response does not match the expected schema. + + Inherits from ReAsk. + """ + pass class NonParseableReAsk(ReAsk): + """An implementation of ReAsk that is used to reask for structured data + when the response is not parseable as JSON. + + Inherits from ReAsk. + """ + pass diff --git a/guardrails/actions/refrain.py b/guardrails/actions/refrain.py index 923b746d3..a4819cc20 100644 --- a/guardrails/actions/refrain.py +++ b/guardrails/actions/refrain.py @@ -24,6 +24,10 @@ def check_for_refrain(value: Union[List, Dict]) -> bool: # Could be a generic instead of Any def apply_refrain(value: Any, output_type: OutputTypes) -> Any: + """Recursively check for any values that are instances of Refrain. + + If found, return an empty value of the appropriate type. + """ refrain_value = {} if output_type == OutputTypes.STRING: refrain_value = "" diff --git a/guardrails/async_guard.py b/guardrails/async_guard.py index fca49a948..911a087d3 100644 --- a/guardrails/async_guard.py +++ b/guardrails/async_guard.py @@ -440,7 +440,7 @@ async def __call__( Args: llm_api: The LLM API to call - (e.g. openai.Completion.create or openai.Completion.acreate) + (e.g. openai.completions.create or openai.chat.completions.create) prompt_params: The parameters to pass to the prompt.format() method. num_reasks: The max times to re-ask the LLM for invalid output. prompt: The prompt to use for the LLM. @@ -496,7 +496,7 @@ async def parse( llm_output: The output being parsed and validated. metadata: Metadata to pass to the validators. llm_api: The LLM API to call - (e.g. openai.Completion.create or openai.Completion.acreate) + (e.g. openai.completions.create or openai.Completion.acreate) num_reasks: The max times to re-ask the LLM for invalid output. prompt_params: The parameters to pass to the prompt.format() method. full_schema_reask: When reasking, whether to regenerate the full schema diff --git a/guardrails/call_tracing/__init__.py b/guardrails/call_tracing/__init__.py index 62078ab46..cfc312cc5 100644 --- a/guardrails/call_tracing/__init__.py +++ b/guardrails/call_tracing/__init__.py @@ -1,10 +1,9 @@ -""" -For tracing (logging) and reporting the timing of Guard and Validator calls. +"""For tracing (logging) and reporting the timing of Guard and Validator calls. sqlite_trace_handler defines most of the actual implementation methods. -trace_handler provides the singleton that's used for fast global access across threads. -tracer_mixin defines the interface and can act as a noop. -trace_entry is just a helpful dataclass. +trace_handler provides the singleton that's used for fast global access +across threads. tracer_mixin defines the interface and can act as a +noop. trace_entry is just a helpful dataclass. """ from guardrails.call_tracing.trace_entry import GuardTraceEntry diff --git a/guardrails/call_tracing/sqlite_trace_handler.py b/guardrails/call_tracing/sqlite_trace_handler.py index 2831c05d8..1d555d6fd 100644 --- a/guardrails/call_tracing/sqlite_trace_handler.py +++ b/guardrails/call_tracing/sqlite_trace_handler.py @@ -1,20 +1,22 @@ -""" -sqlite_trace_handler.py - -This is the metaphorical bread and butter of our tracing implementation, or at least the -butter. It wraps a SQLite database and configures it to be 'agreeable' in multithreaded -situations. Normally, when sharing across threads and instances one should consider -using a larger database solution like Postgres, but in this case we only care about -_supporting_ writing from multiple places. We don't expect it will be the norm. -We care about (1) not negatively impacting performance, (2) not crashing when used in -unusual ways, and (3) not losing data when possible. - -The happy path should be reasonably performant. The unhappy path should not crash. - -The other part of the multithreaded support comes from the public trace_handler, which -uses a singleton pattern to only have a single instance of the database per-thread. -If we _do_ somehow end up shared across threads, the journaling settings and writeahead -should protect us from odd behavior. +"""sqlite_trace_handler.py. + +This is the metaphorical bread and butter of our tracing implementation, +or at least the butter. It wraps a SQLite database and configures it to +be 'agreeable' in multithreaded situations. Normally, when sharing +across threads and instances one should consider using a larger database +solution like Postgres, but in this case we only care about _supporting_ +writing from multiple places. We don't expect it will be the norm. We +care about (1) not negatively impacting performance, (2) not crashing +when used in unusual ways, and (3) not losing data when possible. + +The happy path should be reasonably performant. The unhappy path should +not crash. + +The other part of the multithreaded support comes from the public +trace_handler, which uses a singleton pattern to only have a single +instance of the database per-thread. If we _do_ somehow end up shared +across threads, the journaling settings and writeahead should protect us +from odd behavior. """ import datetime @@ -194,12 +196,14 @@ def log_validator(self, vlog: ValidatorLogs): def tail_logs( self, start_offset_idx: int = 0, follow: bool = False ) -> Iterator[GuardTraceEntry]: - """Returns an iterator to generate GuardLogEntries. - @param start_offset_idx : Start printing entries after this IDX. If - negative, this will instead start printing the LAST start_offset_idx entries. - @param follow : If follow is True, will re-check the database for new entries - after the first batch is complete. If False (default), will return when entries - are exhausted. + """Returns an iterator to generate GuardLogEntries. @param + start_offset_idx : Start printing entries after this IDX. If. + + negative, this will instead start printing the LAST + start_offset_idx entries. @param follow : If follow is True, + will re-check the database for new entries after the first batch + is complete. If False (default), will return when entries are + exhausted. """ last_idx = start_offset_idx cursor = self.db.cursor() diff --git a/guardrails/call_tracing/trace_entry.py b/guardrails/call_tracing/trace_entry.py index 259ff3865..6f807a9f1 100644 --- a/guardrails/call_tracing/trace_entry.py +++ b/guardrails/call_tracing/trace_entry.py @@ -1,10 +1,10 @@ -""" -trace_entry.py +"""trace_entry.py. -GuardTraceEntry is a dataclass which doesn't explicitly define the schema of our logs, -but serves as a nice, easy-to-use dataclass for when we want to manipulate things -programmatically. If performance and filtering is a concern, it's probably worth -writing the SQL directly instead of filtering these in a for-loop. +GuardTraceEntry is a dataclass which doesn't explicitly define the +schema of our logs, but serves as a nice, easy-to-use dataclass for when +we want to manipulate things programmatically. If performance and +filtering is a concern, it's probably worth writing the SQL directly +instead of filtering these in a for-loop. """ from dataclasses import dataclass diff --git a/guardrails/call_tracing/trace_handler.py b/guardrails/call_tracing/trace_handler.py index cb383c063..1e689f2d0 100644 --- a/guardrails/call_tracing/trace_handler.py +++ b/guardrails/call_tracing/trace_handler.py @@ -1,5 +1,4 @@ -""" -trace_handler.py +"""trace_handler.py. A set of tools to track the behavior of guards, specifically with the intent of collating the pre/post validation text and timing of guard calls. Uses a singleton to @@ -41,9 +40,12 @@ class TraceHandler(TracerMixin): - """TraceHandler wraps the internal _SQLiteTraceHandler to make it multi-thread - safe. Coupled with some write ahead journaling in the _SyncTrace internal, we have - a faux-multi-write multi-read interface for SQLite.""" + """TraceHandler wraps the internal _SQLiteTraceHandler to make it multi- + thread safe. + + Coupled with some write ahead journaling in the _SyncTrace internal, + we have a faux-multi-write multi-read interface for SQLite. + """ _instance = None _lock = threading.Lock() diff --git a/guardrails/call_tracing/tracer_mixin.py b/guardrails/call_tracing/tracer_mixin.py index dd56307c5..76b1684f3 100644 --- a/guardrails/call_tracing/tracer_mixin.py +++ b/guardrails/call_tracing/tracer_mixin.py @@ -1,9 +1,7 @@ -""" -tracer_mixin.py +"""tracer_mixin.py. -This file defines our preferred tracer interface. -It has a side effect of acting as a 'noop' when we want to benchmark performance of a -tracer. +This file defines our preferred tracer interface. It has a side effect +of acting as a 'noop' when we want to benchmark performance of a tracer. """ import os diff --git a/guardrails/classes/generic/arbitrary_model.py b/guardrails/classes/generic/arbitrary_model.py index d26def657..876c978ac 100644 --- a/guardrails/classes/generic/arbitrary_model.py +++ b/guardrails/classes/generic/arbitrary_model.py @@ -2,4 +2,6 @@ class ArbitraryModel(BaseModel): + """Empty Pydantic model with a config that allows arbitrary types.""" + model_config = ConfigDict(arbitrary_types_allowed=True) diff --git a/guardrails/classes/history/__init__.py b/guardrails/classes/history/__init__.py index 622b0cd18..469fdbfee 100644 --- a/guardrails/classes/history/__init__.py +++ b/guardrails/classes/history/__init__.py @@ -4,4 +4,4 @@ from guardrails.classes.history.iteration import Iteration from guardrails.classes.history.outputs import Outputs -__all__ = ["CallInputs", "Call", "Inputs", "Iteration", "Outputs"] +__all__ = ["Call", "Iteration", "Inputs", "Outputs", "CallInputs"] diff --git a/guardrails/classes/history/call.py b/guardrails/classes/history/call.py index 99252830f..1f2498900 100644 --- a/guardrails/classes/history/call.py +++ b/guardrails/classes/history/call.py @@ -29,6 +29,20 @@ # We can't inherit from Iteration because python # won't let you override a class attribute with a managed attribute class Call(ICall, ArbitraryModel): + """A Call represents a single execution of a Guard. One Call is created + each time the user invokes the `Guard.__call__`, `Guard.parse`, or + `Guard.validate` method. + + Attributes: + iterations (Stack[Iteration]): A stack of iterations + for the initial validation round + and one for each reask that occurs during a Call. + inputs (CallInputs): The inputs as passed in to + `Guard.__call__`, `Guard.parse`, or `Guard.validate` + exception (Optional[Exception]): The exception that interrupted + the Guard execution. + """ + iterations: Stack[Iteration] = Field( description="A stack of iterations for each" "step/reask that occurred during this call." diff --git a/guardrails/classes/history/call_inputs.py b/guardrails/classes/history/call_inputs.py index bc99a4905..4aa2363f8 100644 --- a/guardrails/classes/history/call_inputs.py +++ b/guardrails/classes/history/call_inputs.py @@ -8,6 +8,21 @@ class CallInputs(Inputs, ICallInputs, ArbitraryModel): + """CallInputs represent the input data that is passed into the Guard from + the user. Inherits from Inputs with the below overrides and additional + attributes. + + Attributes: + llm_api (Optional[Callable[[Any], Awaitable[Any]]]): The LLM function + provided by the user during Guard.__call__ or Guard.parse. + prompt (Optional[str]): The prompt string as provided by the user. + instructions (Optional[str]): The instructions string as provided by the user. + args (List[Any]): Additional arguments for the LLM as provided by the user. + Default []. + kwargs (Dict[str, Any]): Additional keyword-arguments for + the LLM as provided by the user. Default {}. + """ + llm_api: Optional[Callable[[Any], Awaitable[Any]]] = Field( description="The LLM function provided by the user" "during Guard.__call__ or Guard.parse.", diff --git a/guardrails/classes/history/inputs.py b/guardrails/classes/history/inputs.py index f9ee44423..0e6c2ea8f 100644 --- a/guardrails/classes/history/inputs.py +++ b/guardrails/classes/history/inputs.py @@ -10,6 +10,29 @@ class Inputs(IInputs, ArbitraryModel): + """Inputs represent the input data that is passed into the validation loop. + + Attributes: + llm_api (Optional[PromptCallableBase]): The constructed class + for calling the LLM. + llm_output (Optional[str]): The string output from an + external LLM call provided by the user via Guard.parse. + instructions (Optional[Instructions]): The constructed + Instructions class for chat model calls. + prompt (Optional[Prompt]): The constructed Prompt class. + msg_history (Optional[List[Dict]]): The message history + provided by the user for chat model calls. + prompt_params (Optional[Dict]): The parameters provided + by the user that will be formatted into the final LLM prompt. + num_reasks (Optional[int]): The total number of reasks allowed; + user provided or defaulted. + metadata (Optional[Dict[str, Any]]): The metadata provided + by the user to be used during validation. + full_schema_reask (Optional[bool]): Whether reasks we + performed across the entire schema or at the field level. + stream (Optional[bool]): Whether or not streaming was used. + """ + llm_api: Optional[PromptCallableBase] = Field( description="The constructed class for calling the LLM.", default=None ) diff --git a/guardrails/classes/history/iteration.py b/guardrails/classes/history/iteration.py index c440c7e95..45c60baab 100644 --- a/guardrails/classes/history/iteration.py +++ b/guardrails/classes/history/iteration.py @@ -19,6 +19,18 @@ class Iteration(IIteration, ArbitraryModel): + """An Iteration represents a single iteration of the validation loop + including a single call to the LLM if applicable. + + Attributes: + id (str): The unique identifier for the iteration. + call_id (str): The unique identifier for the Call + that this iteration is a part of. + index (int): The index of this iteration within the Call. + inputs (Inputs): The inputs for the validation loop. + outputs (Outputs): The outputs from the validation loop. + """ + # I think these should be containered since their names slightly overlap with # outputs, but could be convinced otherwise inputs: Inputs = Field( diff --git a/guardrails/classes/history/outputs.py b/guardrails/classes/history/outputs.py index dda4c7340..a2c21ac1e 100644 --- a/guardrails/classes/history/outputs.py +++ b/guardrails/classes/history/outputs.py @@ -20,6 +20,28 @@ class Outputs(IOutputs, ArbitraryModel): + """Outputs represent the data that is output from the validation loop. + + Attributes: + llm_response_info (Optional[LLMResponse]): Information from the LLM response + raw_output (Optional[str]): The exact output from the LLM. + parsed_output (Optional[Union[str, List, Dict]]): The output parsed from the LLM + response as it was passed into validation. + validation_response (Optional[Union[str, ReAsk, List, Dict]]): The response + from the validation process. + guarded_output (Optional[Union[str, List, Dict]]): Any valid values after + undergoing validation. + Some values may be "fixed" values that were corrected during validation. + This property may be a partial structure if field level reasks occur. + reasks (List[ReAsk]): Information from the validation process used to construct + a ReAsk to the LLM on validation failure. Default []. + validator_logs (List[ValidatorLogs]): The results of each individual + validation. Default []. + error (Optional[str]): The error message from any exception that raised + and interrupted the process. + exception (Optional[Exception]): The exception that interrupted the process. + """ + llm_response_info: Optional[LLMResponse] = Field( description="Information from the LLM response.", default=None ) @@ -47,7 +69,6 @@ class Outputs(IOutputs, ArbitraryModel): default_factory=list, ) # TODO: Rename this; - # TODO: Add json_path to ValidatorLogs to specify what property it applies to validator_logs: List[ValidatorLogs] = Field( description="The results of each individual validation.", default_factory=list ) diff --git a/guardrails/classes/llm/llm_response.py b/guardrails/classes/llm/llm_response.py index 6051d2fca..d26e37a35 100644 --- a/guardrails/classes/llm/llm_response.py +++ b/guardrails/classes/llm/llm_response.py @@ -13,6 +13,21 @@ def async_to_sync(awaitable): # TODO: We might be able to delete this class LLMResponse(ILLMResponse): + """Standard information collection from LLM responses to feed the + validation loop. + + Attributes: + output (str): The output from the LLM. + stream_output (Optional[Iterable]): A stream of output from the LLM. + Default None. + async_stream_output (Optional[AsyncIterable]): An async stream of output + from the LLM. Default None. + prompt_token_count (Optional[int]): The number of tokens in the prompt. + Default None. + response_token_count (Optional[int]): The number of tokens in the response. + Default None. + """ + # Pydantic Config model_config = ConfigDict(arbitrary_types_allowed=True) diff --git a/guardrails/classes/validation/validation_result.py b/guardrails/classes/validation/validation_result.py index 316f3c415..18e6a0baa 100644 --- a/guardrails/classes/validation/validation_result.py +++ b/guardrails/classes/validation/validation_result.py @@ -10,11 +10,19 @@ class ValidationResult(IValidationResult, ArbitraryModel): + """ValidationResult is the output type of Validator.validate and the + abstract base class for all validation results. + + Attributes: + outcome (str): The outcome of the validation. Must be one of "pass" or "fail". + metadata (Optional[Dict[str, Any]]): The metadata associated with this + validation result. + validated_chunk (Optional[Any]): The value argument passed to + validator.validate or validator.validate_stream. + """ + outcome: str metadata: Optional[Dict[str, Any]] = None - - # value argument passed to validator.validate - # or validator.validate_stream validated_chunk: Optional[Any] = None @classmethod @@ -45,6 +53,15 @@ def from_dict(cls, obj: Dict[str, Any]) -> "ValidationResult": class PassResult(ValidationResult, IPassResult): + """PassResult is the output type of Validator.validate when validation + succeeds. + + Attributes: + outcome (Literal["pass"]): The outcome of the validation. Must be "pass". + value_override (Optional[Any]): The value to use as an override + if validation passes. + """ + outcome: Literal["pass"] = "pass" class ValueOverrideSentinel: @@ -76,21 +93,28 @@ def to_dict(self) -> Dict[str, Any]: return _dict -# FIXME: Add this to json schema -class ErrorSpan(IErrorSpan, ArbitraryModel): - start: int - end: int - # reason validation failed, specific to this chunk - reason: str - - class FailResult(ValidationResult, IFailResult): + """FailResult is the output type of Validator.validate when validation + fails. + + Attributes: + outcome (Literal["fail"]): The outcome of the validation. Must be "fail". + error_message (str): The error message indicating why validation failed. + fix_value (Optional[Any]): The auto-fix value that would be applied + if the Validator's on_fail method is "fix". + error_spans (Optional[List[ErrorSpan]]): Segments that caused + validation to fail. + """ + outcome: Literal["fail"] = "fail" error_message: str fix_value: Optional[Any] = None - # segments that caused validation to fail - error_spans: Optional[List[ErrorSpan]] = None + """Segments that caused validation to fail. + + May not exist for non-streamed output. + """ + error_spans: Optional[List["ErrorSpan"]] = None @classmethod def from_interface(cls, i_fail_result: IFailResult) -> "FailResult": @@ -137,3 +161,21 @@ def to_dict(self) -> Dict[str, Any]: ), } return _dict + + +class ErrorSpan(IErrorSpan, ArbitraryModel): + """ErrorSpan provide additional context for why a validation failed. They + specify the start and end index of the segment that caused the failure, + which can be useful when validating large chunks of text or validating + while streaming with different chunking methods. + + Attributes: + start (int): Starting index relative to the validated chunk. + end (int): Ending index relative to the validated chunk. + reason (str): Reason validation failed for this chunk. + """ + + start: int + end: int + # reason validation failed, specific to this chunk + reason: str diff --git a/guardrails/classes/validation/validator_logs.py b/guardrails/classes/validation/validator_logs.py index 7cf31f193..cb38e22cb 100644 --- a/guardrails/classes/validation/validator_logs.py +++ b/guardrails/classes/validation/validator_logs.py @@ -12,7 +12,20 @@ class ValidatorLogs(IValidatorLog, ArbitraryModel): - """Logs for a single validator.""" + """Logs for a single validator execution. + + Attributes: + validator_name (str): The class name of the validator + registered_name (str): The snake_cased id of the validator + property_path (str): The JSON path to the property being validated + value_before_validation (Any): The value before validation + value_after_validation (Optional[Any]): The value after validation; + could be different if `value_override`s or `fix`es are applied + validation_result (Optional[ValidationResult]): The result of the validation + start_time (Optional[datetime]): The time the validation started + end_time (Optional[datetime]): The time the validation ended + instance_id (Optional[int]): The unique id of this instance of the validator + """ validator_name: str registered_name: str diff --git a/guardrails/classes/validation/validator_reference.py b/guardrails/classes/validation/validator_reference.py new file mode 100644 index 000000000..93890d0b0 --- /dev/null +++ b/guardrails/classes/validation/validator_reference.py @@ -0,0 +1,19 @@ +from guardrails_api_client import ValidatorReference as IValidatorReference + + +# Docs only +class ValidatorReference(IValidatorReference): + """ValidatorReference is a serialized reference for constructing a + Validator. + + Attributes: + id (Optional[str]): The unique identifier for this Validator. + Often the hub id; e.g. guardrails/regex_match. Default None. + on (Optional[str]): A reference to the property this validator should be + applied against. Can be a valid JSON path or a meta-property + such as `prompt` or `output`. Default None. + on_fail (Optional[str]): The OnFailAction to apply during validation. + Default None. + args (Optional[List[Any]]): Positional arguments. Default None. + kwargs (Optional[Dict[str, Any]]): Keyword arguments. Default None. + """ diff --git a/guardrails/classes/validation_outcome.py b/guardrails/classes/validation_outcome.py index fe23a1e91..39f26a363 100644 --- a/guardrails/classes/validation_outcome.py +++ b/guardrails/classes/validation_outcome.py @@ -16,6 +16,21 @@ class ValidationOutcome(IValidationOutcome, ArbitraryModel, Generic[OT]): + """The final output from a Guard execution. + + Attributes: + call_id: The id of the Call that produced this ValidationOutcome. + raw_llm_output: The raw, unchanged output from the LLM call. + validated_output: The validated, and potentially fixed, output from the LLM call + after passing through validation. + reask: If validation continuously fails and all allocated reasks are used, + this field will contain the final reask that would have been sent + to the LLM if additional reasks were available. + validation_passed: A boolean to indicate whether or not the LLM output + passed validation. If this is False, the validated_output may be invalid. + error: If the validation failed, this field will contain the error message + """ + raw_llm_output: Optional[str] = Field( description="The raw, unchanged output from the LLM call.", default=None ) diff --git a/guardrails/errors/__init__.py b/guardrails/errors/__init__.py index 64b795688..529467074 100644 --- a/guardrails/errors/__init__.py +++ b/guardrails/errors/__init__.py @@ -1,5 +1,11 @@ class ValidationError(Exception): - """Top level validation error.""" + """Top level validation error. + + This is thrown from the validation engine when a Validator has + on_fail=OnFailActions.EXCEPTION set and validation fails. + + Inherits from Exception. + """ class UserFacingException(Exception): diff --git a/guardrails/formatters/json_formatter.py b/guardrails/formatters/json_formatter.py index 000423851..791b823f1 100644 --- a/guardrails/formatters/json_formatter.py +++ b/guardrails/formatters/json_formatter.py @@ -87,6 +87,9 @@ def _jsonschema_to_jsonformer( class JsonFormatter(BaseFormatter): + """A formatter that uses Jsonformer to ensure the shape of structured data + for Hugging Face models.""" + def __init__(self, schema: dict): self.output_schema = _jsonschema_to_jsonformer(schema) diff --git a/guardrails/guard.py b/guardrails/guard.py index 0b21e1c08..fc8546ec8 100644 --- a/guardrails/guard.py +++ b/guardrails/guard.py @@ -31,6 +31,7 @@ from guardrails.api_client import GuardrailsApiClient from guardrails.classes.output_type import OT +from guardrails.classes.validation.validation_result import ErrorSpan from guardrails.classes.validation_outcome import ValidationOutcome from guardrails.classes.credentials import Credentials from guardrails.classes.execution import GuardExecutionOptions @@ -79,7 +80,10 @@ ValidatorMap, ) -from guardrails.utils.tools_utils import add_json_function_calling_tool +from guardrails.utils.tools_utils import ( + # Prevent duplicate declaration in the docs + add_json_function_calling_tool as add_json_function_calling_tool_util, +) class Guard(IGuard, Generic[OT]): @@ -118,7 +122,11 @@ def __init__( validators: Optional[List[ValidatorReference]] = None, output_schema: Optional[Dict[str, Any]] = None, ): - """Initialize the Guard with validators and an output schema.""" + """Initialize the Guard with serialized validator references and an + output schema. + + Output schema must be a valid JSON Schema. + """ _try_to_load = name is not None @@ -351,7 +359,8 @@ def from_rail( name: Optional[str] = None, description: Optional[str] = None, ): - """Create a Schema from a `.rail` file. + """Create a Guard using a `.rail` file to specify the output schema, + prompt, etc. Args: rail_file: The path to the `.rail` file. @@ -399,7 +408,8 @@ def from_rail_string( name: Optional[str] = None, description: Optional[str] = None, ): - """Create a Schema from a `.rail` string. + """Create a Guard using a `.rail` string to specify the output schema, + prompt, etc.. Args: rail_string: The `.rail` string. @@ -452,7 +462,8 @@ def from_pydantic( description: Optional[str] = None, output_formatter: Optional[Union[str, BaseFormatter]] = None, ): - """Create a Guard instance from a Pydantic model. + """Create a Guard instance using a Pydantic model to specify the output + schema. Args: output_class: (Union[Type[BaseModel], List[Type[BaseModel]]]): The pydantic model that describes @@ -832,7 +843,7 @@ def __call__( Args: llm_api: The LLM API to call - (e.g. openai.Completion.create or openai.Completion.acreate) + (e.g. openai.completions.create or openai.Completion.acreate) prompt_params: The parameters to pass to the prompt.format() method. num_reasks: The max times to re-ask the LLM for invalid output. prompt: The prompt to use for the LLM. @@ -845,7 +856,7 @@ def __call__( `False` otherwise. Returns: - The raw text output from the LLM and the validated output. + ValidationOutcome """ instructions = instructions or self._exec_opts.instructions prompt = prompt or self._exec_opts.prompt @@ -887,15 +898,14 @@ def parse( llm_output: The output being parsed and validated. metadata: Metadata to pass to the validators. llm_api: The LLM API to call - (e.g. openai.Completion.create or openai.Completion.acreate) + (e.g. openai.completions.create or openai.Completion.acreate) num_reasks: The max times to re-ask the LLM for invalid output. prompt_params: The parameters to pass to the prompt.format() method. full_schema_reask: When reasking, whether to regenerate the full schema or just the incorrect values. Returns: - The validated response. This is either a string or a dictionary, - determined by the object schema defined in the RAILspec. + ValidationOutcome """ final_num_reasks = ( num_reasks @@ -929,7 +939,8 @@ def parse( **kwargs, ) - def error_spans_in_output(self): + def error_spans_in_output(self) -> List[ErrorSpan]: + """Get the error spans in the last output.""" try: call = self.history.last if call: @@ -991,8 +1002,6 @@ def use( - The instructions - The message history - *Note*: For on="output", `use` is only available for string output types. - Args: validator: The validator to use. Either the class or an instance. on: The part of the LLM request to validate. Defaults to "output". @@ -1017,7 +1026,7 @@ def use_many( *validators: UseManyValidatorSpec, on: str = "output", ) -> "Guard": - """Use a validator to validate results of an LLM request.""" + """Use multiple validators to validate results of an LLM request.""" # Loop through the validators for v in validators: hydrated_validator = get_validator(v) @@ -1192,6 +1201,7 @@ def _save(self): self.upsert_guard() def to_runnable(self) -> Runnable: + """Convert a Guard to a LangChain Runnable.""" from guardrails.integrations.langchain.guard_runnable import GuardRunnable return GuardRunnable(self) @@ -1213,7 +1223,9 @@ def add_json_function_calling_tool( self, tools: list, ) -> List[Dict[str, Any]]: - tools = add_json_function_calling_tool( + """Appends an OpenAI tool that specifies the output structure using + JSON Schema for chat models.""" + tools = add_json_function_calling_tool_util( tools=tools, # todo to_dict has a slight bug workaround here # but should fix in the long run dont have to diff --git a/guardrails/llm_providers.py b/guardrails/llm_providers.py index 9525f075d..19c7cee23 100644 --- a/guardrails/llm_providers.py +++ b/guardrails/llm_providers.py @@ -178,7 +178,7 @@ def _invoke_llm( Use Guardrails with OpenAI chat engines by doing ``` raw_llm_response, validated_response, *rest = guard( - openai.ChatCompletion.create, + openai.chat.completions.create, prompt_params={...}, text=..., instructions=..., @@ -754,7 +754,7 @@ async def invoke_llm( Use Guardrails with OpenAI chat engines by doing ``` raw_llm_response, validated_response, *rest = guard( - openai.ChatCompletion.create, + openai.chat.completions.create, prompt_params={...}, text=..., instructions=..., diff --git a/guardrails/prompt/base_prompt.py b/guardrails/prompt/base_prompt.py index 1eed29cc1..1ff70559e 100644 --- a/guardrails/prompt/base_prompt.py +++ b/guardrails/prompt/base_prompt.py @@ -2,7 +2,7 @@ import re from string import Template -from typing import Optional +from typing import List, Optional import regex @@ -21,6 +21,7 @@ def __init__( *, xml_output_schema: Optional[str] = None, ): + """Initialize and substitute constants in the prompt.""" self._source = source self.format_instructions_start = self.get_format_instructions_idx(source) @@ -55,7 +56,7 @@ def variable_names(self): def format_instructions(self): return self.source[self.format_instructions_start :] - def substitute_constants(self, text): + def substitute_constants(self, text: str) -> str: """Substitute constants in the prompt.""" # Substitute constants by reading the constants file. # Regex to extract all occurrences of ${gr.