diff --git a/samples-v2/openai_agents/.funcignore b/samples-v2/openai_agents/.funcignore new file mode 100644 index 00000000..9966315f --- /dev/null +++ b/samples-v2/openai_agents/.funcignore @@ -0,0 +1,8 @@ +.git* +.vscode +__azurite_db*__.json +__blobstorage__ +__queuestorage__ +local.settings.json +test +.venv \ No newline at end of file diff --git a/samples-v2/openai_agents/.gitignore b/samples-v2/openai_agents/.gitignore new file mode 100644 index 00000000..6921f8c7 --- /dev/null +++ b/samples-v2/openai_agents/.gitignore @@ -0,0 +1,135 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don’t work, or not +# install all needed dependencies. +#Pipfile.lock + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# Azure Functions artifacts +bin +obj +appsettings.json +# local.settings.json + +# Azurite artifacts +__blobstorage__ +__queuestorage__ +__azurite_db*__.json +.python_packages \ No newline at end of file diff --git a/samples-v2/openai_agents/basic/hello_world.py b/samples-v2/openai_agents/basic/hello_world.py index 169290d6..ff19a269 100644 --- a/samples-v2/openai_agents/basic/hello_world.py +++ b/samples-v2/openai_agents/basic/hello_world.py @@ -10,7 +10,7 @@ async def main(): ) result = await Runner.run(agent, "Tell me about recursion in programming.") - print(result.final_output) + return result.final_output # Function calls itself, # Looping in smaller pieces, # Endless by design. diff --git a/samples-v2/openai_agents/function_app.py b/samples-v2/openai_agents/function_app.py new file mode 100644 index 00000000..572f436d --- /dev/null +++ b/samples-v2/openai_agents/function_app.py @@ -0,0 +1,29 @@ +import azure.functions as func +import logging + +app = func.FunctionApp(http_auth_level=func.AuthLevel.FUNCTION) + +@app.route(route="orchestrators/{functionName}") +@app.durable_client_input(client_name="client") +async def hello_orchestration_starter(req: func.HttpRequest, client): + function_name = req.route_params.get('functionName') + instance_id = await client.start_new(function_name) + response = client.create_check_status_response(req, instance_id) + return response + + +@app.orchestration_trigger(context_name="context") +def basic_hello_world_orchestrator(context): + result = yield context.call_activity("openai_agent_activity") + return result + +# Activity for OpenAI agent execution +@app.activity_trigger(input_name="input") +async def openai_agent_activity(input: str): + # TODO: Instead of wrapping this code in an activity function like this, + # we should be able to invoke it from the orchestrator directly. + # In order to enable this, Runner.run invocations should be implicitly + # wrapped in activity invocations. + from basic.hello_world import main + result = await main() + return result diff --git a/samples-v2/openai_agents/host.json b/samples-v2/openai_agents/host.json new file mode 100644 index 00000000..9df91361 --- /dev/null +++ b/samples-v2/openai_agents/host.json @@ -0,0 +1,15 @@ +{ + "version": "2.0", + "logging": { + "applicationInsights": { + "samplingSettings": { + "isEnabled": true, + "excludedTypes": "Request" + } + } + }, + "extensionBundle": { + "id": "Microsoft.Azure.Functions.ExtensionBundle", + "version": "[4.*, 5.0.0)" + } +} \ No newline at end of file diff --git a/samples-v2/openai_agents/local.settings.json b/samples-v2/openai_agents/local.settings.json new file mode 100644 index 00000000..41ce6b37 --- /dev/null +++ b/samples-v2/openai_agents/local.settings.json @@ -0,0 +1,7 @@ +{ + "IsEncrypted": false, + "Values": { + "AzureWebJobsStorage": "UseDevelopmentStorage=true", + "FUNCTIONS_WORKER_RUNTIME": "python" + } +} \ No newline at end of file diff --git a/samples-v2/openai_agents/requirements.txt b/samples-v2/openai_agents/requirements.txt new file mode 100644 index 00000000..8e41db3a --- /dev/null +++ b/samples-v2/openai_agents/requirements.txt @@ -0,0 +1,8 @@ +# DO NOT include azure-functions-worker in this file +# The Python Worker is managed by Azure Functions platform +# Manually managing azure-functions-worker may cause unexpected issues + +azure-functions +azure-functions-durable +openai-agents>=0.2.3,<0.3 +eval-type-backport>=0.2.2; python_version < '3.10'