diff --git a/.github/workflows/test_llm.yml b/.github/workflows/test_llm.yml index 8856d9f5..b4af7d73 100644 --- a/.github/workflows/test_llm.yml +++ b/.github/workflows/test_llm.yml @@ -31,4 +31,4 @@ jobs: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} run: | - uv run pytest tests/test_handlers_llm_provider.py -v --tb=short + uv run pytest tests/test_handlers_llm_provider*.py -v --tb=short diff --git a/docs/source/llm.ipynb b/docs/source/llm.ipynb index 433f9dc8..f81ba027 100644 --- a/docs/source/llm.ipynb +++ b/docs/source/llm.ipynb @@ -55,7 +55,11 @@ }, { "cell_type": "code", +<<<<<<< HEAD + "execution_count": 2, +======= "execution_count": 34, +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 "id": "1e832675", "metadata": {}, "outputs": [], @@ -78,7 +82,11 @@ }, { "cell_type": "code", +<<<<<<< HEAD + "execution_count": 3, +======= "execution_count": 35, +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 "id": "634f6533", "metadata": {}, "outputs": [ @@ -86,6 +94,21 @@ "name": "stdout", "output_type": "stream", "text": [ +<<<<<<< HEAD + "In the ocean, a fish swam with glee, \n", + "Darting 'round coral, wild and free. \n", + "With scales shining bright, \n", + "It danced in the light, \n", + "A marvel for all eyes to see.\n", + "----------------------------------------\n", + "Here is a limerick on the theme of fish:\n", + "\n", + "In the ocean, a fish did flip, \n", + "Dancing wildly, giving a dip. \n", + "With scales all agleam, \n", + "In a silvery beam, \n", + "It glided with hardly a slip.\n" +======= "In the ocean so vast and so wide, \n", "A little fish tried hard to hide. \n", "With scales shining bright, \n", @@ -97,6 +120,7 @@ "He danced through the tide, \n", "With friends by his side, \n", "A joyous splash with his slippery fin!\n" +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 ] } ], @@ -117,7 +141,11 @@ }, { "cell_type": "code", +<<<<<<< HEAD + "execution_count": 4, +======= "execution_count": 36, +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 "id": "706ce53b", "metadata": {}, "outputs": [ @@ -126,6 +154,35 @@ "output_type": "stream", "text": [ "\n", +<<<<<<< HEAD + "In water's embrace, \n", + "Silver scales shimmer and glide, \n", + "Silent currents flow.\n", + "----------------------------------------\n", + "In water's embrace, \n", + "Silver scales shimmer and glide, \n", + "Silent currents flow.\n", + "\n", + "Fish swim silently, \n", + "Beneath the sunlit ripples, \n", + "Whispers of the deep. \n", + "----------------------------------------\n", + "Fish swim silently, \n", + "Beneath the sunlit ripples, \n", + "Whispers of the deep. \n", + "\n", + "Here's a haiku on the theme of fish3:\n", + "\n", + "In gentle streams flow, \n", + "Fish dance with the water's grace, \n", + "Nature's quiet show.\n", + "----------------------------------------\n", + "Here's a haiku on the theme of fish3:\n", + "\n", + "In gentle streams flow, \n", + "Fish dance with the water's grace, \n", + "Nature's quiet show.\n" +======= "Glimmering scales shine, \n", "Dancing in the water's flow, \n", "Silent whispers swim. \n", @@ -149,6 +206,7 @@ "Fish swim in clear stream, \n", "Scales shimmer in sunlight glow, \n", "Nature's quiet dance.\n" +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 ] } ], @@ -199,7 +257,11 @@ }, { "cell_type": "code", +<<<<<<< HEAD + "execution_count": 5, +======= "execution_count": 37, +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 "id": "2c766859", "metadata": {}, "outputs": [], @@ -216,6 +278,59 @@ }, { "cell_type": "markdown", +<<<<<<< HEAD + "id": "36d78a71", + "metadata": {}, + "source": [ + "More complex types can be converted by providing handlers for `decode`. `ProgramSynthesisIntp` provides a `decode` handler that parses Python callables." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "c83bbdc0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "def count_a_occurrences(input_string: str) -> int:\n", + " \"\"\"\n", + " Count the occurrences of the character 'a' in a given string.\n", + "\n", + " :param input_string: The string in which to count 'a' occurrences.\n", + " :return: The number of times 'a' appears in the input string.\n", + " \"\"\"\n", + " count = 0\n", + " for char in input_string:\n", + " if char == 'a':\n", + " count += 1\n", + " return count\n", + "\n" + ] + } + ], + "source": [ + "@Template.define\n", + "def count_char(char: str) -> Callable[[str], int]:\n", + " \"\"\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\"\"\"\n", + " raise NotHandled\n", + "\n", + "\n", + "with handler(provider), handler(ProgramSynthesis()):\n", + " count_a = count_char(\"a\")\n", + " assert callable(count_a)\n", + " assert count_a(\"banana\") == 3\n", + " assert count_a(\"cherry\") == 0\n", + " # Print the source code of the generated function\n", + " print(inspect.getsource(count_a))" + ] + }, + { + "cell_type": "markdown", +======= +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 "id": "991ee445", "metadata": {}, "source": [ @@ -228,7 +343,11 @@ }, { "cell_type": "code", +<<<<<<< HEAD + "execution_count": 7, +======= "execution_count": 39, +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 "id": "66711301", "metadata": {}, "outputs": [ @@ -240,7 +359,11 @@ "Tool call: weather(*(), **{'city': 'Chicago'}) -> cold\n", "Tool call: weather(*(), **{'city': 'New York'}) -> wet\n", "Tool call: weather(*(), **{'city': 'Barcelona'}) -> sunny\n", +<<<<<<< HEAD + "Based on the weather information, Barcelona currently has good weather, described as \"sunny.\"\n" +======= "Based on the weather conditions, Barcelona has good weather as it is sunny.\n" +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 ] } ], @@ -286,7 +409,11 @@ }, { "cell_type": "code", +<<<<<<< HEAD + "execution_count": 8, +======= "execution_count": 40, +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 "id": "17668ac8", "metadata": {}, "outputs": [ @@ -299,7 +426,11 @@ "Who's there?\n", "Lizard.\n", "Lizard who?\n", +<<<<<<< HEAD + "Lizard be the funniest joke you've heard yet!\n", +======= "Lizard who? Lizard you! Open the door, it's chilly out here!\n", +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 "> The crowd stares in stony silence.\n" ] } @@ -350,7 +481,11 @@ }, { "cell_type": "code", +<<<<<<< HEAD + "execution_count": 9, +======= "execution_count": 41, +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 "id": "cbf495a2", "metadata": {}, "outputs": [ @@ -358,6 +493,10 @@ "name": "stdout", "output_type": "stream", "text": [ +<<<<<<< HEAD + "Request fired: () {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Write a haiku on the theme of fish2. Do not use any tools.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}]} ModelResponse(id='chatcmpl-CnUE7fbXtVjJgIODaUDGK8gtwmWor', created=1765910299, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content=\"In the deep blue sea, \\nSilver scales gently shimmer— \\nNature's quiet dance.\", role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=19, prompt_tokens=364, total_tokens=383, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')\n", + "Request fired: () {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Write a limerick on the theme of fish. Do not use any tools.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}]} ModelResponse(id='chatcmpl-CnUE8vMEssF1FzFejbIOcxhnjZiDK', created=1765910300, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content='In the ocean, there swam a bright fish, \\nWhose colors would swirl and swish. \\nHe danced through the sea, \\nSo wild and so free, \\nA sight that fulfilled every wish.', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=44, prompt_tokens=364, total_tokens=408, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')\n" +======= "> Write a haiku on the theme of fish2. Do not use any tools.\n", "In waters serene, \n", "Gliding scales of silver bright, \n", @@ -368,6 +507,7 @@ "He swam with a wail, \n", "To the tip of his tail, \n", "And waved to the marlins in May.\n" +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 ] } ], @@ -403,7 +543,11 @@ }, { "cell_type": "code", +<<<<<<< HEAD + "execution_count": 10, +======= "execution_count": 42, +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 "id": "81a15f00", "metadata": {}, "outputs": [ @@ -411,6 +555,16 @@ "name": "stdout", "output_type": "stream", "text": [ +<<<<<<< HEAD + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Write a haiku on the theme of fish3. Do not use any tools.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUE9dXHuFAfKrcdrwc7CRY6H2vz8', created=1765910301, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content=None, role='assistant', tool_calls=[ChatCompletionMessageToolCall(function=Function(arguments='{\"theme\":\"fish3\"}', name='haiku_no_cache'), id='call_qslYzCSecwT5pFjoGHwzwi50', type='function')], function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=18, prompt_tokens=364, total_tokens=382, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Write a haiku on the theme of fish3. Do not use any tools.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUE96ToBoMlPV1OyIvlnWNFNGVBo', created=1765910301, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content=None, role='assistant', tool_calls=[ChatCompletionMessageToolCall(function=Function(arguments='{\"theme\":\"fish\"}', name='haiku_no_cache'), id='call_OZxMIjFhLozcK6mjbbSwlGpK', type='function')], function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=17, prompt_tokens=364, total_tokens=381, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Write a haiku on the theme of fish. Do not use any tools.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEAZwKsJqw6SVTCIVNxx6dq69SO', created=1765910302, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content='Silent waters glide, \\nSilver scales flicker below— \\nWhispers of the deep.', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=19, prompt_tokens=363, total_tokens=382, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'tool': 'haiku_no_cache', 'args': (), 'kwargs': {'theme': 'fish'}}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Write a haiku on the theme of fish3. Do not use any tools.'}], 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{\"theme\":\"fish\"}', 'name': 'haiku_no_cache'}, 'id': 'call_OZxMIjFhLozcK6mjbbSwlGpK', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_OZxMIjFhLozcK6mjbbSwlGpK', 'name': 'haiku_no_cache', 'content': [{'type': 'text', 'text': 'Silent waters glide, \\nSilver scales flicker below— \\nWhispers of the deep.'}]}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEA73rIuQD7tQWwNwvMlolNgoRO', created=1765910302, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content='Here is a haiku on the theme of fish:\\n\\nSilent waters glide, \\nSilver scales flicker below— \\nWhispers of the deep.', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=30, prompt_tokens=409, total_tokens=439, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'tool': 'haiku_no_cache', 'args': (), 'kwargs': {'theme': 'fish3'}}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Write a haiku on the theme of fish3. Do not use any tools.'}], 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{\"theme\":\"fish3\"}', 'name': 'haiku_no_cache'}, 'id': 'call_qslYzCSecwT5pFjoGHwzwi50', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_qslYzCSecwT5pFjoGHwzwi50', 'name': 'haiku_no_cache', 'content': [{'type': 'text', 'text': 'Here is a haiku on the theme of fish:\\n\\nSilent waters glide, \\nSilver scales flicker below— \\nWhispers of the deep.'}]}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEBG8aYhVGdEoMD6f1XUvs2NyBd', created=1765910303, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content='Here is a haiku on the theme of fish:\\n\\nSilent waters glide, \\nSilver scales flicker below— \\nWhispers of the deep.', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=30, prompt_tokens=421, total_tokens=451, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Write a limerick on the theme of fish4. Do not use any tools.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUECinXFKY0SYBZuze4iP2R9DSJL', created=1765910304, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content=\"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=41, prompt_tokens=365, total_tokens=406, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n" +======= "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Write a haiku on the theme of fish3. Do not use any tools.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': 'Given a city name, return a description of the weather in that city.', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data. Do not use the fetch_data tool.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'give_rating_for_movie', 'description': 'Give a rating for {movie_name}. The explanation MUST include the numeric score. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'movie_name': {'title': 'Movie Name', 'type': 'string'}}, 'required': ['movie_name'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': 'Return a list of cities that can be passed to `weather`.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CpiNvfUe5SAUhZMSz1tNAzVXYgVmK', created=1766441379, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_deacdd5f6f', choices=[Choices(finish_reason='stop', index=0, message=Message(content=\"In waters they glide, \\nSilver scales shimmer and dance, \\nNature's silent grace. \", role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=20, prompt_tokens=643, total_tokens=663, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Write a haiku on the theme of fish3. Do not use any tools.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': 'Given a city name, return a description of the weather in that city.', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data. Do not use the fetch_data tool.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'give_rating_for_movie', 'description': 'Give a rating for {movie_name}. The explanation MUST include the numeric score. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'movie_name': {'title': 'Movie Name', 'type': 'string'}}, 'required': ['movie_name'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': 'Return a list of cities that can be passed to `weather`.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CpiNvfUe5SAUhZMSz1tNAzVXYgVmK', created=1766441379, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_deacdd5f6f', choices=[Choices(finish_reason='stop', index=0, message=Message(content=\"In waters they glide, \\nSilver scales shimmer and dance, \\nNature's silent grace. \", role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=20, prompt_tokens=643, total_tokens=663, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Write a limerick on the theme of fish4. Do not use any tools.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': 'Given a city name, return a description of the weather in that city.', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data. Do not use the fetch_data tool.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'give_rating_for_movie', 'description': 'Give a rating for {movie_name}. The explanation MUST include the numeric score. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'movie_name': {'title': 'Movie Name', 'type': 'string'}}, 'required': ['movie_name'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': 'Return a list of cities that can be passed to `weather`.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CpiNwNX281AjkWQ1dQ4k6EdUhYLcY', created=1766441380, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_deacdd5f6f', choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content=None, role='assistant', tool_calls=[ChatCompletionMessageToolCall(function=Function(arguments='{\"theme\":\"fish\"}', name='limerick'), id='call_saz9unenzuVoXATZ5fCZZ8Bt', type='function')], function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=15, prompt_tokens=644, total_tokens=659, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", @@ -419,6 +573,7 @@ "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Write a limerick on the theme of fish. Do not use any tools.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': 'Given a city name, return a description of the weather in that city.', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data. Do not use the fetch_data tool.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'give_rating_for_movie', 'description': 'Give a rating for {movie_name}. The explanation MUST include the numeric score. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'movie_name': {'title': 'Movie Name', 'type': 'string'}}, 'required': ['movie_name'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': 'Return a list of cities that can be passed to `weather`.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CpiNxuLZfAwYkaGF3fQh9qG200UyU', created=1766441381, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_deacdd5f6f', choices=[Choices(finish_reason='stop', index=0, message=Message(content='In a pond where the waters were still, \\nA fish had a wish to fulfill, \\nHe leaped in the air, \\nWith debonair flair, \\nAnd splashed down with plenty of thrill. ', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=45, prompt_tokens=643, total_tokens=688, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Write a limerick on the theme of fish4. Do not use any tools.'}], 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{\"theme\":\"fish\"}', 'name': 'limerick'}, 'id': 'call_saz9unenzuVoXATZ5fCZZ8Bt', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_saz9unenzuVoXATZ5fCZZ8Bt', 'name': 'limerick', 'content': [{'type': 'text', 'text': 'In a pond where the waters were still, \\nA fish had a wish to fulfill, \\nHe leaped in the air, \\nWith debonair flair, \\nAnd splashed down with plenty of thrill. '}]}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': 'Given a city name, return a description of the weather in that city.', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data. Do not use the fetch_data tool.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'give_rating_for_movie', 'description': 'Give a rating for {movie_name}. The explanation MUST include the numeric score. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'movie_name': {'title': 'Movie Name', 'type': 'string'}}, 'required': ['movie_name'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': 'Return a list of cities that can be passed to `weather`.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CpiNzarHb5Rc5y8Lns7KYZRUs9MKu', created=1766441383, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_deacdd5f6f', choices=[Choices(finish_reason='stop', index=0, message=Message(content='Here\\'s a limerick on the theme of \"fish\":\\n\\nIn a pond where the waters were still, \\nA fish had a wish to fulfill, \\nHe leaped in the air, \\nWith debonair flair, \\nAnd splashed down with plenty of thrill. ', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=57, prompt_tokens=712, total_tokens=769, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Write a limerick on the theme of fish4. Do not use any tools.'}], 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{\"theme\":\"fish\"}', 'name': 'limerick'}, 'id': 'call_saz9unenzuVoXATZ5fCZZ8Bt', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_saz9unenzuVoXATZ5fCZZ8Bt', 'name': 'limerick', 'content': [{'type': 'text', 'text': 'In a pond where the waters were still, \\nA fish had a wish to fulfill, \\nHe leaped in the air, \\nWith debonair flair, \\nAnd splashed down with plenty of thrill. '}]}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': 'Given a city name, return a description of the weather in that city.', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data. Do not use the fetch_data tool.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'give_rating_for_movie', 'description': 'Give a rating for {movie_name}. The explanation MUST include the numeric score. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'movie_name': {'title': 'Movie Name', 'type': 'string'}}, 'required': ['movie_name'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': 'Return a list of cities that can be passed to `weather`.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CpiNzarHb5Rc5y8Lns7KYZRUs9MKu', created=1766441383, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_deacdd5f6f', choices=[Choices(finish_reason='stop', index=0, message=Message(content='Here\\'s a limerick on the theme of \"fish\":\\n\\nIn a pond where the waters were still, \\nA fish had a wish to fulfill, \\nHe leaped in the air, \\nWith debonair flair, \\nAnd splashed down with plenty of thrill. ', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=57, prompt_tokens=712, total_tokens=769, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n" +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 ] } ], @@ -452,7 +607,11 @@ }, { "cell_type": "code", +<<<<<<< HEAD + "execution_count": 11, +======= "execution_count": 43, +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 "id": "78a4bf44", "metadata": {}, "outputs": [ @@ -460,6 +619,48 @@ "name": "stdout", "output_type": "stream", "text": [ +<<<<<<< HEAD + "Sub-templates available to write_story: [Template(__prompt_template__='Write a limerick on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': ..., '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': Template(__prompt_template__='Write a haiku on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='haiku_no_cache'), 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': Template(__prompt_template__='Give a prime number with {first_digit} as the first digit. Do not use any tools.', __signature__= int>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='primes'), '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': Template(__prompt_template__=\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", __signature__= collections.abc.Callable[[str], int]>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='count_char'), 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': Template(__prompt_template__='Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='vacation'), 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': Template(__prompt_template__='Write a knock-knock joke on the theme of {theme}. Do not use any tools.', __signature__= __main__.KnockKnockJoke>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_joke'), 'rate_joke': Template(__prompt_template__='Decide if {joke} is funny or not. Do not use any tools.', __signature__= bool>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='rate_joke'), 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': Template(__prompt_template__='Write a short story about {topic} and end with a moral lesson. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_with_moral'), 'story_funny': Template(__prompt_template__='Write a funny, humorous story about {topic}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_funny'), 'write_story': Template(__prompt_template__=\"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_story')}), mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': ..., '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': Template(__prompt_template__='Write a haiku on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='haiku_no_cache'), 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': Template(__prompt_template__='Give a prime number with {first_digit} as the first digit. Do not use any tools.', __signature__= int>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='primes'), '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': Template(__prompt_template__=\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", __signature__= collections.abc.Callable[[str], int]>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='count_char'), 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': Template(__prompt_template__='Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='vacation'), 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': Template(__prompt_template__='Write a knock-knock joke on the theme of {theme}. Do not use any tools.', __signature__= __main__.KnockKnockJoke>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_joke'), 'rate_joke': Template(__prompt_template__='Decide if {joke} is funny or not. Do not use any tools.', __signature__= bool>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='rate_joke'), 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': Template(__prompt_template__='Write a short story about {topic} and end with a moral lesson. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_with_moral'), 'story_funny': Template(__prompt_template__='Write a funny, humorous story about {topic}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_funny'), 'write_story': Template(__prompt_template__=\"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_story')})), __name__='limerick'), Template(__prompt_template__='Write a haiku on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': Template(__prompt_template__='Write a limerick on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='limerick'), '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': ..., 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': Template(__prompt_template__='Give a prime number with {first_digit} as the first digit. Do not use any tools.', __signature__= int>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='primes'), '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': Template(__prompt_template__=\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", __signature__= collections.abc.Callable[[str], int]>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='count_char'), 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': Template(__prompt_template__='Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='vacation'), 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': Template(__prompt_template__='Write a knock-knock joke on the theme of {theme}. Do not use any tools.', __signature__= __main__.KnockKnockJoke>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_joke'), 'rate_joke': Template(__prompt_template__='Decide if {joke} is funny or not. Do not use any tools.', __signature__= bool>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='rate_joke'), 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': Template(__prompt_template__='Write a short story about {topic} and end with a moral lesson. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_with_moral'), 'story_funny': Template(__prompt_template__='Write a funny, humorous story about {topic}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_funny'), 'write_story': Template(__prompt_template__=\"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_story')}), mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': Template(__prompt_template__='Write a limerick on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='limerick'), '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': ..., 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': Template(__prompt_template__='Give a prime number with {first_digit} as the first digit. Do not use any tools.', __signature__= int>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='primes'), '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': Template(__prompt_template__=\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", __signature__= collections.abc.Callable[[str], int]>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='count_char'), 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': Template(__prompt_template__='Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='vacation'), 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': Template(__prompt_template__='Write a knock-knock joke on the theme of {theme}. Do not use any tools.', __signature__= __main__.KnockKnockJoke>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_joke'), 'rate_joke': Template(__prompt_template__='Decide if {joke} is funny or not. Do not use any tools.', __signature__= bool>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='rate_joke'), 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': Template(__prompt_template__='Write a short story about {topic} and end with a moral lesson. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_with_moral'), 'story_funny': Template(__prompt_template__='Write a funny, humorous story about {topic}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_funny'), 'write_story': Template(__prompt_template__=\"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_story')})), __name__='haiku_no_cache'), Template(__prompt_template__='Give a prime number with {first_digit} as the first digit. Do not use any tools.', __signature__= int>, __context__=LexicalContext(mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': Template(__prompt_template__='Write a limerick on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='limerick'), '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': Template(__prompt_template__='Write a haiku on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='haiku_no_cache'), 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': ..., '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': Template(__prompt_template__=\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", __signature__= collections.abc.Callable[[str], int]>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='count_char'), 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': Template(__prompt_template__='Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='vacation'), 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': Template(__prompt_template__='Write a knock-knock joke on the theme of {theme}. Do not use any tools.', __signature__= __main__.KnockKnockJoke>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_joke'), 'rate_joke': Template(__prompt_template__='Decide if {joke} is funny or not. Do not use any tools.', __signature__= bool>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='rate_joke'), 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': Template(__prompt_template__='Write a short story about {topic} and end with a moral lesson. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_with_moral'), 'story_funny': Template(__prompt_template__='Write a funny, humorous story about {topic}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_funny'), 'write_story': Template(__prompt_template__=\"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_story')}), mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': Template(__prompt_template__='Write a limerick on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='limerick'), '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': Template(__prompt_template__='Write a haiku on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='haiku_no_cache'), 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': ..., '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': Template(__prompt_template__=\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", __signature__= collections.abc.Callable[[str], int]>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='count_char'), 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': Template(__prompt_template__='Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='vacation'), 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': Template(__prompt_template__='Write a knock-knock joke on the theme of {theme}. Do not use any tools.', __signature__= __main__.KnockKnockJoke>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_joke'), 'rate_joke': Template(__prompt_template__='Decide if {joke} is funny or not. Do not use any tools.', __signature__= bool>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='rate_joke'), 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': Template(__prompt_template__='Write a short story about {topic} and end with a moral lesson. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_with_moral'), 'story_funny': Template(__prompt_template__='Write a funny, humorous story about {topic}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_funny'), 'write_story': Template(__prompt_template__=\"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_story')})), __name__='primes'), Template(__prompt_template__=\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", __signature__= collections.abc.Callable[[str], int]>, __context__=LexicalContext(mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': Template(__prompt_template__='Write a limerick on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='limerick'), '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': Template(__prompt_template__='Write a haiku on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='haiku_no_cache'), 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': Template(__prompt_template__='Give a prime number with {first_digit} as the first digit. Do not use any tools.', __signature__= int>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='primes'), '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': ..., 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': Template(__prompt_template__='Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='vacation'), 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': Template(__prompt_template__='Write a knock-knock joke on the theme of {theme}. Do not use any tools.', __signature__= __main__.KnockKnockJoke>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_joke'), 'rate_joke': Template(__prompt_template__='Decide if {joke} is funny or not. Do not use any tools.', __signature__= bool>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='rate_joke'), 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': Template(__prompt_template__='Write a short story about {topic} and end with a moral lesson. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_with_moral'), 'story_funny': Template(__prompt_template__='Write a funny, humorous story about {topic}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_funny'), 'write_story': Template(__prompt_template__=\"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_story')}), mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': Template(__prompt_template__='Write a limerick on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='limerick'), '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': Template(__prompt_template__='Write a haiku on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='haiku_no_cache'), 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': Template(__prompt_template__='Give a prime number with {first_digit} as the first digit. Do not use any tools.', __signature__= int>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='primes'), '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': ..., 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': Template(__prompt_template__='Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='vacation'), 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': Template(__prompt_template__='Write a knock-knock joke on the theme of {theme}. Do not use any tools.', __signature__= __main__.KnockKnockJoke>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_joke'), 'rate_joke': Template(__prompt_template__='Decide if {joke} is funny or not. Do not use any tools.', __signature__= bool>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='rate_joke'), 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': Template(__prompt_template__='Write a short story about {topic} and end with a moral lesson. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_with_moral'), 'story_funny': Template(__prompt_template__='Write a funny, humorous story about {topic}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_funny'), 'write_story': Template(__prompt_template__=\"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_story')})), __name__='count_char'), Operation(cities, () -> list[str]), Operation(weather, (city: str) -> str), Template(__prompt_template__='Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', __signature__= str>, __context__=LexicalContext(mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': Template(__prompt_template__='Write a limerick on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='limerick'), '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': Template(__prompt_template__='Write a haiku on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='haiku_no_cache'), 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': Template(__prompt_template__='Give a prime number with {first_digit} as the first digit. Do not use any tools.', __signature__= int>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='primes'), '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': Template(__prompt_template__=\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", __signature__= collections.abc.Callable[[str], int]>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='count_char'), 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': ..., 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': Template(__prompt_template__='Write a knock-knock joke on the theme of {theme}. Do not use any tools.', __signature__= __main__.KnockKnockJoke>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_joke'), 'rate_joke': Template(__prompt_template__='Decide if {joke} is funny or not. Do not use any tools.', __signature__= bool>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='rate_joke'), 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': Template(__prompt_template__='Write a short story about {topic} and end with a moral lesson. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_with_moral'), 'story_funny': Template(__prompt_template__='Write a funny, humorous story about {topic}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_funny'), 'write_story': Template(__prompt_template__=\"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_story')}), mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': Template(__prompt_template__='Write a limerick on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='limerick'), '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': Template(__prompt_template__='Write a haiku on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='haiku_no_cache'), 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': Template(__prompt_template__='Give a prime number with {first_digit} as the first digit. Do not use any tools.', __signature__= int>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='primes'), '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': Template(__prompt_template__=\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", __signature__= collections.abc.Callable[[str], int]>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='count_char'), 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': ..., 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': Template(__prompt_template__='Write a knock-knock joke on the theme of {theme}. Do not use any tools.', __signature__= __main__.KnockKnockJoke>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_joke'), 'rate_joke': Template(__prompt_template__='Decide if {joke} is funny or not. Do not use any tools.', __signature__= bool>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='rate_joke'), 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': Template(__prompt_template__='Write a short story about {topic} and end with a moral lesson. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_with_moral'), 'story_funny': Template(__prompt_template__='Write a funny, humorous story about {topic}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_funny'), 'write_story': Template(__prompt_template__=\"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_story')})), __name__='vacation'), Template(__prompt_template__='Write a knock-knock joke on the theme of {theme}. Do not use any tools.', __signature__= __main__.KnockKnockJoke>, __context__=LexicalContext(mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': Template(__prompt_template__='Write a limerick on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='limerick'), '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': Template(__prompt_template__='Write a haiku on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='haiku_no_cache'), 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': Template(__prompt_template__='Give a prime number with {first_digit} as the first digit. Do not use any tools.', __signature__= int>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='primes'), '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': Template(__prompt_template__=\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", __signature__= collections.abc.Callable[[str], int]>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='count_char'), 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': Template(__prompt_template__='Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='vacation'), 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': ..., 'rate_joke': Template(__prompt_template__='Decide if {joke} is funny or not. Do not use any tools.', __signature__= bool>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='rate_joke'), 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': Template(__prompt_template__='Write a short story about {topic} and end with a moral lesson. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_with_moral'), 'story_funny': Template(__prompt_template__='Write a funny, humorous story about {topic}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_funny'), 'write_story': Template(__prompt_template__=\"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_story')}), mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': Template(__prompt_template__='Write a limerick on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='limerick'), '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': Template(__prompt_template__='Write a haiku on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='haiku_no_cache'), 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': Template(__prompt_template__='Give a prime number with {first_digit} as the first digit. Do not use any tools.', __signature__= int>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='primes'), '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': Template(__prompt_template__=\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", __signature__= collections.abc.Callable[[str], int]>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='count_char'), 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': Template(__prompt_template__='Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='vacation'), 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': ..., 'rate_joke': Template(__prompt_template__='Decide if {joke} is funny or not. Do not use any tools.', __signature__= bool>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='rate_joke'), 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': Template(__prompt_template__='Write a short story about {topic} and end with a moral lesson. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_with_moral'), 'story_funny': Template(__prompt_template__='Write a funny, humorous story about {topic}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_funny'), 'write_story': Template(__prompt_template__=\"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_story')})), __name__='write_joke'), Template(__prompt_template__='Decide if {joke} is funny or not. Do not use any tools.', __signature__= bool>, __context__=LexicalContext(mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': Template(__prompt_template__='Write a limerick on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='limerick'), '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': Template(__prompt_template__='Write a haiku on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='haiku_no_cache'), 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': Template(__prompt_template__='Give a prime number with {first_digit} as the first digit. Do not use any tools.', __signature__= int>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='primes'), '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': Template(__prompt_template__=\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", __signature__= collections.abc.Callable[[str], int]>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='count_char'), 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': Template(__prompt_template__='Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='vacation'), 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': Template(__prompt_template__='Write a knock-knock joke on the theme of {theme}. Do not use any tools.', __signature__= __main__.KnockKnockJoke>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_joke'), 'rate_joke': ..., 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': Template(__prompt_template__='Write a short story about {topic} and end with a moral lesson. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_with_moral'), 'story_funny': Template(__prompt_template__='Write a funny, humorous story about {topic}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_funny'), 'write_story': Template(__prompt_template__=\"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_story')}), mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': Template(__prompt_template__='Write a limerick on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='limerick'), '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': Template(__prompt_template__='Write a haiku on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='haiku_no_cache'), 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': Template(__prompt_template__='Give a prime number with {first_digit} as the first digit. Do not use any tools.', __signature__= int>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='primes'), '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': Template(__prompt_template__=\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", __signature__= collections.abc.Callable[[str], int]>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='count_char'), 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': Template(__prompt_template__='Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='vacation'), 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': Template(__prompt_template__='Write a knock-knock joke on the theme of {theme}. Do not use any tools.', __signature__= __main__.KnockKnockJoke>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_joke'), 'rate_joke': ..., 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': Template(__prompt_template__='Write a short story about {topic} and end with a moral lesson. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_with_moral'), 'story_funny': Template(__prompt_template__='Write a funny, humorous story about {topic}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_funny'), 'write_story': Template(__prompt_template__=\"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_story')})), __name__='rate_joke'), Template(__prompt_template__='Write a short story about {topic} and end with a moral lesson. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': Template(__prompt_template__='Write a limerick on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='limerick'), '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': Template(__prompt_template__='Write a haiku on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='haiku_no_cache'), 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': Template(__prompt_template__='Give a prime number with {first_digit} as the first digit. Do not use any tools.', __signature__= int>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='primes'), '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': Template(__prompt_template__=\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", __signature__= collections.abc.Callable[[str], int]>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='count_char'), 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': Template(__prompt_template__='Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='vacation'), 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': Template(__prompt_template__='Write a knock-knock joke on the theme of {theme}. Do not use any tools.', __signature__= __main__.KnockKnockJoke>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_joke'), 'rate_joke': Template(__prompt_template__='Decide if {joke} is funny or not. Do not use any tools.', __signature__= bool>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='rate_joke'), 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': ..., 'story_funny': Template(__prompt_template__='Write a funny, humorous story about {topic}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_funny'), 'write_story': Template(__prompt_template__=\"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_story')}), mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': Template(__prompt_template__='Write a limerick on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='limerick'), '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': Template(__prompt_template__='Write a haiku on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='haiku_no_cache'), 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': Template(__prompt_template__='Give a prime number with {first_digit} as the first digit. Do not use any tools.', __signature__= int>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='primes'), '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': Template(__prompt_template__=\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", __signature__= collections.abc.Callable[[str], int]>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='count_char'), 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': Template(__prompt_template__='Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='vacation'), 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': Template(__prompt_template__='Write a knock-knock joke on the theme of {theme}. Do not use any tools.', __signature__= __main__.KnockKnockJoke>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_joke'), 'rate_joke': Template(__prompt_template__='Decide if {joke} is funny or not. Do not use any tools.', __signature__= bool>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='rate_joke'), 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': ..., 'story_funny': Template(__prompt_template__='Write a funny, humorous story about {topic}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_funny'), 'write_story': Template(__prompt_template__=\"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_story')})), __name__='story_with_moral'), Template(__prompt_template__='Write a funny, humorous story about {topic}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': Template(__prompt_template__='Write a limerick on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='limerick'), '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': Template(__prompt_template__='Write a haiku on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='haiku_no_cache'), 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': Template(__prompt_template__='Give a prime number with {first_digit} as the first digit. Do not use any tools.', __signature__= int>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='primes'), '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': Template(__prompt_template__=\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", __signature__= collections.abc.Callable[[str], int]>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='count_char'), 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': Template(__prompt_template__='Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='vacation'), 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': Template(__prompt_template__='Write a knock-knock joke on the theme of {theme}. Do not use any tools.', __signature__= __main__.KnockKnockJoke>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_joke'), 'rate_joke': Template(__prompt_template__='Decide if {joke} is funny or not. Do not use any tools.', __signature__= bool>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='rate_joke'), 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': Template(__prompt_template__='Write a short story about {topic} and end with a moral lesson. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_with_moral'), 'story_funny': ..., 'write_story': Template(__prompt_template__=\"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_story')}), mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': Template(__prompt_template__='Write a limerick on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='limerick'), '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': Template(__prompt_template__='Write a haiku on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='haiku_no_cache'), 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': Template(__prompt_template__='Give a prime number with {first_digit} as the first digit. Do not use any tools.', __signature__= int>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='primes'), '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': Template(__prompt_template__=\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", __signature__= collections.abc.Callable[[str], int]>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='count_char'), 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': Template(__prompt_template__='Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='vacation'), 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': Template(__prompt_template__='Write a knock-knock joke on the theme of {theme}. Do not use any tools.', __signature__= __main__.KnockKnockJoke>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_joke'), 'rate_joke': Template(__prompt_template__='Decide if {joke} is funny or not. Do not use any tools.', __signature__= bool>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='rate_joke'), 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': Template(__prompt_template__='Write a short story about {topic} and end with a moral lesson. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_with_moral'), 'story_funny': ..., 'write_story': Template(__prompt_template__=\"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_story')})), __name__='story_funny'), Template(__prompt_template__=\"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", __signature__= str>, __context__=LexicalContext(mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': Template(__prompt_template__='Write a limerick on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='limerick'), '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': Template(__prompt_template__='Write a haiku on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='haiku_no_cache'), 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': Template(__prompt_template__='Give a prime number with {first_digit} as the first digit. Do not use any tools.', __signature__= int>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='primes'), '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': Template(__prompt_template__=\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", __signature__= collections.abc.Callable[[str], int]>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='count_char'), 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': Template(__prompt_template__='Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='vacation'), 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': Template(__prompt_template__='Write a knock-knock joke on the theme of {theme}. Do not use any tools.', __signature__= __main__.KnockKnockJoke>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_joke'), 'rate_joke': Template(__prompt_template__='Decide if {joke} is funny or not. Do not use any tools.', __signature__= bool>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='rate_joke'), 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': Template(__prompt_template__='Write a short story about {topic} and end with a moral lesson. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_with_moral'), 'story_funny': Template(__prompt_template__='Write a funny, humorous story about {topic}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_funny'), 'write_story': ...}), mappingproxy({'__name__': '__main__', '__doc__': 'Automatically created module for IPython interactive environment', '__package__': None, '__loader__': None, '__spec__': None, '__builtin__': , '__builtins__': , '_ih': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], '_oh': {}, '_dh': [PosixPath('/Users/datnguyenthanh/Marc/effectful')], 'In': ['', 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))'], 'Out': {}, 'get_ipython': >, 'exit': , 'quit': , 'open': , '_': \"In the sea, a fish named Four, \\nSwam circles, but wanted more. \\nHe found a big dish, \\nOf delightful fish, \\nNow he's the happiest on the ocean floor!\", '__': '', '___': '', '__vsc_ipynb_file__': '/Users/datnguyenthanh/Marc/effectful/docs/source/llm.ipynb', '_i': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', '_ii': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', '_iii': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', '_i1': 'import dataclasses\\nimport functools\\nimport inspect\\nimport logging\\nimport sys\\nfrom collections.abc import Callable\\n\\nfrom effectful.handlers.llm import Template\\nfrom effectful.handlers.llm.providers import (\\n CacheLLMRequestHandler,\\n LiteLLMProvider,\\n LLMLoggingHandler,\\n RetryLLMHandler,\\n completion,\\n tool_call,\\n)\\nfrom effectful.handlers.llm.synthesis import ProgramSynthesis\\nfrom effectful.ops.semantics import NotHandled, fwd, handler\\nfrom effectful.ops.syntax import defop\\n\\nprovider = LiteLLMProvider()', 'dataclasses': , 'functools': , 'inspect': , 'logging': , 'sys': , 'Callable': , 'Template': , 'CacheLLMRequestHandler': , 'LiteLLMProvider': , 'LLMLoggingHandler': , 'RetryLLMHandler': , 'completion': Operation(completion, (model: str, messages: List = [], timeout: Union[float, str, openai.Timeout, NoneType] = None, temperature: Optional[float] = None, top_p: Optional[float] = None, n: Optional[int] = None, stream: Optional[bool] = None, stream_options: Optional[dict] = None, stop=None, max_completion_tokens: Optional[int] = None, max_tokens: Optional[int] = None, modalities: Optional[List[Literal['text', 'audio']]] = None, prediction: Optional[openai.types.chat.chat_completion_prediction_content_param.ChatCompletionPredictionContentParam] = None, audio: Optional[openai.types.chat.chat_completion_audio_param.ChatCompletionAudioParam] = None, presence_penalty: Optional[float] = None, frequency_penalty: Optional[float] = None, logit_bias: Optional[dict] = None, user: Optional[str] = None, reasoning_effort: Optional[Literal['none', 'minimal', 'low', 'medium', 'high', 'default']] = None, verbosity: Optional[Literal['low', 'medium', 'high']] = None, response_format: Union[dict, Type[pydantic.main.BaseModel], NoneType] = None, seed: Optional[int] = None, tools: Optional[List] = None, tool_choice: Union[str, dict, NoneType] = None, logprobs: Optional[bool] = None, top_logprobs: Optional[int] = None, parallel_tool_calls: Optional[bool] = None, web_search_options: Optional[litellm.types.llms.openai.OpenAIWebSearchOptions] = None, deployment_id=None, extra_headers: Optional[dict] = None, safety_identifier: Optional[str] = None, service_tier: Optional[str] = None, functions: Optional[List] = None, function_call: Optional[str] = None, base_url: Optional[str] = None, api_version: Optional[str] = None, api_key: Optional[str] = None, model_list: Optional[list] = None, thinking: Optional[litellm.types.llms.anthropic.AnthropicThinkingParam] = None, shared_session: Optional[ForwardRef('ClientSession')] = None, **kwargs) -> Union[litellm.types.utils.ModelResponse, litellm.litellm_core_utils.streaming_handler.CustomStreamWrapper]), 'tool_call': Operation(tool_call, (template: effectful.handlers.llm.Template, tool: Union[effectful.ops.types.Operation[..., T], effectful.handlers.llm.Template[..., T]], *args, **kwargs) -> T), 'ProgramSynthesis': , 'NotHandled': , 'fwd': Operation(fwd, (*args, **kwargs) -> Any), 'handler': , 'defop': , 'provider': , '_i2': '@Template.define\\ndef limerick(theme: str) -> str:\\n \"\"\"Write a limerick on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled', 'limerick': Template(__prompt_template__='Write a limerick on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='limerick'), '_i3': 'with handler(provider):\\n print(limerick(\"fish\"))\\n print(\"-\" * 40)\\n print(limerick(\"fish\"))', '_i4': '@functools.cache\\n@Template.define\\ndef haiku(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef haiku_no_cache(theme: str) -> str:\\n \"\"\"Write a haiku on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nprint()\\nwith handler(provider):\\n print(haiku(\"fish\"))\\n print(\"-\" * 40)\\n print(haiku(\"fish\"))\\n\\nprint()\\ncache_handler1 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler1):\\n print(haiku_no_cache(\"fish2\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish2\"))\\n\\nprint()\\ncache_handler2 = CacheLLMRequestHandler()\\nwith handler(provider), handler(cache_handler2):\\n print(haiku_no_cache(\"fish3\"))\\n print(\"-\" * 40)\\n print(haiku_no_cache(\"fish3\"))', 'haiku': , 'haiku_no_cache': Template(__prompt_template__='Write a haiku on the theme of {theme}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='haiku_no_cache'), 'cache_handler1': , 'cache_handler2': , '_i5': '@Template.define\\ndef primes(first_digit: int) -> int:\\n \"\"\"Give a prime number with {first_digit} as the first digit. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider):\\n assert type(primes(6)) is int', 'primes': Template(__prompt_template__='Give a prime number with {first_digit} as the first digit. Do not use any tools.', __signature__= int>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='primes'), '_i6': '@Template.define\\ndef count_char(char: str) -> Callable[[str], int]:\\n \"\"\"Write a function which takes a string and counts the occurrances of \\'{char}\\'. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\nwith handler(provider), handler(ProgramSynthesis()):\\n count_a = count_char(\"a\")\\n assert callable(count_a)\\n assert count_a(\"banana\") == 3\\n assert count_a(\"cherry\") == 0\\n # Print the source code of the generated function\\n print(inspect.getsource(count_a))', 'count_char': Template(__prompt_template__=\"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", __signature__= collections.abc.Callable[[str], int]>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='count_char'), 'count_a': , '_i7': '@defop\\ndef cities() -> list[str]:\\n return [\"Chicago\", \"New York\", \"Barcelona\"]\\n\\n\\n@defop\\ndef weather(city: str) -> str:\\n status = {\"Chicago\": \"cold\", \"New York\": \"wet\", \"Barcelona\": \"sunny\"}\\n return status.get(city, \"unknown\")\\n\\n\\n@Template.define # cities and weather auto-captured from lexical scope\\ndef vacation() -> str:\\n \"\"\"Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.\"\"\"\\n raise NotHandled\\n\\n\\ndef log_tool_call(_, tool, *args, **kwargs):\\n result = fwd()\\n print(f\"Tool call: {tool}(*{args}, **{kwargs}) -> {result}\")\\n return result\\n\\n\\nwith handler(provider), handler({tool_call: log_tool_call}):\\n print(vacation())', 'cities': Operation(cities, () -> list[str]), 'weather': Operation(weather, (city: str) -> str), 'vacation': Template(__prompt_template__='Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='vacation'), 'log_tool_call': , '_i8': '@dataclasses.dataclass\\nclass KnockKnockJoke:\\n whos_there: str\\n punchline: str\\n\\n\\n@Template.define\\ndef write_joke(theme: str) -> KnockKnockJoke:\\n \"\"\"Write a knock-knock joke on the theme of {theme}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef rate_joke(joke: KnockKnockJoke) -> bool:\\n \"\"\"Decide if {joke} is funny or not. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\ndef do_comedy():\\n joke = write_joke(\"lizards\")\\n print(\"> You are onstage at a comedy club. You tell the following joke:\")\\n print(\\n f\"Knock knock.\\\\nWho\\'s there?\\\\n{joke.whos_there}.\\\\n{joke.whos_there} who?\\\\n{joke.punchline}\"\\n )\\n if rate_joke(joke):\\n print(\"> The crowd laughs politely.\")\\n else:\\n print(\"> The crowd stares in stony silence.\")\\n\\n\\nwith handler(provider):\\n do_comedy()', 'KnockKnockJoke': , 'write_joke': Template(__prompt_template__='Write a knock-knock joke on the theme of {theme}. Do not use any tools.', __signature__= __main__.KnockKnockJoke>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='write_joke'), 'rate_joke': Template(__prompt_template__='Decide if {joke} is funny or not. Do not use any tools.', __signature__= bool>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='rate_joke'), 'do_comedy': , '_i9': 'def log_llm(*args, **kwargs):\\n result = fwd()\\n print(\"Request fired: \", args, kwargs, result)\\n return result\\n\\n\\n# Avoid cache\\ntry:\\n haiku.cache_clear()\\nexcept Exception:\\n pass\\n\\n# Put completion handler innermost so it has highest precedence during the call\\nwith handler(provider), handler({completion: log_llm}):\\n _ = haiku(\"fish2\")\\n _ = limerick(\"fish\") # or use haiku(\"fish-2\") to avoid cache', 'log_llm': , '_i10': '# 1. Create a logger\\nlogger = logging.getLogger(\"effectful.llm\")\\nlogger.setLevel(logging.INFO)\\nlog_handler = logging.StreamHandler(sys.stdout)\\nlog_handler.setFormatter(logging.Formatter(\"%(levelname)s %(payload)s\"))\\nlogger.addHandler(log_handler)\\n# 2. Pass it to the handler\\nllm_logger = LLMLoggingHandler(logger=logger) # can also be LLMLoggingHandler()\\n\\n# Avoid cache for demonstration\\ntry:\\n haiku.cache_clear()\\n limerick.cache_clear()\\nexcept Exception:\\n pass\\n\\nwith handler(provider), handler(llm_logger):\\n _ = haiku(\"fish3\")\\n _ = limerick(\"fish4\")', 'logger': , 'log_handler': , 'llm_logger': , '_i11': '# Sub-templates for different story styles\\n@Template.define\\ndef story_with_moral(topic: str) -> str:\\n \"\"\"Write a short story about {topic} and end with a moral lesson. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n@Template.define\\ndef story_funny(topic: str) -> str:\\n \"\"\"Write a funny, humorous story about {topic}. Do not use any tools.\"\"\"\\n raise NotHandled\\n\\n\\n# Main orchestrator template - has access to sub-templates\\n@Template.define\\ndef write_story(topic: str, style: str) -> str:\\n \"\"\"Write a story about {topic} in the style: {style}.\\n Available styles: \\'moral\\' for a story with a lesson, \\'funny\\' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"\"\"\\n raise NotHandled\\n\\n\\n# Verify sub-templates are captured in write_story\\'s lexical context\\nassert story_with_moral in write_story.tools\\nassert story_funny in write_story.tools\\nprint(\"Sub-templates available to write_story:\", list(write_story.tools))\\n\\nwith handler(provider), handler(llm_logger):\\n print(\"=== Story with moral ===\")\\n print(write_story(\"a curious cat\", \"moral\"))\\n print()\\n print(\"=== Funny story ===\")\\n print(write_story(\"a curious cat\", \"funny\"))', 'story_with_moral': Template(__prompt_template__='Write a short story about {topic} and end with a moral lesson. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_with_moral'), 'story_funny': Template(__prompt_template__='Write a funny, humorous story about {topic}. Do not use any tools.', __signature__= str>, __context__=LexicalContext(mappingproxy({...}), mappingproxy({...})), __name__='story_funny'), 'write_story': ...})), __name__='write_story')]\n", + "=== Story with moral ===\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': \"Write a story about a curious cat in the style: moral.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEDqkyey8hGyUP8N4pApvKotzCg', created=1765910305, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content=None, role='assistant', tool_calls=[ChatCompletionMessageToolCall(function=Function(arguments='{\"topic\":\"a curious cat\"}', name='story_with_moral'), id='call_VSAs7DmCe4maSEmL5vuI55Qt', type='function')], function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=18, prompt_tokens=560, total_tokens=578, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Write a short story about a curious cat and end with a moral lesson. Do not use any tools.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEDpLxPDuwMHW8vcASn4N8aWY0x', created=1765910305, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content=\"Once upon a time in a quaint little village, there lived a cat named Whiskers. Whiskers was no ordinary cat; he was curious beyond measure. Every nook and cranny of the village had been explored by his nimble paws, and every villager knew of his adventurous spirit.\\n\\nOne day, as Whiskers roamed the cobblestone streets, a glint of something shiny caught his eye. Nestled between two large stones at the base of a dilapidated wall was a curious object — a small, silver key. Whiskers, being the inquisitive feline that he was, decided to investigate further.\\n\\nHe carefully pawed the key from its hiding spot and began to search for what it might unlock. Whiskers explored every door, gate, and chest he could find, but none yielded to the mysterious key. Just as he was about to give up, he noticed an old, overgrown path leading to the back of the village where a forgotten garden lay in ruins.\\n\\nWith the silver key dangling from his mouth, Whiskers bounded down the path. At the end, hidden behind a curtain of ivy, stood an iron gate, rusted and long unused. With a determined leap, Whiskers stretched and placed the key into the rusty lock. To his surprise, the lock clicked open, and the gate creaked ajar.\\n\\nBeyond the gate was an enchanting garden, overgrown but full of beauty. Whiskers marveled at the vibrant flowers and the gentle bubbling brook that meandered through the garden. Birds chirped a melodious tune, and butterflies danced in the air. It was a secret paradise, long forgotten by the villagers.\\n\\nWhiskers spent hours exploring the garden, every corner holding another surprise. As the sun began to set, casting a golden hue over the garden, Whiskers realized it was time to return to the village. He knew he had discovered something special, something that even the humans had forgotten.\\n\\nThe next day, he led the villagers to the garden, where they were astonished by its hidden beauty. The villagers decided to restore the garden, turning it into a communal space for all to enjoy. Thanks to Whiskers' curiosity, the village now had a place of wonder and relaxation.\\n\\nThe moral of the story is: Curiosity, when pursued mindfully, can lead to wonderful discoveries and opportunities that enrich both your life and those of others.\", role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=495, prompt_tokens=528, total_tokens=1023, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'tool': 'story_with_moral', 'args': (), 'kwargs': {'topic': 'a curious cat'}}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': \"Write a story about a curious cat in the style: moral.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"}], 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{\"topic\":\"a curious cat\"}', 'name': 'story_with_moral'}, 'id': 'call_VSAs7DmCe4maSEmL5vuI55Qt', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_VSAs7DmCe4maSEmL5vuI55Qt', 'name': 'story_with_moral', 'content': [{'type': 'text', 'text': \"Once upon a time in a quaint little village, there lived a cat named Whiskers. Whiskers was no ordinary cat; he was curious beyond measure. Every nook and cranny of the village had been explored by his nimble paws, and every villager knew of his adventurous spirit.\\n\\nOne day, as Whiskers roamed the cobblestone streets, a glint of something shiny caught his eye. Nestled between two large stones at the base of a dilapidated wall was a curious object — a small, silver key. Whiskers, being the inquisitive feline that he was, decided to investigate further.\\n\\nHe carefully pawed the key from its hiding spot and began to search for what it might unlock. Whiskers explored every door, gate, and chest he could find, but none yielded to the mysterious key. Just as he was about to give up, he noticed an old, overgrown path leading to the back of the village where a forgotten garden lay in ruins.\\n\\nWith the silver key dangling from his mouth, Whiskers bounded down the path. At the end, hidden behind a curtain of ivy, stood an iron gate, rusted and long unused. With a determined leap, Whiskers stretched and placed the key into the rusty lock. To his surprise, the lock clicked open, and the gate creaked ajar.\\n\\nBeyond the gate was an enchanting garden, overgrown but full of beauty. Whiskers marveled at the vibrant flowers and the gentle bubbling brook that meandered through the garden. Birds chirped a melodious tune, and butterflies danced in the air. It was a secret paradise, long forgotten by the villagers.\\n\\nWhiskers spent hours exploring the garden, every corner holding another surprise. As the sun began to set, casting a golden hue over the garden, Whiskers realized it was time to return to the village. He knew he had discovered something special, something that even the humans had forgotten.\\n\\nThe next day, he led the villagers to the garden, where they were astonished by its hidden beauty. The villagers decided to restore the garden, turning it into a communal space for all to enjoy. Thanks to Whiskers' curiosity, the village now had a place of wonder and relaxation.\\n\\nThe moral of the story is: Curiosity, when pursued mindfully, can lead to wonderful discoveries and opportunities that enrich both your life and those of others.\"}]}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEOPrpbgOHb7HX300i0JtULBTfY', created=1765910316, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content=\"Once upon a time in a quaint little village, there lived a cat named Whiskers. Whiskers was no ordinary cat; he was curious beyond measure. Every nook and cranny of the village had been explored by his nimble paws, and every villager knew of his adventurous spirit.\\n\\nOne day, as Whiskers roamed the cobblestone streets, a glint of something shiny caught his eye. Nestled between two large stones at the base of a dilapidated wall was a curious object — a small, silver key. Whiskers, being the inquisitive feline that he was, decided to investigate further.\\n\\nHe carefully pawed the key from its hiding spot and began to search for what it might unlock. Whiskers explored every door, gate, and chest he could find, but none yielded to the mysterious key. Just as he was about to give up, he noticed an old, overgrown path leading to the back of the village where a forgotten garden lay in ruins.\\n\\nWith the silver key dangling from his mouth, Whiskers bounded down the path. At the end, hidden behind a curtain of ivy, stood an iron gate, rusted and long unused. With a determined leap, Whiskers stretched and placed the key into the rusty lock. To his surprise, the lock clicked open, and the gate creaked ajar.\\n\\nBeyond the gate was an enchanting garden, overgrown but full of beauty. Whiskers marveled at the vibrant flowers and the gentle bubbling brook that meandered through the garden. Birds chirped a melodious tune, and butterflies danced in the air. It was a secret paradise, long forgotten by the villagers.\\n\\nWhiskers spent hours exploring the garden, every corner holding another surprise. As the sun began to set, casting a golden hue over the garden, Whiskers realized it was time to return to the village. He knew he had discovered something special, something that even the humans had forgotten.\\n\\nThe next day, he led the villagers to the garden, where they were astonished by its hidden beauty. The villagers decided to restore the garden, turning it into a communal space for all to enjoy. Thanks to Whiskers' curiosity, the village now had a place of wonder and relaxation.\\n\\nThe moral of the story is: Curiosity, when pursued mindfully, can lead to wonderful discoveries and opportunities that enrich both your life and those of others.\", role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=495, prompt_tokens=1082, total_tokens=1577, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "Once upon a time in a quaint little village, there lived a cat named Whiskers. Whiskers was no ordinary cat; he was curious beyond measure. Every nook and cranny of the village had been explored by his nimble paws, and every villager knew of his adventurous spirit.\n", + "\n", + "One day, as Whiskers roamed the cobblestone streets, a glint of something shiny caught his eye. Nestled between two large stones at the base of a dilapidated wall was a curious object — a small, silver key. Whiskers, being the inquisitive feline that he was, decided to investigate further.\n", + "\n", + "He carefully pawed the key from its hiding spot and began to search for what it might unlock. Whiskers explored every door, gate, and chest he could find, but none yielded to the mysterious key. Just as he was about to give up, he noticed an old, overgrown path leading to the back of the village where a forgotten garden lay in ruins.\n", + "\n", + "With the silver key dangling from his mouth, Whiskers bounded down the path. At the end, hidden behind a curtain of ivy, stood an iron gate, rusted and long unused. With a determined leap, Whiskers stretched and placed the key into the rusty lock. To his surprise, the lock clicked open, and the gate creaked ajar.\n", + "\n", + "Beyond the gate was an enchanting garden, overgrown but full of beauty. Whiskers marveled at the vibrant flowers and the gentle bubbling brook that meandered through the garden. Birds chirped a melodious tune, and butterflies danced in the air. It was a secret paradise, long forgotten by the villagers.\n", + "\n", + "Whiskers spent hours exploring the garden, every corner holding another surprise. As the sun began to set, casting a golden hue over the garden, Whiskers realized it was time to return to the village. He knew he had discovered something special, something that even the humans had forgotten.\n", + "\n", + "The next day, he led the villagers to the garden, where they were astonished by its hidden beauty. The villagers decided to restore the garden, turning it into a communal space for all to enjoy. Thanks to Whiskers' curiosity, the village now had a place of wonder and relaxation.\n", + "\n", + "The moral of the story is: Curiosity, when pursued mindfully, can lead to wonderful discoveries and opportunities that enrich both your life and those of others.\n", + "\n", + "=== Funny story ===\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': \"Write a story about a curious cat in the style: funny.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUESoVAhiOnofpdjEJ9kfxosCVCr', created=1765910320, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content=None, role='assistant', tool_calls=[ChatCompletionMessageToolCall(function=Function(arguments='{\"topic\":\"a curious cat\"}', name='story_funny'), id='call_y9nl1iqWc1CJwphS7L1dN4H5', type='function')], function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=17, prompt_tokens=560, total_tokens=577, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Write a funny, humorous story about a curious cat. Do not use any tools.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUESKUUgAC77rItOvG1Sh227kCId', created=1765910320, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content='Once upon a time in the quaint little village of Whiskerville, lived a curious cat named Oliver. Oliver wasn\\'t just any ordinary cat; he was a feline with an insatiable appetite for adventure and perhaps, just as importantly, for snacks.\\n\\nOne sunny morning, as the villagers went about their daily routines, Oliver noticed something peculiar. A new aroma wafted through the air—a delightful mix of fish and chicken, with just a hint of something exotic. Perplexed and intrigued, Oliver decided it was his duty to investigate. After all, curiosity didn\\'t just kill the cat; it fed it delicious snacks.\\n\\nHis nose led him to the local bakery, which had recently started experimenting with \"gourmet pet pastries.\" As Oliver tiptoed inside, unnoticed by the busy baker, he spotted an array of treats on a shelf. The pièce de résistance was a cake that read \"Happy Birthday Max\" in bold, colorful icing.\\n\\nOliver, assuming this \"Max\" character could afford to miss one slice (or perhaps the entire cake), climbed onto the shelf. With expert precision, he nibbled around the edges, savoring each bite like the connoisseur he was. In his mind, he imagined the villagers applauding his refined palate and heralding him as \"Oliver, the Culinary Cat.\"\\n\\nJust then, the baker returned and realized what had happened. \"Oh no! Max\\'s birthday cake!\" she exclaimed, spotting Oliver mid-feast. Oliver, caught in the act, adopted his most innocent \"I\\'m just a cute kitty\" face, but the baker was less than impressed.\\n\\nIn a moment of inspiration—or perhaps desperation—Oliver decided to make a quick escape. He knocked over a bag of flour, creating a cloud of white, giving him just enough cover to dart out the back door and make his getaway. The baker, though exasperated, couldn\\'t help but chuckle as Oliver, now a ghostly white from the flour, trotted down the street with the last remnants of the cake still sticking to his whiskers.\\n\\nFrom that day on, Oliver earned a new nickname among the villagers: \"The Cake Bandit of Whiskerville.\" Despite the fiasco, he was more revered than ever, proving once again that even the cheekiest of cats could win hearts—and snacks—with a touch of humor and a sprinkle of charm.', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=476, prompt_tokens=524, total_tokens=1000, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'tool': 'story_funny', 'args': (), 'kwargs': {'topic': 'a curious cat'}}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': \"Write a story about a curious cat in the style: funny.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\"}], 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{\"topic\":\"a curious cat\"}', 'name': 'story_funny'}, 'id': 'call_y9nl1iqWc1CJwphS7L1dN4H5', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_y9nl1iqWc1CJwphS7L1dN4H5', 'name': 'story_funny', 'content': [{'type': 'text', 'text': 'Once upon a time in the quaint little village of Whiskerville, lived a curious cat named Oliver. Oliver wasn\\'t just any ordinary cat; he was a feline with an insatiable appetite for adventure and perhaps, just as importantly, for snacks.\\n\\nOne sunny morning, as the villagers went about their daily routines, Oliver noticed something peculiar. A new aroma wafted through the air—a delightful mix of fish and chicken, with just a hint of something exotic. Perplexed and intrigued, Oliver decided it was his duty to investigate. After all, curiosity didn\\'t just kill the cat; it fed it delicious snacks.\\n\\nHis nose led him to the local bakery, which had recently started experimenting with \"gourmet pet pastries.\" As Oliver tiptoed inside, unnoticed by the busy baker, he spotted an array of treats on a shelf. The pièce de résistance was a cake that read \"Happy Birthday Max\" in bold, colorful icing.\\n\\nOliver, assuming this \"Max\" character could afford to miss one slice (or perhaps the entire cake), climbed onto the shelf. With expert precision, he nibbled around the edges, savoring each bite like the connoisseur he was. In his mind, he imagined the villagers applauding his refined palate and heralding him as \"Oliver, the Culinary Cat.\"\\n\\nJust then, the baker returned and realized what had happened. \"Oh no! Max\\'s birthday cake!\" she exclaimed, spotting Oliver mid-feast. Oliver, caught in the act, adopted his most innocent \"I\\'m just a cute kitty\" face, but the baker was less than impressed.\\n\\nIn a moment of inspiration—or perhaps desperation—Oliver decided to make a quick escape. He knocked over a bag of flour, creating a cloud of white, giving him just enough cover to dart out the back door and make his getaway. The baker, though exasperated, couldn\\'t help but chuckle as Oliver, now a ghostly white from the flour, trotted down the street with the last remnants of the cake still sticking to his whiskers.\\n\\nFrom that day on, Oliver earned a new nickname among the villagers: \"The Cake Bandit of Whiskerville.\" Despite the fiasco, he was more revered than ever, proving once again that even the cheekiest of cats could win hearts—and snacks—with a touch of humor and a sprinkle of charm.'}]}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEfS0n3oGVWVXE4YCfLUqgp6ZvA', created=1765910333, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content='Once upon a time in the quaint little village of Whiskerville, lived a curious cat named Oliver. Oliver wasn\\'t just any ordinary cat; he was a feline with an insatiable appetite for adventure and perhaps, just as importantly, for snacks.\\n\\nOne sunny morning, as the villagers went about their daily routines, Oliver noticed something peculiar. A new aroma wafted through the air—a delightful mix of fish and chicken, with just a hint of something exotic. Perplexed and intrigued, Oliver decided it was his duty to investigate. After all, curiosity didn\\'t just kill the cat; it fed it delicious snacks.\\n\\nHis nose led him to the local bakery, which had recently started experimenting with \"gourmet pet pastries.\" As Oliver tiptoed inside, unnoticed by the busy baker, he spotted an array of treats on a shelf. The pièce de résistance was a cake that read \"Happy Birthday Max\" in bold, colorful icing.\\n\\nOliver, assuming this \"Max\" character could afford to miss one slice (or perhaps the entire cake), climbed onto the shelf. With expert precision, he nibbled around the edges, savoring each bite like the connoisseur he was. In his mind, he imagined the villagers applauding his refined palate and heralding him as \"Oliver, the Culinary Cat.\"\\n\\nJust then, the baker returned and realized what had happened. \"Oh no! Max\\'s birthday cake!\" she exclaimed, spotting Oliver mid-feast. Oliver, caught in the act, adopted his most innocent \"I\\'m just a cute kitty\" face, but the baker was less than impressed.\\n\\nIn a moment of inspiration—or perhaps desperation—Oliver decided to make a quick escape. He knocked over a bag of flour, creating a cloud of white, giving him just enough cover to dart out the back door and make his getaway. The baker, though exasperated, couldn\\'t help but chuckle as Oliver, now a ghostly white from the flour, trotted down the street with the last remnants of the cake still sticking to his whiskers.\\n\\nFrom that day on, Oliver earned a new nickname among the villagers: \"The Cake Bandit of Whiskerville.\" Despite the fiasco, he was more revered than ever, proving once again that even the cheekiest of cats could win hearts—and snacks—with a touch of humor and a sprinkle of charm.', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=476, prompt_tokens=1061, total_tokens=1537, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "Once upon a time in the quaint little village of Whiskerville, lived a curious cat named Oliver. Oliver wasn't just any ordinary cat; he was a feline with an insatiable appetite for adventure and perhaps, just as importantly, for snacks.\n", + "\n", + "One sunny morning, as the villagers went about their daily routines, Oliver noticed something peculiar. A new aroma wafted through the air—a delightful mix of fish and chicken, with just a hint of something exotic. Perplexed and intrigued, Oliver decided it was his duty to investigate. After all, curiosity didn't just kill the cat; it fed it delicious snacks.\n", + "\n", + "His nose led him to the local bakery, which had recently started experimenting with \"gourmet pet pastries.\" As Oliver tiptoed inside, unnoticed by the busy baker, he spotted an array of treats on a shelf. The pièce de résistance was a cake that read \"Happy Birthday Max\" in bold, colorful icing.\n", + "\n", + "Oliver, assuming this \"Max\" character could afford to miss one slice (or perhaps the entire cake), climbed onto the shelf. With expert precision, he nibbled around the edges, savoring each bite like the connoisseur he was. In his mind, he imagined the villagers applauding his refined palate and heralding him as \"Oliver, the Culinary Cat.\"\n", + "\n", + "Just then, the baker returned and realized what had happened. \"Oh no! Max's birthday cake!\" she exclaimed, spotting Oliver mid-feast. Oliver, caught in the act, adopted his most innocent \"I'm just a cute kitty\" face, but the baker was less than impressed.\n", + "\n", + "In a moment of inspiration—or perhaps desperation—Oliver decided to make a quick escape. He knocked over a bag of flour, creating a cloud of white, giving him just enough cover to dart out the back door and make his getaway. The baker, though exasperated, couldn't help but chuckle as Oliver, now a ghostly white from the flour, trotted down the street with the last remnants of the cake still sticking to his whiskers.\n", + "\n", + "From that day on, Oliver earned a new nickname among the villagers: \"The Cake Bandit of Whiskerville.\" Despite the fiasco, he was more revered than ever, proving once again that even the cheekiest of cats could win hearts—and snacks—with a touch of humor and a sprinkle of charm.\n" +======= "Sub-templates available to write_story: ['vacation', 'count_char', 'primes', 'weather', 'story_with_moral', 'haiku_no_cache', 'write_joke', 'story_funny', 'unstable_service', 'rate_joke', 'write_story', 'fetch_data', 'limerick', 'give_rating_for_movie', 'cities']\n", "=== Story with moral ===\n", "> Write a story about a curious cat in the style: moral.\n", @@ -570,6 +771,7 @@ "By the end of the day, Whiskers was returned home by a kind market lady who recognized him from the baker's stories. As she gently placed him down at the village square, he gave a nonchalant flick of his tail and walked off, leaving behind a trail of breadcrumbs and a story that the villagers would tell for years to come.\n", "\n", "And so, dear reader, the moral of this tale is simple: Curiosity may take you far and wide, but please remember where home is—because you'll definitely want to come back after an adventure-snack or two!\n" +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 ] } ], @@ -631,7 +833,11 @@ }, { "cell_type": "code", +<<<<<<< HEAD + "execution_count": 12, +======= "execution_count": 44, +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 "id": "4334d07a", "metadata": {}, "outputs": [ @@ -639,6 +845,41 @@ "name": "stdout", "output_type": "stream", "text": [ +<<<<<<< HEAD + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEmIONHwhLsMjK9u9cpJsqWBbgm', created=1765910340, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content=None, role='assistant', tool_calls=[ChatCompletionMessageToolCall(function=Function(arguments='{}', name='fetch_data'), id='call_nxj3sHvWKBpDCcXfbgDLocNc', type='function')], function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=10, prompt_tokens=553, total_tokens=563, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEmLBPSZv4j9Zi1is0ah7lGjyph', created=1765910340, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content=None, role='assistant', tool_calls=[ChatCompletionMessageToolCall(function=Function(arguments='{}', name='fetch_data'), id='call_BjcrjUeLyEvFzdBHZBbNhpAK', type='function')], function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=10, prompt_tokens=553, total_tokens=563, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEnub7d0H00fi77NHiEGLSQ1QdR', created=1765910341, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content=None, role='assistant', tool_calls=[ChatCompletionMessageToolCall(function=Function(arguments='{}', name='fetch_data'), id='call_3dSgdzKP3RpqtIEZKIeGHbaR', type='function')], function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=10, prompt_tokens=553, total_tokens=563, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEnKN3i31lLg13CFtZfZq8EOJOe', created=1765910341, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content=None, role='assistant', tool_calls=[ChatCompletionMessageToolCall(function=Function(arguments='{}', name='fetch_data'), id='call_zh4sXEge4m5oKeys7uPLMH8S', type='function')], function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=10, prompt_tokens=553, total_tokens=563, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEoU6nXlyGn7ibLzyZcgdNwLc1v', created=1765910342, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content=None, role='assistant', tool_calls=[ChatCompletionMessageToolCall(function=Function(arguments='{}', name='fetch_data'), id='call_jo5PH2nFHCUkhPZ5bT7u12bR', type='function')], function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=10, prompt_tokens=553, total_tokens=563, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEoeeRn9IkGRg6q51BgDbiIoeeF', created=1765910342, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content=None, role='assistant', tool_calls=[ChatCompletionMessageToolCall(function=Function(arguments='{}', name='fetch_data'), id='call_ta6xQ0Xyor6swXp9nU0NB4OR', type='function')], function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=10, prompt_tokens=553, total_tokens=563, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEpij6TnFbVNCS2dZp8DP9sW5ZQ', created=1765910343, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content=None, role='assistant', tool_calls=[ChatCompletionMessageToolCall(function=Function(arguments='{}', name='fetch_data'), id='call_3gdzkbFYZoU0t1mFRwbN8a0L', type='function')], function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=10, prompt_tokens=553, total_tokens=563, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEqdb1YjTu1hi1mtxgpEmWFy3dc', created=1765910344, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content=None, role='assistant', tool_calls=[ChatCompletionMessageToolCall(function=Function(arguments='{}', name='fetch_data'), id='call_qvlLtrZwpJYooqZSK4aZanTo', type='function')], function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=10, prompt_tokens=553, total_tokens=563, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUErM2EeRDop0LmxffT1h9FQVFaC', created=1765910345, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content=None, role='assistant', tool_calls=[ChatCompletionMessageToolCall(function=Function(arguments='{}', name='fetch_data'), id='call_vum27pk9btnhr9Mih0R13mbS', type='function')], function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=10, prompt_tokens=553, total_tokens=563, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUErFocEMQZD38QineLbN9jwfmBW', created=1765910345, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content=None, role='assistant', tool_calls=[ChatCompletionMessageToolCall(function=Function(arguments='{}', name='unstable_service'), id='call_KmH8evW9BwoEJ65sRNOTiijH', type='function')], function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=11, prompt_tokens=553, total_tokens=564, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{}', 'name': 'unstable_service'}, 'id': 'call_KmH8evW9BwoEJ65sRNOTiijH', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_KmH8evW9BwoEJ65sRNOTiijH', 'name': 'unstable_service', 'content': \"{'status': 'failure', 'exception': 'Service unavailable! Attempt 1/3. Please retry.'}\"}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEsXalp23viabH6Ypx9igTyB0vE', created=1765910346, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content=None, role='assistant', tool_calls=[ChatCompletionMessageToolCall(function=Function(arguments='{}', name='unstable_service'), id='call_KfYFUQBLLB0sWfl74HMUBivj', type='function')], function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=11, prompt_tokens=596, total_tokens=607, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{}', 'name': 'unstable_service'}, 'id': 'call_KmH8evW9BwoEJ65sRNOTiijH', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_KmH8evW9BwoEJ65sRNOTiijH', 'name': 'unstable_service', 'content': \"{'status': 'failure', 'exception': 'Service unavailable! Attempt 1/3. Please retry.'}\"}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{}', 'name': 'unstable_service'}, 'id': 'call_KfYFUQBLLB0sWfl74HMUBivj', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_KfYFUQBLLB0sWfl74HMUBivj', 'name': 'unstable_service', 'content': \"{'status': 'failure', 'exception': 'Service unavailable! Attempt 2/3. Please retry.'}\"}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEsefSAxCp4UN3CQHL4sW2Nt5Kx', created=1765910346, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='tool_calls', index=0, message=Message(content=None, role='assistant', tool_calls=[ChatCompletionMessageToolCall(function=Function(arguments='{}', name='unstable_service'), id='call_E4INtSQ08RbjluqMPNHtueH9', type='function')], function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=11, prompt_tokens=639, total_tokens=650, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'tool': 'unstable_service', 'args': (), 'kwargs': {}}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{}', 'name': 'unstable_service'}, 'id': 'call_KmH8evW9BwoEJ65sRNOTiijH', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_KmH8evW9BwoEJ65sRNOTiijH', 'name': 'unstable_service', 'content': \"{'status': 'failure', 'exception': 'Service unavailable! Attempt 1/3. Please retry.'}\"}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{}', 'name': 'unstable_service'}, 'id': 'call_KfYFUQBLLB0sWfl74HMUBivj', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_KfYFUQBLLB0sWfl74HMUBivj', 'name': 'unstable_service', 'content': \"{'status': 'failure', 'exception': 'Service unavailable! Attempt 2/3. Please retry.'}\"}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{}', 'name': 'unstable_service'}, 'id': 'call_E4INtSQ08RbjluqMPNHtueH9', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_E4INtSQ08RbjluqMPNHtueH9', 'name': 'unstable_service', 'content': [{'type': 'text', 'text': \"{ 'status': 'ok', 'data': [1, 2, 3] }\"}]}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEte02Ozt3mvzBr7xwcTPQcfWo8', created=1765910347, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content='Successfully fetched data: [1, 2, 3]', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=14, prompt_tokens=679, total_tokens=693, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'tool': 'fetch_data', 'args': (), 'kwargs': {}}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{}', 'name': 'fetch_data'}, 'id': 'call_vum27pk9btnhr9Mih0R13mbS', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_vum27pk9btnhr9Mih0R13mbS', 'name': 'fetch_data', 'content': [{'type': 'text', 'text': 'Successfully fetched data: [1, 2, 3]'}]}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEtyzAH1YfRKGgjks5iTqxXJwd2', created=1765910347, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content='I successfully fetched the data: \\\\([1, 2, 3]\\\\).', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=18, prompt_tokens=584, total_tokens=602, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'tool': 'fetch_data', 'args': (), 'kwargs': {}}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{}', 'name': 'fetch_data'}, 'id': 'call_qvlLtrZwpJYooqZSK4aZanTo', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_qvlLtrZwpJYooqZSK4aZanTo', 'name': 'fetch_data', 'content': [{'type': 'text', 'text': 'I successfully fetched the data: \\\\([1, 2, 3]\\\\).'}]}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEut9xAQEbMXYYTOiQohhkBfMbO', created=1765910348, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e819e3438b', choices=[Choices(finish_reason='stop', index=0, message=Message(content='I successfully fetched the data: \\\\([1, 2, 3]\\\\).', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=18, prompt_tokens=588, total_tokens=606, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'tool': 'fetch_data', 'args': (), 'kwargs': {}}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{}', 'name': 'fetch_data'}, 'id': 'call_3gdzkbFYZoU0t1mFRwbN8a0L', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_3gdzkbFYZoU0t1mFRwbN8a0L', 'name': 'fetch_data', 'content': [{'type': 'text', 'text': 'I successfully fetched the data: \\\\([1, 2, 3]\\\\).'}]}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEv0gJ4TYYParxk5wTbOIWYs137', created=1765910349, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content='I successfully fetched the data: \\\\([1, 2, 3]\\\\).', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=18, prompt_tokens=588, total_tokens=606, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'tool': 'fetch_data', 'args': (), 'kwargs': {}}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{}', 'name': 'fetch_data'}, 'id': 'call_ta6xQ0Xyor6swXp9nU0NB4OR', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_ta6xQ0Xyor6swXp9nU0NB4OR', 'name': 'fetch_data', 'content': [{'type': 'text', 'text': 'I successfully fetched the data: \\\\([1, 2, 3]\\\\).'}]}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEvhnjGnCv0QKuYsiG86e4l3PJk', created=1765910349, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content='I successfully fetched the data: \\\\([1, 2, 3]\\\\).', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=18, prompt_tokens=588, total_tokens=606, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'tool': 'fetch_data', 'args': (), 'kwargs': {}}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{}', 'name': 'fetch_data'}, 'id': 'call_jo5PH2nFHCUkhPZ5bT7u12bR', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_jo5PH2nFHCUkhPZ5bT7u12bR', 'name': 'fetch_data', 'content': [{'type': 'text', 'text': 'I successfully fetched the data: \\\\([1, 2, 3]\\\\).'}]}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEwaQPwBxZP3HRfZLhObtpWoV7o', created=1765910350, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content='I successfully fetched the data: \\\\([1, 2, 3]\\\\).', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=18, prompt_tokens=588, total_tokens=606, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'tool': 'fetch_data', 'args': (), 'kwargs': {}}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{}', 'name': 'fetch_data'}, 'id': 'call_zh4sXEge4m5oKeys7uPLMH8S', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_zh4sXEge4m5oKeys7uPLMH8S', 'name': 'fetch_data', 'content': [{'type': 'text', 'text': 'I successfully fetched the data: \\\\([1, 2, 3]\\\\).'}]}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUExvTpaTUSQyUbDgGJouRpGW2JK', created=1765910351, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content='I successfully fetched the data: \\\\([1, 2, 3]\\\\).', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=18, prompt_tokens=588, total_tokens=606, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'tool': 'fetch_data', 'args': (), 'kwargs': {}}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{}', 'name': 'fetch_data'}, 'id': 'call_3dSgdzKP3RpqtIEZKIeGHbaR', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_3dSgdzKP3RpqtIEZKIeGHbaR', 'name': 'fetch_data', 'content': [{'type': 'text', 'text': 'I successfully fetched the data: \\\\([1, 2, 3]\\\\).'}]}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUExXiP6j9PfzMFM1KYP29Ao7bh7', created=1765910351, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content='I successfully fetched the data: \\\\([1, 2, 3]\\\\).', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=18, prompt_tokens=588, total_tokens=606, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'tool': 'fetch_data', 'args': (), 'kwargs': {}}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{}', 'name': 'fetch_data'}, 'id': 'call_BjcrjUeLyEvFzdBHZBbNhpAK', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_BjcrjUeLyEvFzdBHZBbNhpAK', 'name': 'fetch_data', 'content': [{'type': 'text', 'text': 'I successfully fetched the data: \\\\([1, 2, 3]\\\\).'}]}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEyNJL6tqPyn6gGsDJtcVbc8Vg8', created=1765910352, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content='I successfully fetched the data: \\\\([1, 2, 3]\\\\).', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=18, prompt_tokens=588, total_tokens=606, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'tool': 'fetch_data', 'args': (), 'kwargs': {}}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Use the unstable_service tool to fetch data.'}], 'role': 'user'}, {'content': None, 'role': 'assistant', 'tool_calls': [{'function': {'arguments': '{}', 'name': 'fetch_data'}, 'id': 'call_nxj3sHvWKBpDCcXfbgDLocNc', 'type': 'function'}], 'function_call': None, 'provider_specific_fields': {'refusal': None}, 'annotations': []}, {'role': 'tool', 'tool_call_id': 'call_nxj3sHvWKBpDCcXfbgDLocNc', 'name': 'fetch_data', 'content': [{'type': 'text', 'text': 'I successfully fetched the data: \\\\([1, 2, 3]\\\\).'}]}], 'response_format': None, 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEy8aws4YfPFggmpXtfpUlwVtYf', created=1765910352, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content='I successfully fetched the data: \\\\([1, 2, 3]\\\\).', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=18, prompt_tokens=588, total_tokens=606, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "Result: I successfully fetched the data: \\([1, 2, 3]\\). Retries: 3\n" +======= "> Use the unstable_service tool to fetch data. Do not use the fetch_data tool.\n", "None\n", "> Use the unstable_service tool to fetch data. Do not use the fetch_data tool.\n", @@ -648,6 +889,7 @@ "> Use the unstable_service tool to fetch data. Do not use the fetch_data tool.\n", "The data fetched from the unstable service is: [1, 2, 3].\n", "Result: The data fetched from the unstable service is: [1, 2, 3]. Retries: 3\n" +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 ] } ], @@ -692,7 +934,11 @@ }, { "cell_type": "code", +<<<<<<< HEAD + "execution_count": 13, +======= "execution_count": 45, +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 "id": "39b2b225", "metadata": {}, "outputs": [ @@ -700,6 +946,12 @@ "name": "stdout", "output_type": "stream", "text": [ +<<<<<<< HEAD + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Give a rating for Die Hard. The explanation MUST include the numeric score. Do not use any tools.'}], 'role': 'user'}], 'response_format': , 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'give_rating_for_movie', 'description': 'Give a rating for {movie_name}. The explanation MUST include the numeric score. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'movie_name': {'title': 'Movie Name', 'type': 'string'}}, 'required': ['movie_name'], 'title': 'Params', 'type': 'object'}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUEzoCPoZVdVvxcSYKXBd7GnpypB', created=1765910353, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content='{\"value\":{\"score\":9,\"explanation\":\"Die Hard is a quintessential action film that has set the standard for its genre with its thrilling storyline, charismatic lead performance by Bruce Willis, and iconic villain played by Alan Rickman. Its blend of intense action sequences and clever humor makes it a favorite among audiences, earning it a rating of 9 out of 10.\"}}', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=79, prompt_tokens=681, total_tokens=760, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "INFO {'args': (), 'kwargs': {'messages': [{'type': 'message', 'content': [{'type': 'text', 'text': 'Retry generating the following prompt: Give a rating for Die Hard. The explanation MUST include the numeric score. Do not use any tools.\\n\\nError from previous generation:\\n```\\nTraceback (most recent call last):\\n File \"/Users/datnguyenthanh/Marc/effectful/effectful/handlers/llm/providers.py\", line 347, in _retry_completion\\n return fwd(current_template, *args, **kwargs)\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n File \"/Users/datnguyenthanh/Marc/effectful/effectful/ops/types.py\", line 485, in __call__\\n return self_handler(*args, **kwargs)\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n File \"/opt/homebrew/Cellar/python@3.12/3.12.9/Frameworks/Python.framework/Versions/3.12/lib/python3.12/contextlib.py\", line 81, in inner\\n return func(*args, **kwds)\\n ^^^^^^^^^^^^^^^^^^^\\n File \"/Users/datnguyenthanh/Marc/effectful/effectful/internals/runtime.py\", line 45, in _cont_wrapper\\n return fn(*a, **k)\\n ^^^^^^^^^^^\\n File \"/Users/datnguyenthanh/Marc/effectful/effectful/internals/runtime.py\", line 56, in _cont_wrapper\\n return fn(*a, **k)\\n ^^^^^^^^^^^\\n File \"/Users/datnguyenthanh/Marc/effectful/effectful/internals/runtime.py\", line 70, in bound_body\\n return body(*a, **k)\\n ^^^^^^^^^^^^^\\n File \"/Users/datnguyenthanh/Marc/effectful/effectful/internals/runtime.py\", line 56, in _cont_wrapper\\n return fn(*a, **k)\\n ^^^^^^^^^^^\\n File \"/Users/datnguyenthanh/Marc/effectful/effectful/handlers/llm/providers.py\", line 491, in _call\\n return decode_response(template, resp)\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n File \"/Users/datnguyenthanh/Marc/effectful/effectful/handlers/llm/providers.py\", line 436, in decode_response\\n result = Result.model_validate_json(result_str)\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\n File \"/Users/datnguyenthanh/Marc/effectful/.venv/lib/python3.12/site-packages/pydantic/main.py\", line 766, in model_validate_json\\n return cls.__pydantic_validator__.validate_json(\\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\\npydantic_core._pydantic_core.ValidationError: 1 validation error for Result\\nvalue.score\\n score must be 1–5, got 9 [type=invalid_score, input_value=9, input_type=int]\\n```'}], 'role': 'user'}], 'response_format': , 'tools': [{'type': 'function', 'function': {'name': 'limerick', 'description': 'Write a limerick on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'haiku_no_cache', 'description': 'Write a haiku on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'primes', 'description': 'Give a prime number with {first_digit} as the first digit. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'first_digit': {'title': 'First Digit', 'type': 'integer'}}, 'required': ['first_digit'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'count_char', 'description': \"Write a function which takes a string and counts the occurrances of '{char}'. Do not use any tools.\", 'parameters': {'additionalProperties': False, 'properties': {'char': {'title': 'Char', 'type': 'string'}}, 'required': ['char'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'cities', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'weather', 'description': '', 'parameters': {'additionalProperties': False, 'properties': {'city': {'title': 'City', 'type': 'string'}}, 'required': ['city'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'vacation', 'description': 'Use the provided tools to suggest a city that has good weather. Use only the `cities` and `weather` tools provided.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_joke', 'description': 'Write a knock-knock joke on the theme of {theme}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'theme': {'title': 'Theme', 'type': 'string'}}, 'required': ['theme'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'rate_joke', 'description': 'Decide if {joke} is funny or not. Do not use any tools.', 'parameters': {'$defs': {'KnockKnockJoke': {'properties': {'whos_there': {'title': 'Whos There', 'type': 'string'}, 'punchline': {'title': 'Punchline', 'type': 'string'}}, 'required': ['whos_there', 'punchline'], 'title': 'KnockKnockJoke', 'type': 'object', 'additionalProperties': False}}, 'additionalProperties': False, 'properties': {'joke': {'$ref': '#/$defs/KnockKnockJoke'}}, 'required': ['joke'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_with_moral', 'description': 'Write a short story about {topic} and end with a moral lesson. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'story_funny', 'description': 'Write a funny, humorous story about {topic}. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}}, 'required': ['topic'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'write_story', 'description': \"Write a story about {topic} in the style: {style}.\\n Available styles: 'moral' for a story with a lesson, 'funny' for humor. Use story_funny for humor, story_with_moral for a story with a lesson.\", 'parameters': {'additionalProperties': False, 'properties': {'topic': {'title': 'Topic', 'type': 'string'}, 'style': {'title': 'Style', 'type': 'string'}}, 'required': ['topic', 'style'], 'title': 'Params', 'type': 'object'}, 'strict': True}}, {'type': 'function', 'function': {'name': 'unstable_service', 'description': 'Fetch data from an unstable external service. May require retries.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'fetch_data', 'description': 'Use the unstable_service tool to fetch data.', 'parameters': {'additionalProperties': False, 'properties': {}, 'title': 'Params', 'type': 'object', 'required': []}, 'strict': True}}, {'type': 'function', 'function': {'name': 'give_rating_for_movie', 'description': 'Give a rating for {movie_name}. The explanation MUST include the numeric score. Do not use any tools.', 'parameters': {'additionalProperties': False, 'properties': {'movie_name': {'title': 'Movie Name', 'type': 'string'}}, 'required': ['movie_name'], 'title': 'Params', 'type': 'object'}, 'strict': True}}]}, 'response': ModelResponse(id='chatcmpl-CnUF1YnTVQv55Uk38dPyOrbY4xRJW', created=1765910355, model='gpt-4o-2024-08-06', object='chat.completion', system_fingerprint='fp_e413f45763', choices=[Choices(finish_reason='stop', index=0, message=Message(content='{\"value\":{\"score\":5,\"explanation\":\"Die Hard is a classic action film that has stood the test of time. It\\'s praised for its engaging storyline, memorable characters, and thrilling action sequences. Although it\\'s a great film deserving of a high score, given the rating scale, it receives a 5 for being one of the best examples of the action genre, known for Bruce Willis’s iconic performance and its blend of excitement and humor.\"}}', role='assistant', tool_calls=None, function_call=None, provider_specific_fields={'refusal': None}, annotations=[]), provider_specific_fields={})], usage=Usage(completion_tokens=93, prompt_tokens=1268, total_tokens=1361, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=0, audio_tokens=0, reasoning_tokens=0, rejected_prediction_tokens=0, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=0, cached_tokens=0, text_tokens=None, image_tokens=None)), service_tier='default')}\n", + "Score: 5/5\n", + "Explanation: Die Hard is a classic action film that has stood the test of time. It's praised for its engaging storyline, memorable characters, and thrilling action sequences. Although it's a great film deserving of a high score, given the rating scale, it receives a 5 for being one of the best examples of the action genre, known for Bruce Willis’s iconic performance and its blend of excitement and humor.\n" +======= "> Give a rating for Die Hard. The explanation MUST include the numeric score. Do not use any tools.\n", "{\"value\":{\"score\":9,\"explanation\":\"Die Hard is a quintessential action film that redefined the genre with its intense action sequences, memorable characters, and sharp wit. Bruce Willis delivers an iconic performance as John McClane, a relatable and charismatic hero battling terrorists. Its clever plot twists, non-stop thrills, and innovative cinematography contribute to its enduring popularity and critical acclaim. Overall, it's often considered one of the best action movies of all time, deserving a score of 9 out of 10.\"}}\n", "> Give a rating for Die Hard. The explanation MUST include the numeric score. Do not use any tools.\n", @@ -743,6 +995,7 @@ "{\"value\":{\"score\":5,\"explanation\":\"Die Hard is often celebrated as one of the quintessential action movies of all time. It features high-stakes tension, impressive action sequences, and an iconic performance by Bruce Willis as John McClane. Released in 1988, the film remains a benchmark for action storytelling with its clever plot and memorable villain portrayed by Alan Rickman. Hence, it earns a 5 out of 5 for its lasting impact and entertainment value in the action genre.\"}}\n", "Score: 5/5\n", "Explanation: Die Hard is often celebrated as one of the quintessential action movies of all time. It features high-stakes tension, impressive action sequences, and an iconic performance by Bruce Willis as John McClane. Released in 1988, the film remains a benchmark for action storytelling with its clever plot and memorable villain portrayed by Alan Rickman. Hence, it earns a 5 out of 5 for its lasting impact and entertainment value in the action genre.\n" +>>>>>>> 74589b4ca19e397838f356a3bd931ff1285ef552 ] } ], diff --git a/effectful/handlers/llm/providers.py b/effectful/handlers/llm/providers.py index e99e4ce4..9c7da672 100644 --- a/effectful/handlers/llm/providers.py +++ b/effectful/handlers/llm/providers.py @@ -294,9 +294,12 @@ def compute_response(template: Template, model_input: list[Any]) -> ModelRespons ) +@defop def decode_response[**P, T](template: Callable[P, T], response: ModelResponse) -> T: - """Decode an LLM response into an instance of the template return type. This - operation should raise if the output cannot be decoded. + """Decode an LLM response into an instance of the template return type. + + This is an operation that can be handled to customize decoding behavior. + The default implementation uses the encoder's decode method. """ assert isinstance(template, Template) choice: Choices = typing.cast(Choices, response.choices[0]) @@ -326,7 +329,6 @@ def format_model_input[**P, T]( ) -> list[Any]: """Format a template applied to arguments into a sequence of input messages. - """ bound_args = template.__signature__.bind(*args, **kwargs) bound_args.apply_defaults() diff --git a/effectful/handlers/llm/synthesis.py b/effectful/handlers/llm/synthesis.py index 3db32fd7..ce93043a 100644 --- a/effectful/handlers/llm/synthesis.py +++ b/effectful/handlers/llm/synthesis.py @@ -1,4 +1,25 @@ -from effectful.ops.syntax import ObjectInterpretation +import collections +import collections.abc +import inspect +import linecache +import textwrap +import typing +from collections import ChainMap +from collections.abc import Callable +from typing import Any + +import pydantic +from litellm.types.utils import ModelResponse +from pydantic import Field + +from effectful.handlers.llm import Template +from effectful.handlers.llm.encoding import EncodableAs, type_to_encodable_type +from effectful.handlers.llm.providers import ( + OpenAIMessageContentListBlock, + decode_response, +) +from effectful.ops.semantics import fwd +from effectful.ops.syntax import ObjectInterpretation, implements class SynthesisError(Exception): @@ -9,6 +30,179 @@ def __init__(self, message, code=None): self.code = code +class SynthesizedFunction(pydantic.BaseModel): + """Structured output for function synthesis. + + Pydantic model representing synthesized code with function name and module code. + """ + + function_name: str = Field( + ..., + description="The name of the main function that satisfies the specification", + ) + module_code: str = Field( + ..., + description="Complete Python module code (no imports needed)", + ) + + +@type_to_encodable_type.register(collections.abc.Callable) +class EncodableSynthesizedFunction( + EncodableAs[Callable, SynthesizedFunction], +): + """Encodes Callable to SynthesizedFunction and vice versa.""" + + t = SynthesizedFunction + + @classmethod + def encode( + cls, vl: Callable, context: ChainMap[str, Any] | None = None + ) -> SynthesizedFunction: + """Encode a Callable to a SynthesizedFunction. + + Extracts the function name and source code. + """ + func_name = vl.__name__ + try: + source = inspect.getsource(vl) + except (OSError, TypeError): + # If we can't get source, create a minimal representation + try: + sig = inspect.signature(vl) + source = f"def {func_name}{sig}:\n pass # Source unavailable" + except (ValueError, TypeError): + source = f"def {func_name}(...):\n pass # Source unavailable" + + return SynthesizedFunction( + function_name=func_name, module_code=textwrap.dedent(source).strip() + ) + + # Counter for unique filenames + _decode_counter: typing.ClassVar[int] = 0 + + @classmethod + def decode(cls, vl: SynthesizedFunction) -> Callable: + """Decode a SynthesizedFunction to a Callable. + + Executes the module code and returns the named function. + Uses _decode_context attribute on vl if present (set by ProgramSynthesis). + """ + context: ChainMap[str, Any] | None = getattr(vl, "_decode_context", None) + func_name = vl.function_name + module_code = textwrap.dedent(vl.module_code).strip() + + cls._decode_counter += 1 + filename = f"" + lines = module_code.splitlines(keepends=True) + # Ensure last line has newline for linecache + if lines and not lines[-1].endswith("\n"): + lines[-1] += "\n" + linecache.cache[filename] = ( + len(module_code), + None, + lines, + filename, + ) + + # Start with provided context or empty dict + # Include collections module for type hints in synthesized code + exec_globals: dict[str, typing.Any] = {} + exec_globals.update(context) + + try: + code_obj = compile(module_code, filename, "exec") + exec(code_obj, exec_globals) + except SyntaxError as exc: + raise SynthesisError( + f"Syntax error in generated code: {exc}", module_code + ) from exc + except Exception as exc: + raise SynthesisError(f"Evaluation failed: {exc!r}", module_code) from exc + + if func_name not in exec_globals: + raise SynthesisError( + f"Function '{func_name}' not found after execution. " + f"Available names: {[k for k in exec_globals.keys() if not k.startswith('_')]}", + module_code, + ) + + func = exec_globals[func_name] + # Also attach source code directly for convenience + func.__source__ = module_code + func.__synthesized__ = vl + return func + + @classmethod + def serialize(cls, vl: SynthesizedFunction) -> list[OpenAIMessageContentListBlock]: + return [{"type": "text", "text": vl.model_dump_json()}] + + class ProgramSynthesis(ObjectInterpretation): - def __init__(self, *args, **kwargs): - raise NotImplementedError + """Provides a `template` handler to instruct the LLM to generate code of the + right form and with the right type. + """ + + @implements(Template.__apply__) + def _call(self, template, *args, **kwargs) -> None: + """Handle synthesis of Callable return types.""" + ret_type = template.__signature__.return_annotation + origin = typing.get_origin(ret_type) + ret_type_origin = ret_type if origin is None else origin + + # Check if return type is Callable + if ret_type_origin is not collections.abc.Callable: + return fwd() + + prompt_ext = textwrap.dedent(f""" + Implement a Python function with the following specification. + + **Specification:** {template.__prompt_template__} + + **Required function signature:** {repr(ret_type)} + The following types, functions, and values are available: + + ```python + {template.__context__} + ``` + **Critical Instructions:** + 1. The function you write MUST have EXACTLY this signature: {repr(ret_type)} + 2. Any values mentioned in the specification (like specific characters or strings) should be hardcoded directly in the function body, NOT as parameters. + 3. Do NOT create a wrapper or factory function. Write the function directly. + 4. You may include helper functions/classes/constants. + 5. Do not redefine provided types - they are already available. + 6. Do not include import statements. + + Example: If asked to "count occurrences of 'a'" with signature Callable[[str], int], write: + def count_a(text: str) -> int: + return text.count('a') + NOT: + def make_counter(char: str) -> Callable[[str], int]: + def inner(text: str) -> int: + return text.count(char) + return inner + """).strip() + + return fwd( + template.replace(prompt_template=prompt_ext), + *args, + **kwargs, + ) + + @implements(decode_response) + def _decode_response(self, template: Template, response: ModelResponse) -> Callable: + """Decode a synthesized function response with lexical context.""" + ret_type = template.__signature__.return_annotation + origin = typing.get_origin(ret_type) + ret_type_origin = ret_type if origin is None else origin + + # Only handle Callable return types + if ret_type_origin is not collections.abc.Callable: + return fwd() + + # Parse JSON and attach context to the value for decode() to use + choice = typing.cast(typing.Any, response.choices[0]) + result_str: str = choice.message.content or "" + Result = pydantic.create_model("Result", value=(SynthesizedFunction, ...)) + synth: SynthesizedFunction = Result.model_validate_json(result_str).value # type: ignore[attr-defined] + object.__setattr__(synth, "_decode_context", template.__context__) + return EncodableSynthesizedFunction.decode(synth) diff --git a/effectful/handlers/llm/type_synthesis.py b/effectful/handlers/llm/type_synthesis.py new file mode 100644 index 00000000..bcc71456 --- /dev/null +++ b/effectful/handlers/llm/type_synthesis.py @@ -0,0 +1,327 @@ +"""Type/class synthesis for LLM-generated code.""" + +import ast +import collections +import collections.abc +import ctypes +import dataclasses +import inspect +import linecache +import sys +import textwrap +import types +import typing + + +class _PyMappingProxyObject(ctypes.Structure): + """Internal ctypes structure to access the underlying dict of a mappingproxy.""" + + _fields_ = [ + ("ob_refcnt", ctypes.c_ssize_t), + ("ob_type", ctypes.py_object), + ("mapping", ctypes.py_object), + ] + + +import pydantic +from litellm import OpenAIMessageContentListBlock +from pydantic import Field + +from effectful.handlers.llm import LexicalContext, Template +from effectful.handlers.llm.encoding import EncodableAs, type_to_encodable_type +from effectful.handlers.llm.synthesis import ( + EncodableLexicalContext, + SynthesisError, + run_mypy_check, +) +from effectful.ops.semantics import fwd +from effectful.ops.syntax import ObjectInterpretation, implements + + +class SynthesizedType(pydantic.BaseModel): + """Structured output for type/class synthesis. + + Pydantic model representing synthesized class code with type name and module code. + """ + + type_name: str = Field( + ..., + description="The name of the class that satisfies the specification", + ) + module_code: str = Field( + ..., + description="Complete Python module code with the class definition (no imports needed)", + ) + + +@type_to_encodable_type.register(type) +class EncodableSynthesizedType( + EncodableAs[type, SynthesizedType], +): + """Encodes type to SynthesizedType and vice versa.""" + + t = SynthesizedType + + @classmethod + def encode(cls, vl: type, context: LexicalContext | None = None) -> SynthesizedType: + """Encode a type to a SynthesizedType. + + Extracts the type name and source code. + """ + type_name = vl.__name__ + try: + source = inspect.getsource(vl) + except (OSError, TypeError): + # If we can't get source, create a minimal representation + source = f"class {type_name}: pass # Source unavailable" + + return SynthesizedType( + type_name=type_name, module_code=textwrap.dedent(source).strip() + ) + + # Counter for unique filenames + _decode_counter: typing.ClassVar[int] = 0 + + @classmethod + def decode(cls, vl: SynthesizedType, context: LexicalContext | None = None) -> type: + """Decode a SynthesizedType to a type. + + Executes the module code and returns the named class. + The module code becomes the class's definition context, + optionally augmented with provided context. + """ + type_name = vl.type_name + module_code = textwrap.dedent(vl.module_code).strip() + "\n" + + # Create a unique filename and register source with linecache + # This allows inspect.getsource() to work on the generated class + cls._decode_counter += 1 + # NOTE: adding source to class is more tricky + # because for function func.__code__.co_filename (set by compile(..., filename, "exec")) is set automatically + # We have to do this manually for class (set module name) for inspect.getsource() to work + module_name = ( + f"_llm_effectful_synthesized_types.{type_name}.{cls._decode_counter}" + ) + filename = f"" + + # Register source for inspect/linecache + lines = module_code.splitlines(keepends=True) + # Ensure last line has newline for linecache + if lines and not lines[-1].endswith("\n"): + lines[-1] += "\n" + linecache.cache[filename] = ( + len(module_code), + None, + lines, + filename, + ) + + # Create a real module and put it to sys.modules + mod = types.ModuleType(module_name) + mod.__file__ = filename + sys.modules[module_name] = mod + + # globals = module.__dict__ + context + g = mod.__dict__ + g.update({"collections": collections}) + if context: + g.update(context) + g.update({"__name__": module_name, "__file__": filename}) + g.setdefault("__package__", module_name.rpartition(".")[0]) + + try: + # NOTE: Parse and inject __firstlineno__ into class bodies for Python 3.13+ compatibility + # inspect.getsource() looks for __firstlineno__ in vars(cls), which requires it to be in the class's __dict__. + # We inject it via AST before execution. + tree = ast.parse(module_code) + for node in ast.walk(tree): + if isinstance(node, ast.ClassDef): + # Create: __firstlineno__ = + assign = ast.Assign( + targets=[ast.Name(id="__firstlineno__", ctx=ast.Store())], + value=ast.Constant(value=node.lineno), + lineno=node.lineno, + col_offset=0, + ) + ast.fix_missing_locations(assign) + node.body.insert(0, assign) + ast.fix_missing_locations(tree) + code_obj = compile(tree, filename, "exec") + exec(code_obj, g, g) + except SyntaxError as exc: + raise SynthesisError( + f"Syntax error in generated code: {exc}", module_code + ) from exc + except Exception as exc: + raise SynthesisError(f"Evaluation failed: {exc!r}", module_code) from exc + + if type_name not in g: + raise SynthesisError( + f"Type '{type_name}' not found after execution. " + f"Available names: {[k for k in g.keys() if not k.startswith('_')]}", + module_code, + ) + + synthesized_type = g[type_name] + + if not isinstance(synthesized_type, type): + raise SynthesisError( + f"'{type_name}' is not a type, got {type(synthesized_type).__name__}", + module_code, + ) + + # Attach source code and module name + synthesized_type.__source__ = module_code # type: ignore[attr-defined] + synthesized_type.__synthesized__ = vl # type: ignore[attr-defined] + synthesized_type.__module__ = module_name + + # NOTE: Set __firstlineno__ AFTER __module__ assignment! + # In Python 3.13, setting __module__ clears __firstlineno__ from vars(). + # We use ctypes to directly inject it into __dict__ for inspect.getsource(). + if "__firstlineno__" not in vars(synthesized_type): + firstlineno = next( + ( + n.lineno + for n in ast.walk(ast.parse(module_code)) + if isinstance(n, ast.ClassDef) and n.name == type_name + ), + 1, + ) + inner_dict = _PyMappingProxyObject.from_address( + id(vars(synthesized_type)) + ).mapping + inner_dict["__firstlineno__"] = firstlineno + + return synthesized_type + + @classmethod + def serialize(cls, vl: SynthesizedType) -> list[OpenAIMessageContentListBlock]: + return [{"type": "text", "text": vl.model_dump_json()}] + + +class TypeSynthesis(ObjectInterpretation): + """Provides a `template` handler to instruct the LLM to generate a class/type + that inherits from a specified base type. + """ + + def __init__(self, type_check: bool = False): + """Initialize the type synthesis handler. + + Args: + type_check: Whether to run mypy to verify the generated code. + """ + self.type_check = type_check + + def _build_type( + self, + result: SynthesizedType, + base_type: type, + lexical_context: LexicalContext, + ) -> type: + """Build and execute a type from the synthesized module. + + Uses EncodableSynthesizedType.decode with the template's lexical context. + Optionally runs mypy type checking if enabled. + Validates that the synthesized type is a subclass of base_type. + + Args: + result: The structured output from the LLM + base_type: The expected base type (e.g., Animal for type[Animal]) + lexical_context: Dict of lexical context (functions/types) available in scope + + Returns: + The synthesized type (class) + """ + if self.type_check: + success, error_msg = run_mypy_check(result.module_code, lexical_context) + if not success: + raise SynthesisError( + f"Type check failed:\n{error_msg}", result.module_code + ) + + synthesized_type = EncodableSynthesizedType.decode( + result, context=lexical_context + ) + + # Validate that synthesized type inherits from base_type + if not issubclass(synthesized_type, base_type): + raise SynthesisError( + f"Synthesized type '{synthesized_type.__name__}' does not inherit from '{base_type.__name__}'", + result.module_code, + ) + + return synthesized_type + + @implements(Template.__call__) + def _call(self, template, *args, **kwargs) -> type: + ret_type = template.__signature__.return_annotation + origin = typing.get_origin(ret_type) + ret_type_origin = ret_type if origin is None else origin + + # Check if return type is type[BaseClass] + if ret_type_origin is not type: + return fwd() + + # Extract the base type from type[BaseClass] + type_args = typing.get_args(ret_type) + if not type_args: + raise SynthesisError( + "Type synthesis requires a base type, e.g., type[Animal]. " + "Got bare 'type' without a type parameter.", + None, + ) + + base_type = type_args[0] + + # Verify base type is in lexical context + base_type_name = base_type.__name__ + if base_type_name not in template.__context__: + raise SynthesisError( + f"Base type '{base_type_name}' must be in the template's lexical context.", + None, + ) + + # Include the full lexical context + context_source = EncodableLexicalContext.encode(template.__context__) + escaped_context = context_source.replace("{", "{{").replace("}", "}}") + context_section = f""" +The following types, functions, and values are available: + +```python +{escaped_context} +``` +""" + + prompt_ext = textwrap.dedent(f""" + Implement a Python class with the following specification. + + **Specification:** {template.__prompt_template__} + + **Required:** The class must inherit from `{base_type_name}` and implement its interface. + {context_section} + **Instructions:** + 1. Write a complete Python module with the class definition. + 2. Choose a descriptive class name. + 3. The class MUST inherit from `{base_type_name}`. + 4. Implement all required methods from the base class. + 5. You may include helper functions/classes/constants. + 6. Do not redefine provided types - they are already available. + 7. Do not include import statements. + """).strip() + + response: SynthesizedType = fwd( + dataclasses.replace( + template, + __prompt_template__=prompt_ext, + __signature__=template.__signature__.replace( + return_annotation=SynthesizedType + ), + ), + *args, + **kwargs, + ) + + # Build the type using lexical context for exec globals + synthesized_type = self._build_type(response, base_type, template.__context__) + + return synthesized_type diff --git a/pyproject.toml b/pyproject.toml index ac502509..2260193a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,6 +42,7 @@ jax = ["jax", "dm-tree"] numpyro = ["numpyro>=0.19", "dm-tree"] llm = [ "litellm", + "mypy", "pillow", "pydantic", ] diff --git a/tests/test_handlers_llm.py b/tests/test_handlers_llm.py index 2fd0fd42..d8a81938 100644 --- a/tests/test_handlers_llm.py +++ b/tests/test_handlers_llm.py @@ -1,11 +1,12 @@ from collections.abc import Callable +from dataclasses import dataclass from typing import Annotated import pytest from effectful.handlers.llm import Template from effectful.handlers.llm.providers import RetryLLMHandler -from effectful.handlers.llm.synthesis import ProgramSynthesis +from effectful.handlers.llm.synthesis import ProgramSynthesis, SynthesizedFunction from effectful.handlers.llm.template import IsRecursive from effectful.ops.semantics import NotHandled, handler from effectful.ops.syntax import ObjectInterpretation, implements @@ -41,14 +42,14 @@ def _call[**P]( class SingleResponseLLMProvider[T](ObjectInterpretation): - """Simplified mock provider that returns a single response for any prompt.""" + """Simplified mock provider that returns a single response. - def __init__(self, response: T): - """Initialize with a single response string. + Simulates LiteLLMProvider behavior by creating a ModelResponse and calling + decode_response. Automatically wraps response in {"value": ...} for non-string types. + """ - Args: - response: The response to return for any template call - """ + def __init__(self, response: T): + """Initialize with a response value.""" self.response = response @implements(Template.__apply__) @@ -58,6 +59,37 @@ def _call[**P]( return self.response +class FailingThenSucceedingProvider[T](ObjectInterpretation): + """Mock provider that fails a specified number of times before succeeding.""" + + def __init__( + self, + fail_count: int, + success_response: T, + exception_factory: Callable[[], Exception], + ): + """Initialize the provider. + + Args: + fail_count: Number of times to fail before succeeding + success_response: Response to return after failures + exception_factory: Factory function that creates exceptions to raise + """ + self.fail_count = fail_count + self.success_response = success_response + self.exception_factory = exception_factory + self.call_count = 0 + + @implements(Template.__call__) + def _call[**P]( + self, template: Template[P, T], *args: P.args, **kwargs: P.kwargs + ) -> T: + self.call_count += 1 + if self.call_count <= self.fail_count: + raise self.exception_factory() + return self.success_response + + # Test templates from the notebook examples @Template.define def limerick(theme: str) -> str: @@ -96,6 +128,36 @@ def mutual_b() -> Annotated[str, IsRecursive]: raise NotHandled +@dataclass +class Person: + name: str + age: int + + +@Template.define +def make_greeter(style: str) -> Callable[[Person], str]: + """Create a greeting function for a person with the given style.""" + raise NotImplementedError + + +# Helper function for lexical scope test - defined at module level +def double_count(text: str, char: str) -> int: + """Count occurrences of a character and double it.""" + return text.count(char) * 2 + + +# Template that captures the lexical function above +@Template.define +def make_double_counter(char: str) -> Callable[[str], int]: + """Create a function that counts occurrences of '{char}' and doubles the result. + Use the double_count helper function.""" + raise NotImplementedError + + +# Module-level variable for shadowing test +shadow_test_value = "global" + + # Unit tests def test_limerick(): """Test the limerick template returns a string.""" @@ -123,11 +185,12 @@ def test_primes_decode_int(): @pytest.mark.xfail(reason="Synthesis handler not yet implemented") def test_count_char_with_program_synthesis(): """Test the count_char template with program synthesis.""" - mock_code = """ -def count_occurrences(s): - return s.count('a') -""" - mock_provider = SingleResponseLLMProvider(mock_code) + mock_provider = SingleResponseLLMProvider( + { + "function_name": "count_occurrences", + "module_code": "def count_occurrences(s):\n return s.count('a')", + } + ) with handler(mock_provider), handler(ProgramSynthesis()): count_a = count_char("a") @@ -136,36 +199,22 @@ def count_occurrences(s): assert count_a("cherry") == 0 -class FailingThenSucceedingProvider[T](ObjectInterpretation): - """Mock provider that fails a specified number of times before succeeding.""" - - def __init__( - self, - fail_count: int, - success_response: T, - exception_factory: Callable[[], Exception], - ): - """Initialize the provider. - - Args: - fail_count: Number of times to fail before succeeding - success_response: Response to return after failures - exception_factory: Factory function that creates exceptions to raise - """ - self.fail_count = fail_count - self.success_response = success_response - self.exception_factory = exception_factory - self.call_count = 0 - - @implements(Template.__apply__) - def _call[**P]( - self, template: Template[P, T], *args: P.args, **kwargs: P.kwargs - ) -> T: - self.call_count += 1 - if self.call_count <= self.fail_count: - raise self.exception_factory() - return self.success_response +def test_count_char_with_untyped_function(): + """Test program synthesis works even when LLM omits type annotations.""" + mock_response = SynthesizedFunction( + function_name="count_chars", + module_code=""" +def count_chars(s): + return s.count('x') +""", + ) + mock_provider = SingleResponseLLMProvider(mock_response) + with handler(mock_provider), handler(ProgramSynthesis()): + count_x = count_char("x") + assert callable(count_x) + assert count_x("xylophone") == 1 + assert count_x("xxx") == 3 def test_retry_handler_succeeds_after_failures(): """Test that RetryLLMHandler retries and eventually succeeds.""" @@ -330,10 +379,6 @@ def test_mutually_recursive_templates(): assert mutual_b in mutual_b.tools.values() -# Module-level variable for shadowing test -shadow_test_value = "global" - - def test_lexical_context_shadowing(): """Test that local variables shadow global variables in lexical context.""" # Local shadows global diff --git a/tests/test_handlers_llm_provider.py b/tests/test_handlers_llm_provider.py index 4006913f..6f167b8b 100644 --- a/tests/test_handlers_llm_provider.py +++ b/tests/test_handlers_llm_provider.py @@ -1,7 +1,6 @@ """Tests for LLM handlers and providers. -This module tests the functionality from build/main.py and build/llm.py, -breaking down individual components like LiteLLMProvider, LLMLoggingHandler, -ProgramSynthesis, and sampling strategies. +This module tests the functionality of LiteLLMProvider, LLMLoggingHandler, +and related LLM components. """ import functools @@ -318,7 +317,7 @@ def smiley_face() -> Image.Image: @Template.define def categorise_image(image: Image.Image) -> str: - """Return a description of the following image. + """Return a description of the following image. You MUST NOT use any tools. {image}""" raise NotHandled diff --git a/tests/test_handlers_llm_provider_class_synthesis.py b/tests/test_handlers_llm_provider_class_synthesis.py new file mode 100644 index 00000000..4b4e43e3 --- /dev/null +++ b/tests/test_handlers_llm_provider_class_synthesis.py @@ -0,0 +1,119 @@ +"""Tests for LLM type/class synthesis functionality.""" + +import inspect +import logging +import sys + +import pytest + +from effectful.handlers.llm import Template +from effectful.handlers.llm.providers import LiteLLMProvider, LLMLoggingHandler +from effectful.handlers.llm.synthesis import SynthesisError +from effectful.handlers.llm.type_synthesis import TypeSynthesis +from effectful.ops.semantics import handler +from effectful.ops.types import NotHandled + +from .test_handlers_llm_provider import ( + LimitLLMCallsHandler, + requires_openai, + retry_on_error, +) + + +# Base class for type synthesis tests +class Animal: + """Base class for animals.""" + + def speak(self) -> str: + raise NotImplementedError + + def move(self) -> str: + raise NotImplementedError + + +@Template.define +def create_animal(behavior: str) -> type[Animal]: + """Create an Animal subclass with the specified behavior: {behavior} + + The class should implement speak() and move() methods. + Do not use any tools. + """ + raise NotHandled + + +class TestTypeSynthesis: + """Tests for type (class) synthesis functionality.""" + + @requires_openai + @retry_on_error(error=SynthesisError, n=3) + def test_generates_subtype(self): + """Test that TypeSynthesis can generate a subtype of a base class.""" + with ( + handler(LiteLLMProvider(model_name="gpt-4o-mini")), + handler(TypeSynthesis()), + handler(LimitLLMCallsHandler(max_calls=1)), + ): + DogClass = create_animal("a dog that barks and walks") + + # Verify it's a type + assert isinstance(DogClass, type) + # Verify it inherits from Animal + assert issubclass(DogClass, Animal) + + # Create an instance and test methods + dog = DogClass() + speak_result = dog.speak() + move_result = dog.move() + + assert isinstance(speak_result, str) + assert isinstance(move_result, str) + + @requires_openai + @retry_on_error(error=SynthesisError, n=3) + def test_synthesized_type_has_source(self): + """Test that synthesized types have __source__ attribute.""" + logger = logging.getLogger("effectful.llm") + logger.setLevel(logging.INFO) + log_handler = logging.StreamHandler(sys.stdout) + log_handler.setFormatter(logging.Formatter("%(levelname)s %(payload)s")) + logger.addHandler(log_handler) + llm_logger = LLMLoggingHandler(logger=logger) + with ( + handler(LiteLLMProvider(model_name="gpt-4o-mini")), + handler(TypeSynthesis()), + handler(LimitLLMCallsHandler(max_calls=1)), + handler(llm_logger), + ): + CatClass = create_animal("a cat that meows and prowls") + + source = inspect.getsource(CatClass) + assert hasattr(CatClass, "__synthesized__") + assert hasattr(CatClass, "__source__") + assert source == CatClass.__source__ + + def test_type_synthesis_requires_base_in_context(self): + """Test that type synthesis fails if base type is not in lexical context.""" + import dataclasses + + from effectful.handlers.llm import LexicalContext + + # Create a template with Animal in return type but NOT in context + @Template.define + def create_orphan() -> type[Animal]: + """Create an animal.""" + raise NotHandled + + # Create a modified template with empty context + orphan_template = dataclasses.replace( + create_orphan, + __context__=LexicalContext({}), # Empty context - no Animal + ) + + with pytest.raises( + SynthesisError, match="must be in the template's lexical context" + ): + with ( + handler(LiteLLMProvider(model_name="gpt-4o-mini")), + handler(TypeSynthesis()), + ): + orphan_template() diff --git a/tests/test_handlers_llm_provider_image.py b/tests/test_handlers_llm_provider_image.py new file mode 100644 index 00000000..d2b40255 --- /dev/null +++ b/tests/test_handlers_llm_provider_image.py @@ -0,0 +1,71 @@ +"""Tests for LLM image input functionality.""" + +import os + +import pytest +from PIL import Image + +from effectful.handlers.llm import Template +from effectful.handlers.llm.providers import LiteLLMProvider, completion +from effectful.ops.semantics import fwd, handler +from effectful.ops.syntax import ObjectInterpretation, implements +from effectful.ops.types import NotHandled + +# Check for API keys +HAS_OPENAI_KEY = "OPENAI_API_KEY" in os.environ and os.environ["OPENAI_API_KEY"] + +requires_openai = pytest.mark.skipif( + not HAS_OPENAI_KEY, reason="OPENAI_API_KEY environment variable not set" +) + + +class LimitLLMCallsHandler(ObjectInterpretation): + max_calls: int + no_calls: int = 0 + + def __init__(self, max_calls: int): + self.max_calls = max_calls + + @implements(completion) + def _completion(self, *args, **kwargs): + if self.no_calls >= self.max_calls: + raise RuntimeError( + f"Test used too many requests (max_calls = {self.max_calls})" + ) + self.no_calls += 1 + return fwd() + + +def smiley_face() -> Image.Image: + bmp = [ + "00000000", + "00100100", + "00100100", + "00000000", + "01000010", + "00111100", + "00000000", + "00000000", + ] + + img = Image.new("1", (8, 8)) + for y, row in enumerate(bmp): + for x, c in enumerate(row): + img.putpixel((x, y), 1 if c == "1" else 0) + return img + + +@Template.define +def categorise_image(image: Image.Image) -> str: + """Return a description of the following image. Do not use any tools. + {image}""" + raise NotHandled + + +@requires_openai +def test_image_input(): + with ( + handler(LiteLLMProvider(model_name="gpt-4o")), + handler(LimitLLMCallsHandler(max_calls=3)), + ): + assert any("smile" in categorise_image(smiley_face()).lower() for _ in range(3)) diff --git a/tests/test_handlers_llm_provider_synthesis.py b/tests/test_handlers_llm_provider_synthesis.py new file mode 100644 index 00000000..db86ea00 --- /dev/null +++ b/tests/test_handlers_llm_provider_synthesis.py @@ -0,0 +1,123 @@ +"""Tests for LLM program synthesis functionality.""" + +import inspect +from collections.abc import Callable + +from effectful.handlers.llm import Template +from effectful.handlers.llm.providers import LiteLLMProvider +from effectful.handlers.llm.synthesis import ProgramSynthesis, SynthesisError +from effectful.ops.semantics import handler +from effectful.ops.types import NotHandled + +from .test_handlers_llm_provider import ( + LimitLLMCallsHandler, + requires_openai, + retry_on_error, +) + + +@Template.define +def create_function(char: str) -> Callable[[str], int]: + """Create a function that counts occurrences of the character '{char}' in a string. + Do not use any tools and implement this function directly. + + Return as a code block with the last definition being the function. + """ + raise NotHandled + + +class TestProgramSynthesis: + """Tests for ProgramSynthesis handler functionality.""" + + @requires_openai + @retry_on_error(error=SynthesisError, n=3) + def test_generates_callable(self): + """Test ProgramSynthesis handler generates executable code.""" + with ( + handler(LiteLLMProvider(model_name="gpt-4o-mini")), + handler(ProgramSynthesis(type_check=True)), + handler(LimitLLMCallsHandler(max_calls=1)), + ): + count_func = create_function("a") + + assert callable(count_func) + # Test the generated function + assert count_func("banana") == 3 + assert count_func("cherry") == 0 + assert count_func("aardvark") == 3 + + @requires_openai + @retry_on_error(error=SynthesisError, n=3) + def test_inspect_getsource_works(self): + """Test that inspect.getsource() works on synthesized functions.""" + with ( + handler(LiteLLMProvider(model_name="gpt-4o-mini")), + handler(ProgramSynthesis(type_check=True)), + handler(LimitLLMCallsHandler(max_calls=1)), + ): + count_func = create_function("x") + + # inspect.getsource() should work on the synthesized function + source = inspect.getsource(count_func) + assert isinstance(source, str) + assert len(source) > 0 + assert "def" in source + + # __source__ attribute should also be available with full module code + assert hasattr(count_func, "__source__") + assert "def" in count_func.__source__ + + @requires_openai + @retry_on_error(error=SynthesisError, n=3) + def test_synthesized_attribute(self): + """Test that __synthesized__ attribute is attached to generated functions.""" + from effectful.handlers.llm.synthesis import SynthesizedFunction + + with ( + handler(LiteLLMProvider(model_name="gpt-4o-mini")), + handler(ProgramSynthesis(type_check=True)), + handler(LimitLLMCallsHandler(max_calls=1)), + ): + count_func = create_function("z") + + assert hasattr(count_func, "__synthesized__") + assert isinstance(count_func.__synthesized__, SynthesizedFunction) + # The synthesized module code should be present + assert "def" in count_func.__synthesized__.module_code + # The function should work correctly + assert count_func("pizza") == 2 # two 'z's in "pizza" + + def test_immutable_context(self): + """Test that synthesis does not pollute the original lexical context.""" + from effectful.handlers.llm import LexicalContext + from effectful.handlers.llm.synthesis import ( + EncodableSynthesizedFunction, + SynthesizedFunction, + ) + + # Create a context with known contents + original_context = LexicalContext({"helper": lambda x: x * 2}) + original_keys = set(original_context.keys()) + + # Synthesize a function that defines new names + synth = SynthesizedFunction( + function_name="my_func", + module_code=""" +def internal_helper(x): + return x + 1 + +def my_func(n): + return internal_helper(n) * 2 +""", + ) + + # Decode with the context + func = EncodableSynthesizedFunction.decode(synth, context=original_context) + + # Verify the function works + assert func(5) == 12 # (5 + 1) * 2 + + # Verify original context was NOT polluted with new definitions + assert set(original_context.keys()) == original_keys + assert "my_func" not in original_context + assert "internal_helper" not in original_context