From 0bf0a24ada50a0457cb804f58bcfbd7950f94230 Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Wed, 5 Aug 2026 11:32:01 -0700 Subject: [PATCH] Adding tethered agent sample --- test_samples/tethered-agent/README.md | 0 test_samples/tethered-agent/env.TEMPLATE | 9 ++++ test_samples/tethered-agent/requirements.txt | 7 +++ test_samples/tethered-agent/src/__init__.py | 0 test_samples/tethered-agent/src/agent.py | 54 +++++++++++++++++++ test_samples/tethered-agent/src/main.py | 16 ++++++ .../tethered-agent/src/start_server.py | 32 +++++++++++ 7 files changed, 118 insertions(+) create mode 100644 test_samples/tethered-agent/README.md create mode 100644 test_samples/tethered-agent/env.TEMPLATE create mode 100644 test_samples/tethered-agent/requirements.txt create mode 100644 test_samples/tethered-agent/src/__init__.py create mode 100644 test_samples/tethered-agent/src/agent.py create mode 100644 test_samples/tethered-agent/src/main.py create mode 100644 test_samples/tethered-agent/src/start_server.py diff --git a/test_samples/tethered-agent/README.md b/test_samples/tethered-agent/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/test_samples/tethered-agent/env.TEMPLATE b/test_samples/tethered-agent/env.TEMPLATE new file mode 100644 index 000000000..8b4753691 --- /dev/null +++ b/test_samples/tethered-agent/env.TEMPLATE @@ -0,0 +1,9 @@ +CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTID= +CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTSECRET= +CONNECTIONS__SERVICE_CONNECTION__SETTINGS__TENANTID= + +LOGGING__LOGLEVEL__microsoft_agents=DEBUG + +CONNECTIONSMAP__0__SERVICEURL=* +CONNECTIONSMAP__0__CONNECTION=SERVICE_CONNECTION + \ No newline at end of file diff --git a/test_samples/tethered-agent/requirements.txt b/test_samples/tethered-agent/requirements.txt new file mode 100644 index 000000000..80c725303 --- /dev/null +++ b/test_samples/tethered-agent/requirements.txt @@ -0,0 +1,7 @@ +python-dotenv +aiohttp +microsoft-agents-hosting-aiohttp +microsoft-agents-hosting-core +microsoft-agents-authentication-msal +microsoft-agents-activity +tethered \ No newline at end of file diff --git a/test_samples/tethered-agent/src/__init__.py b/test_samples/tethered-agent/src/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/test_samples/tethered-agent/src/agent.py b/test_samples/tethered-agent/src/agent.py new file mode 100644 index 000000000..93578cdb3 --- /dev/null +++ b/test_samples/tethered-agent/src/agent.py @@ -0,0 +1,54 @@ +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. + +import aiohttp + +from os import environ, path +from dotenv import load_dotenv +from microsoft_agents.activity import load_configuration_from_env +from microsoft_agents.authentication.msal import ( + MsalConnectionManager, +) +from microsoft_agents.hosting.core import ( + AgentApplication, + TurnState, + TurnContext, + MemoryStorage, +) +from microsoft_agents.hosting.aiohttp import CloudAdapter +from microsoft_agents.hosting.core.app.oauth.authorization import Authorization + +load_dotenv() + +agents_sdk_config = load_configuration_from_env(environ) + +STORAGE = MemoryStorage() +CONNECTION_MANAGER = MsalConnectionManager(**agents_sdk_config) +ADAPTER = CloudAdapter(connection_manager=CONNECTION_MANAGER) + +AUTHORIZATION = Authorization(STORAGE, CONNECTION_MANAGER, **agents_sdk_config) + +AGENT_APP = AgentApplication[TurnState]( + storage=STORAGE, adapter=ADAPTER, authorization=AUTHORIZATION, **agents_sdk_config +) + + +@AGENT_APP.conversation_update("membersAdded") +@AGENT_APP.message("/help") +async def _help(context: TurnContext, _state: TurnState): + await context.send_activity( + "Welcome to the Echo Agent sample 🚀. " + "Type /help for help or send a message to see the echo feature in action." + ) + +@AGENT_APP.message("/get") +async def _get(context: TurnContext, _state: TurnState): + async with aiohttp.ClientSession() as session: + async with session.get("https://www.bing.com") as response: + await context.send_activity( + f"This is a GET request. You can use this to retrieve information. Status: {response.status}" + ) + +@AGENT_APP.activity("message") +async def on_message(context: TurnContext, _): + await context.send_activity(f"you said: {context.activity.text}") diff --git a/test_samples/tethered-agent/src/main.py b/test_samples/tethered-agent/src/main.py new file mode 100644 index 000000000..164d898c6 --- /dev/null +++ b/test_samples/tethered-agent/src/main.py @@ -0,0 +1,16 @@ +import tethered + +tethered.activate(allow=[ + "login.microsoftonline.com", + "login.botframework.*", + "api.botframework.*", + "www.botframework.", +]) + +from .agent import AGENT_APP, CONNECTION_MANAGER +from .start_server import start_server + +start_server( + agent_application=AGENT_APP, + auth_configuration=CONNECTION_MANAGER.get_default_connection_configuration(), +) diff --git a/test_samples/tethered-agent/src/start_server.py b/test_samples/tethered-agent/src/start_server.py new file mode 100644 index 000000000..d76b619eb --- /dev/null +++ b/test_samples/tethered-agent/src/start_server.py @@ -0,0 +1,32 @@ +from os import environ +from microsoft_agents.hosting.core import AgentApplication, AgentAuthConfiguration +from microsoft_agents.hosting.aiohttp import ( + start_agent_process, + jwt_authorization_middleware, + CloudAdapter, +) +from aiohttp.web import Request, Response, Application, run_app + + +def start_server( + agent_application: AgentApplication, auth_configuration: AgentAuthConfiguration +): + async def entry_point(req: Request) -> Response: + agent: AgentApplication = req.app["agent_app"] + adapter: CloudAdapter = req.app["adapter"] + return await start_agent_process( + req, + agent, + adapter, + ) + + APP = Application(middlewares=[jwt_authorization_middleware]) + APP.router.add_post("/api/messages", entry_point) + APP["agent_configuration"] = auth_configuration + APP["agent_app"] = agent_application + APP["adapter"] = agent_application.adapter + + try: + run_app(APP, host="localhost", port=environ.get("PORT", 3978)) + except Exception as error: + raise error