diff --git a/01_funccall.ipynb b/01_funccall.ipynb index c059c76..c352f3d 100644 --- a/01_funccall.ipynb +++ b/01_funccall.ipynb @@ -26,7 +26,7 @@ "outputs": [], "source": [ "#| exports\n", - "import inspect, json, ast\n", + "import asyncio, inspect, json, ast\n", "from collections import abc\n", "from fastcore.utils import *\n", "from fastcore.docments import docments\n", @@ -965,27 +965,9 @@ "name": "stdout", "output_type": "stream", "text": [ - "Adds a + b.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Returns:\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "Adds a + b.\n", + "\n", + "Returns:\n", "- The sum of the inputs (type: integer)\n" ] }, @@ -1869,90 +1851,18 @@ "name": "stdout", "output_type": "stream", "text": [ - "Traceback (most recent call last):\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " File \"/var/folders/51/b2_szf2945n072c0vj2cyty40000gn/T/ipymini_45858/2052945749.py\", line 14, in python\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " try: return _run(code, glb, loc)\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ^^^^^^^^^^^^^^^^^^^^\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " File \"/var/folders/51/b2_szf2945n072c0vj2cyty40000gn/T/ipymini_45858/1858893181.py\", line 18, in _run\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " try: exec(compiled_code, glb, loc)\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " File \"\", line 1, in \n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " File \"/var/folders/51/b2_szf2945n072c0vj2cyty40000gn/T/ipymini_45858/2052945749.py\", line 9, in handler\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " def handler(*args): raise TimeoutError()\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " ^^^^^^^^^^^^^^^^^^^^\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "TimeoutError\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ + "Traceback (most recent call last):\n", + " File \"/var/folders/zl/js35kg3914qc7d8lsdtqsyf00000gn/T/ipykernel_75165/2052945749.py\", line 14, in python\n", + " try: return _run(code, glb, loc)\n", + " ^^^^^^^^^^^^^^^^^^^^\n", + " File \"/var/folders/zl/js35kg3914qc7d8lsdtqsyf00000gn/T/ipykernel_75165/1858893181.py\", line 18, in _run\n", + " try: exec(compiled_code, glb, loc)\n", + " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", + " File \"\", line 1, in \n", + " File \"/var/folders/zl/js35kg3914qc7d8lsdtqsyf00000gn/T/ipykernel_75165/2052945749.py\", line 9, in handler\n", + " def handler(*args): raise TimeoutError()\n", + " ^^^^^^^^^^^^^^^^^^^^\n", + "TimeoutError\n", "\n" ] } @@ -2374,34 +2284,44 @@ "#| exports\n", "async def call_func_async(fc_name, fc_inputs, ns, raise_on_err=True):\n", " \"Awaits the function `fc_name` with the given `fc_inputs` using namespace `ns`.\"\n", - " res = call_func(fc_name, fc_inputs, ns, raise_on_err=raise_on_err)\n", - " if inspect.iscoroutine(res):\n", - " try: res = await res\n", - " except Exception as e:\n", - " if raise_on_err: raise e from None\n", - " else: return traceback.format_exc()\n", + " if not isinstance(ns, abc.Mapping): ns = mk_ns(ns)\n", + " func = resolve_nm(fc_name, ns)\n", + " if inspect.iscoroutinefunction(func):\n", + " res = call_func(fc_name, fc_inputs, ns, raise_on_err=raise_on_err)\n", + " else: res = asyncio.to_thread(call_func, fc_name, fc_inputs, ns, raise_on_err=raise_on_err)\n", + " try: res = await res\n", + " except Exception as e:\n", + " if raise_on_err: raise e from None\n", + " else: return traceback.format_exc()\n", " return res" ] }, + { + "cell_type": "markdown", + "id": "740ada11", + "metadata": {}, + "source": [ + "Testing async `call_func_async` both with sync and async functions. Sync functions are automatically run in a separate thread via `asyncio.to_thread`, allowing `asyncio.gather` to execute multiple sync tool calls in parallel without blocking the event loop." + ] + }, { "cell_type": "code", "execution_count": null, "id": "b83998ac-68e2-4dbe-b594-65fb4fdf59b8", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3" - ] - }, - "execution_count": null, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], + "source": [ + "test_eq(await call_func_async('asums', {'a': 1, 'b': 2}, ns=[asums]), 3)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1c4d8b2b", + "metadata": {}, + "outputs": [], "source": [ - "await call_func_async('asums', {'a': 1, 'b': 2}, ns=[asums])" + "test_eq(await call_func_async('sums', {'a': 1, 'b': 2}, ns=[sums]), 3)" ] }, { diff --git a/toolslm/funccall.py b/toolslm/funccall.py index b757d9a..f3fabb7 100644 --- a/toolslm/funccall.py +++ b/toolslm/funccall.py @@ -5,7 +5,7 @@ 'call_func_async', 'mk_param', 'schema2sig', 'mk_tool'] # %% ../01_funccall.ipynb #e5ad6b86 -import inspect, json, ast +import asyncio, inspect, json, ast from collections import abc from fastcore.utils import * from fastcore.docments import docments @@ -257,12 +257,15 @@ def call_func(fc_name, fc_inputs, ns, raise_on_err=True): # %% ../01_funccall.ipynb #73bca085 async def call_func_async(fc_name, fc_inputs, ns, raise_on_err=True): "Awaits the function `fc_name` with the given `fc_inputs` using namespace `ns`." - res = call_func(fc_name, fc_inputs, ns, raise_on_err=raise_on_err) - if inspect.iscoroutine(res): - try: res = await res - except Exception as e: - if raise_on_err: raise e from None - else: return traceback.format_exc() + if not isinstance(ns, abc.Mapping): ns = mk_ns(ns) + func = resolve_nm(fc_name, ns) + if inspect.iscoroutinefunction(func): + res = call_func(fc_name, fc_inputs, ns, raise_on_err=raise_on_err) + else: res = asyncio.to_thread(call_func, fc_name, fc_inputs, ns, raise_on_err=raise_on_err) + try: res = await res + except Exception as e: + if raise_on_err: raise e from None + else: return traceback.format_exc() return res # %% ../01_funccall.ipynb #ede7ea66