From 23b25cf05a14e1bec6c27d038259aafdb999d6c1 Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Fri, 10 Apr 2026 13:29:34 -0700 Subject: [PATCH 1/2] Removing cross sdk tests from this repo --- dev/testing/cross-sdk-tests/.gitignore | 244 -- dev/testing/cross-sdk-tests/__init__.py | 0 .../agents/core-agent/README.md | 3 - .../agents/core-agent/python/README.md | 82 - .../agents/core-agent/python/__init__.py | 0 .../agents/core-agent/python/env.TEMPLATE | 8 - .../core-agent/python/pre_requirements.txt | 8 - .../agents/core-agent/python/requirements.txt | 9 - .../agents/core-agent/python/src/__init__.py | 0 .../agents/core-agent/python/src/agent.py | 313 -- .../agents/core-agent/python/src/app.py | 98 - .../agents/core-agent/python/src/config.py | 18 - .../core-agent/python/src/weather/__init__.py | 0 .../python/src/weather/agents/__init__.py | 0 .../weather/agents/weather_forecast_agent.py | 110 - .../python/src/weather/plugins/__init__.py | 9 - .../weather/plugins/adaptive_card_plugin.py | 33 - .../src/weather/plugins/date_time_plugin.py | 31 - .../src/weather/plugins/weather_forecast.py | 7 - .../plugins/weather_forecast_plugin.py | 26 - .../agents/quickstart/README.md | 3 - .../agents/quickstart/js/_run_agent.ps1 | 4 - .../agents/quickstart/js/env.TEMPLATE | 9 - .../agents/quickstart/js/package-lock.json | 3077 ----------------- .../agents/quickstart/js/package.json | 29 - .../agents/quickstart/js/src/index.ts | 42 - .../agents/quickstart/js/tsconfig.json | 20 - .../agents/quickstart/net/AspNetExtensions.cs | 270 -- .../agents/quickstart/net/MyAgent.cs | 36 - .../agents/quickstart/net/Program.cs | 51 - .../agents/quickstart/net/Quickstart.csproj | 15 - .../agents/quickstart/net/_run_agent.ps1 | 2 - .../agents/quickstart/python/_run_agent.ps1 | 6 - .../agents/quickstart/python/env.TEMPLATE | 0 .../agents/quickstart/python/requirements.txt | 3 - .../agents/quickstart/python/src/__init__.py | 0 .../agents/quickstart/python/src/agent.py | 62 - .../agents/quickstart/python/src/main.py | 10 - .../quickstart/python/src/start_server.py | 39 - dev/testing/cross-sdk-tests/env.TEMPLATE | 5 - dev/testing/cross-sdk-tests/pytest.ini | 33 - dev/testing/cross-sdk-tests/tests/__init__.py | 0 .../cross-sdk-tests/tests/_common/__init__.py | 12 - .../tests/_common/constants.py | 7 - .../tests/_common/source_scenario.py | 78 - .../cross-sdk-tests/tests/_common/types.py | 7 - .../cross-sdk-tests/tests/_common/utils.py | 21 - .../cross-sdk-tests/tests/basic/__init__.py | 0 .../tests/basic/test_quickstart.py | 71 - .../cross-sdk-tests/tests/core/__init__.py | 0 .../tests/core/test_basic_agent_base.py | 33 - .../tests/core/test_directline.py | 454 --- .../tests/core/test_msteams.py | 746 ---- .../tests/core/test_webchat.py | 455 --- .../tests/telemetry/__init__.py | 0 .../tests/telemetry/test_basic_telemetry.py | 28 - 56 files changed, 6627 deletions(-) delete mode 100644 dev/testing/cross-sdk-tests/.gitignore delete mode 100644 dev/testing/cross-sdk-tests/__init__.py delete mode 100644 dev/testing/cross-sdk-tests/agents/core-agent/README.md delete mode 100644 dev/testing/cross-sdk-tests/agents/core-agent/python/README.md delete mode 100644 dev/testing/cross-sdk-tests/agents/core-agent/python/__init__.py delete mode 100644 dev/testing/cross-sdk-tests/agents/core-agent/python/env.TEMPLATE delete mode 100644 dev/testing/cross-sdk-tests/agents/core-agent/python/pre_requirements.txt delete mode 100644 dev/testing/cross-sdk-tests/agents/core-agent/python/requirements.txt delete mode 100644 dev/testing/cross-sdk-tests/agents/core-agent/python/src/__init__.py delete mode 100644 dev/testing/cross-sdk-tests/agents/core-agent/python/src/agent.py delete mode 100644 dev/testing/cross-sdk-tests/agents/core-agent/python/src/app.py delete mode 100644 dev/testing/cross-sdk-tests/agents/core-agent/python/src/config.py delete mode 100644 dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/__init__.py delete mode 100644 dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/agents/__init__.py delete mode 100644 dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/agents/weather_forecast_agent.py delete mode 100644 dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/__init__.py delete mode 100644 dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/adaptive_card_plugin.py delete mode 100644 dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/date_time_plugin.py delete mode 100644 dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/weather_forecast.py delete mode 100644 dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/weather_forecast_plugin.py delete mode 100644 dev/testing/cross-sdk-tests/agents/quickstart/README.md delete mode 100644 dev/testing/cross-sdk-tests/agents/quickstart/js/_run_agent.ps1 delete mode 100644 dev/testing/cross-sdk-tests/agents/quickstart/js/env.TEMPLATE delete mode 100644 dev/testing/cross-sdk-tests/agents/quickstart/js/package-lock.json delete mode 100644 dev/testing/cross-sdk-tests/agents/quickstart/js/package.json delete mode 100644 dev/testing/cross-sdk-tests/agents/quickstart/js/src/index.ts delete mode 100644 dev/testing/cross-sdk-tests/agents/quickstart/js/tsconfig.json delete mode 100644 dev/testing/cross-sdk-tests/agents/quickstart/net/AspNetExtensions.cs delete mode 100644 dev/testing/cross-sdk-tests/agents/quickstart/net/MyAgent.cs delete mode 100644 dev/testing/cross-sdk-tests/agents/quickstart/net/Program.cs delete mode 100644 dev/testing/cross-sdk-tests/agents/quickstart/net/Quickstart.csproj delete mode 100644 dev/testing/cross-sdk-tests/agents/quickstart/net/_run_agent.ps1 delete mode 100644 dev/testing/cross-sdk-tests/agents/quickstart/python/_run_agent.ps1 delete mode 100644 dev/testing/cross-sdk-tests/agents/quickstart/python/env.TEMPLATE delete mode 100644 dev/testing/cross-sdk-tests/agents/quickstart/python/requirements.txt delete mode 100644 dev/testing/cross-sdk-tests/agents/quickstart/python/src/__init__.py delete mode 100644 dev/testing/cross-sdk-tests/agents/quickstart/python/src/agent.py delete mode 100644 dev/testing/cross-sdk-tests/agents/quickstart/python/src/main.py delete mode 100644 dev/testing/cross-sdk-tests/agents/quickstart/python/src/start_server.py delete mode 100644 dev/testing/cross-sdk-tests/env.TEMPLATE delete mode 100644 dev/testing/cross-sdk-tests/pytest.ini delete mode 100644 dev/testing/cross-sdk-tests/tests/__init__.py delete mode 100644 dev/testing/cross-sdk-tests/tests/_common/__init__.py delete mode 100644 dev/testing/cross-sdk-tests/tests/_common/constants.py delete mode 100644 dev/testing/cross-sdk-tests/tests/_common/source_scenario.py delete mode 100644 dev/testing/cross-sdk-tests/tests/_common/types.py delete mode 100644 dev/testing/cross-sdk-tests/tests/_common/utils.py delete mode 100644 dev/testing/cross-sdk-tests/tests/basic/__init__.py delete mode 100644 dev/testing/cross-sdk-tests/tests/basic/test_quickstart.py delete mode 100644 dev/testing/cross-sdk-tests/tests/core/__init__.py delete mode 100644 dev/testing/cross-sdk-tests/tests/core/test_basic_agent_base.py delete mode 100644 dev/testing/cross-sdk-tests/tests/core/test_directline.py delete mode 100644 dev/testing/cross-sdk-tests/tests/core/test_msteams.py delete mode 100644 dev/testing/cross-sdk-tests/tests/core/test_webchat.py delete mode 100644 dev/testing/cross-sdk-tests/tests/telemetry/__init__.py delete mode 100644 dev/testing/cross-sdk-tests/tests/telemetry/test_basic_telemetry.py diff --git a/dev/testing/cross-sdk-tests/.gitignore b/dev/testing/cross-sdk-tests/.gitignore deleted file mode 100644 index 510e2f50..00000000 --- a/dev/testing/cross-sdk-tests/.gitignore +++ /dev/null @@ -1,244 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates -target/ - -# Cake -/.cake -/version.txt -/PSRunCmds*.ps1 - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -bld/ -[Bb]in/ -[Oo]bj/ -[Ll]og/ -/bin/ -/binSigned/ -/obj/ -Drop/ -target/ -Symbols/ -objd/ -.config/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUNIT -*.VisualState.xml -TestResult.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ -**/Properties/launchSettings.json - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# JustCode is a .NET coding add-in -.JustCode - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -#nodeJS stuff -/node_modules/ - -#local development -appsettings.local.json -appsettings.Development.json -appsettings.Development* -appsettings.Production.json -**/[Aa]ppManifest/*.zip -.deployment - -# JetBrains Rider -*.sln.iml -.idea - -# Mac files -.DS_Store - -# VS Code files -.vscode -src/samples/ModelContextProtocol/GitHubMCPServer/Properties/ServiceDependencies/GitHubMCPServer20250311143114 - Web Deploy/profile.arm.json - -# Claude Code temporary files -tmpclaude* - - -node_modules/ -dist/ -*.env -*.key -*.pem -test-report.xml -tsconfig.tsbuildinfo -devTools/ \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/__init__.py b/dev/testing/cross-sdk-tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/dev/testing/cross-sdk-tests/agents/core-agent/README.md b/dev/testing/cross-sdk-tests/agents/core-agent/README.md deleted file mode 100644 index 2c07f981..00000000 --- a/dev/testing/cross-sdk-tests/agents/core-agent/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Core Agent - -An agent that has various routes to test diverse the Agents SDK core functionalities. \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/agents/core-agent/python/README.md b/dev/testing/cross-sdk-tests/agents/core-agent/python/README.md deleted file mode 100644 index 11278cde..00000000 --- a/dev/testing/cross-sdk-tests/agents/core-agent/python/README.md +++ /dev/null @@ -1,82 +0,0 @@ -# 🤖 Agents SDK Test Framework's Python Bot - -This Python bot is part of the Agents SDK Test Framework. It exercises agent behaviors, validates responses, and helps iterate on integrations with LLMs and tools. - -## Highlights ✨ -- âš™ī¸ Test-runner for validating agent flows and tool/function calling -- 🧠 Integrates with LLM providers (Azure OpenAI, Semantic Kernel) -- đŸ–Ĩī¸ Uses Microsoft Agents SDK packages for hosting and activity management - -## 🚀 Getting Started - -### đŸ› ī¸ Prerequisites -- Python 3.9+ -- `pip` (Python package manager) - -### đŸ“Ļ Installation -1. Install dependencies: - ```powershell - pip install --pre --no-deps -r pre_requirements.txt - pip install -r requirements.txt - ``` -#### â„šī¸ Why are there two installation steps? - -**Dependency installation is split into two steps to ensure reliability and avoid conflicts:** - -- **Step 1:** `pre_requirements.txt` — Installs core Microsoft Agents SDK packages. These may require pre-release flags or special handling, and installing them first (without dependency resolution) helps prevent version clashes. -- **Step 2:** `requirements.txt` — Installs the rest of the project dependencies, after the core packages are in place, to ensure compatibility and a smooth setup. - -This approach helps avoid dependency issues and guarantees all required packages are installed in the correct order. - -### âš™ī¸ Set up Environment Variables -Copy or rename `.envLocal` to `.env` and fill in the required values (keys, endpoints, etc.). - -> 💡 Tip: The repo often uses Azure resources (Azure OpenAI / Bot Service) in examples. - -### â–ļī¸ Running the Agent -Start the agent locally: -```powershell -python app.py -``` - -## 📁 Project Layout -``` -Agent/python/ - agent.py - app.py - config.py - requirements.txt - requirements2.txt - pre_requirements.txt - .env - .envLocal - weather/ - agents/ - weather_forecast_agent.py - weather_forecast_agent_response.py - plugins/ - adaptive_card_plugin.py - date_time_plugin.py - weather_forecast_plugin.py - weather_forecast.py -``` - -This launches the process that hosts the agent and exposes the `/api/messages` endpoint. - -## 📚 Key Dependencies -- `microsoft-agents-hosting-core`, `microsoft-agents-hosting-aiohttp`, `microsoft-agents-activity`, `microsoft-agents-authentication-msal` — Microsoft Agents SDK packages -- `semantic-kernel` — LLM orchestration -- `openai` — Azure OpenAI integration - -## Health & Messaging Endpoints -- Health check: (if exposed) `GET /` should return 200 -- Messaging / activity endpoint: `POST /api/messages` (see `app.py`) - -## Agent Flow 🔁 -1. The test runner accepts scenario inputs (natural language user messages). -2. It forwards activity payloads to the agent runtime. -3. The agent may call functions/tools (e.g., weather, date/time). -4. The runner validates the agent's JSON / Adaptive Card outputs and records results. - -## Contributing -- Open a PR with changes and add a short description of the test scenarios you added or modified. diff --git a/dev/testing/cross-sdk-tests/agents/core-agent/python/__init__.py b/dev/testing/cross-sdk-tests/agents/core-agent/python/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/dev/testing/cross-sdk-tests/agents/core-agent/python/env.TEMPLATE b/dev/testing/cross-sdk-tests/agents/core-agent/python/env.TEMPLATE deleted file mode 100644 index df8f217e..00000000 --- a/dev/testing/cross-sdk-tests/agents/core-agent/python/env.TEMPLATE +++ /dev/null @@ -1,8 +0,0 @@ -CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTID= -CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTSECRET= -CONNECTIONS__SERVICE_CONNECTION__SETTINGS__TENANTID= - -AZURE_OPENAI_ENDPOINT= -AZURE_OPENAI_API_KEY= -AZURE_OPENAI_API_VERSION= -AZURE_OPENAI_DEPLOYMENT_NAME= \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/agents/core-agent/python/pre_requirements.txt b/dev/testing/cross-sdk-tests/agents/core-agent/python/pre_requirements.txt deleted file mode 100644 index 13de107e..00000000 --- a/dev/testing/cross-sdk-tests/agents/core-agent/python/pre_requirements.txt +++ /dev/null @@ -1,8 +0,0 @@ -microsoft-agents-hosting-core -microsoft-agents-hosting-aiohttp -microsoft-agents-authentication-msal -microsoft-agents-activity -microsoft-agents-hosting-teams -microsoft-agents-copilotstudio-client -microsoft-agents-storage-blob -microsoft-agents-storage-cosmos \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/agents/core-agent/python/requirements.txt b/dev/testing/cross-sdk-tests/agents/core-agent/python/requirements.txt deleted file mode 100644 index ddf4b785..00000000 --- a/dev/testing/cross-sdk-tests/agents/core-agent/python/requirements.txt +++ /dev/null @@ -1,9 +0,0 @@ -openai -openai-agents -semantic-kernel -microsoft-agents-hosting-aiohttp -microsoft-agents-authentication-msal -microsoft-agents-hosting-teams -microsoft-agents-copilotstudio-client -microsoft-agents-storage-blob -microsoft-agents-storage-cosmos \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/__init__.py b/dev/testing/cross-sdk-tests/agents/core-agent/python/src/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/agent.py b/dev/testing/cross-sdk-tests/agents/core-agent/python/src/agent.py deleted file mode 100644 index 442b8e76..00000000 --- a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/agent.py +++ /dev/null @@ -1,313 +0,0 @@ -from __future__ import annotations -import json -import re - -from microsoft_agents.hosting.core import ( - AgentApplication, - TurnState, - TurnContext, - MessageFactory, -) -from microsoft_agents.activity import ( - ActivityTypes, - InvokeResponse, - Activity, - ConversationUpdateTypes, - Attachment, - EndOfConversationCodes, - DeliveryModes, -) - -from microsoft_agents.hosting.teams import TeamsActivityHandler - - -from semantic_kernel.contents import ChatHistory -from .weather.agents.weather_forecast_agent import WeatherForecastAgent - -from openai import AsyncAzureOpenAI -import asyncio - - -class Agent: - def __init__(self, client: AsyncAzureOpenAI): - self.client = client - self.multiple_message_pattern = re.compile(r"(\w+)\s+(\d+)") - self.weather_message_pattern = re.compile(r"^w: .*") - - def register_handlers(self, agent_app: AgentApplication[TurnState]): - """Register all handlers with the agent application""" - agent_app.conversation_update(ConversationUpdateTypes.MEMBERS_ADDED)( - self.on_members_added - ) - agent_app.message(self.weather_message_pattern)(self.on_weather_message) - agent_app.message(self.multiple_message_pattern)(self.on_multiple_message) - agent_app.message(re.compile(r"^poem$"))(self.on_poem_message) - agent_app.message(re.compile(r"^end$"))(self.on_end_message) - agent_app.message(re.compile(r"^stream$"))(self.on_stream_message) - agent_app.activity(ActivityTypes.message)(self.on_message) - agent_app.activity(ActivityTypes.invoke)(self.on_invoke) - agent_app.message_reaction("reactionsAdded")(self.on_reaction_added) - agent_app.message_reaction("reactionsRemoved")(self.on_reaction_removed) - agent_app.activity(ActivityTypes.message_update)(self.on_message_edit) - agent_app.activity(ActivityTypes.event)(self.on_event) - - async def on_members_added(self, context: TurnContext, _state: TurnState): - await context.send_activity(MessageFactory.text("Hello and Welcome!")) - - async def on_stream_message(self, context: TurnContext, state: TurnState): - if context.activity.delivery_mode == DeliveryModes.stream: - for x in range(1, 5): - await asyncio.sleep(1) - await context.send_activity("Stream response " + str(x)) - else: - await context.send_activity( - "Activity is not set to stream for delivery mode" - ) - - async def on_weather_message(self, context: TurnContext, state: TurnState): - - context.streaming_response.queue_informative_update( - "Working on a response for you" - ) - - chat_history = state.get_value( - "ConversationState.chatHistory", - ChatHistory, - target_cls=ChatHistory, - ) - - weather_agent = WeatherForecastAgent() - - forecast_response = await weather_agent.invoke_agent( - context.activity.text, chat_history - ) - if forecast_response is None: - context.streaming_response.queue_text_chunk( - "Sorry, I couldn't get the weather forecast at the moment." - ) - await context.streaming_response.end_stream() - return - - if forecast_response.contentType == "AdaptiveCard": - context.streaming_response.set_attachments( - [ - Attachment( - content_type="application/vnd.microsoft.card.adaptive", - content=forecast_response.content, - ) - ] - ) - else: - context.streaming_response.queue_text_chunk(forecast_response.content) - - await context.streaming_response.end_stream() - - async def on_multiple_message(self, context: TurnContext, state: TurnState): - counter = state.get_value( - "ConversationState.counter", - default_value_factory=(lambda: 0), - target_cls=int, - ) - - match = self.multiple_message_pattern.match(context.activity.text) - if not match: - return - word = match.group(1) - count = int(match.group(2)) - for _ in range(count): - await context.send_activity(f"[{counter}] You said: {word}") - counter += 1 - - state.set_value("ConversationState.counter", counter) - await state.save(context) - - async def on_poem_message(self, context: TurnContext, state: TurnState): - try: - context.streaming_response.queue_informative_update( - "Hold on for an awesome poem about Apollo..." - ) - - stream = await self.client.chat.completions.create( - model="gpt-4o", - messages=[ - { - "role": "system", - "content": """ - You are a creative assistant who has deeply studied Greek and Roman Gods, You also know all of the Percy Jackson Series - You write poems about the Greek Gods as they are depicted in the Percy Jackson books. - You format the poems in a way that is easy to read and understand - You break your poems into stanzas - You format your poems in Markdown using double lines to separate stanzas - """, - }, - { - "role": "user", - "content": "Write a poem about the Greek God Apollo as depicted in the Percy Jackson books", - }, - ], - stream=True, - max_tokens=1000, - ) - - async for update in stream: - if len(update.choices) > 0: - delta = update.choices[0].delta - if delta.content: - context.streaming_response.queue_text_chunk(delta.content) - finally: - await context.streaming_response.end_stream() - - async def on_end_message(self, context: TurnContext, state: TurnState): - await context.send_activity("Ending conversation...") - - endOfConversation = Activity.create_end_of_conversation_activity() - endOfConversation.code = EndOfConversationCodes.completed_successfully - await context.send_activity(endOfConversation) - - # Simulate a message handler for Action.Submit - # Waiting for Teams Extension to support Action.Submit - async def on_action_submit(self, context: TurnContext, state: TurnState): - user_text = context.activity.value.get("usertext", "") - if not user_text: - await context.send_activity("No user text provided in the action submit.") - return - await context.send_activity( - "doStuff action submitted " + json.dumps(context.activity.value) - ) - - async def on_action_execute(self, context: TurnContext, state: TurnState): - action = context.activity.value.get("action", {}) - data = action.get("data", {}) - user_text = data.get("usertext", "") - - if not user_text: - await context.send_activity("No user text provided in the action execute.") - return - - invoke_response = InvokeResponse( - status=200, - body={ - "statusCode": 200, - "type": "application/vnd.microsoft.card.adaptive", - "value": {"usertext": user_text}, - }, - ) - - await context.send_activity( - Activity(type=ActivityTypes.invoke_response, value=invoke_response) - ) - - async def on_reaction_added(self, context: TurnContext, state: TurnState): - await context.send_activity( - "Message Reaction Added: " + context.activity.reactions_added[0].type - ) - - async def on_reaction_removed(self, context: TurnContext, state: TurnState): - await context.send_activity( - "Message Reaction Removed: " + context.activity.reactions_removed[0].type - ) - - async def on_message(self, context: TurnContext, state: TurnState): - - if context.activity.value and context.activity.value.get("verb") == "doStuff": - await self.on_action_submit(context, state) - return - - counter = state.get_value( - "ConversationState.counter", - default_value_factory=(lambda: 0), - target_cls=int, - ) - await context.send_activity(f"[{counter}] You said: {context.activity.text}") - counter += 1 - state.set_value("ConversationState.counter", counter) - - await state.save(context) - - async def on_invoke(self, context: TurnContext, state: TurnState): - - # Simulate Teams extensions until implemented - if context.activity.name == "adaptiveCard/action": - await self.on_action_execute(context, state) - elif context.activity.name == "composeExtension/query": - invoke_response = InvokeResponse( - status=200, - body={ - "composeExtension": { - "type": "result", - "attachmentLayout": "list", - "attachments": [ - {"contentType": "test", "contentUrl": "example.com"} - ], - } - }, - ) - - await context.send_activity( - Activity(type=ActivityTypes.invoke_response, value=invoke_response) - ) - elif context.activity.name == "composeExtension/queryLink": - invoke_response = InvokeResponse( - status=200, - body={ - "channelId": "msteams", - "composeExtension": { - "type": "result", - "text": "On Query Link", - }, - }, - ) - await context.send_activity( - Activity(type=ActivityTypes.invoke_response, value=invoke_response) - ) - elif context.activity.name == "composeExtension/selectItem": - value = context.activity.value - invoke_response = InvokeResponse( - status=200, - body={ - "channelId": "msteams", - "composeExtension": { - "type": "result", - "attachmentLayout": "list", - "attachments": [ - { - "contentType": "application/vnd.microsoft.card.thumbnail", - "content": { - "title": f"{value['id']}, {value['version']}" - }, - } - ], - }, - }, - ) - await context.send_activity( - Activity(type=ActivityTypes.invoke_response, value=invoke_response) - ) - else: - invoke_response = InvokeResponse( - status=200, - body={"message": "Invoke received.", "data": context.activity.value}, - ) - - await context.send_activity( - Activity(type=ActivityTypes.invoke_response, value=invoke_response) - ) - - async def on_message_edit(self, context: TurnContext, state: TurnState): - await context.send_activity(f"Message Edited: {context.activity.id}") - - async def on_event(self, context: TurnContext, state: TurnState): - if context.activity.name == "application/vnd.microsoft.meetingStart": - await context.send_activity( - f"Meeting started with ID: {context.activity.value['id']}" - ) - elif context.activity.name == "application/vnd.microsoft.meetingEnd": - await context.send_activity( - f"Meeting ended with ID: {context.activity.value['id']}" - ) - elif ( - context.activity.name == "application/vnd.microsoft.meetingParticipantJoin" - ): - await context.send_activity("Welcome to the meeting!") - else: - await context.send_activity("Received an event: " + context.activity.name) diff --git a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/app.py b/dev/testing/cross-sdk-tests/agents/core-agent/python/src/app.py deleted file mode 100644 index 22e19416..00000000 --- a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/app.py +++ /dev/null @@ -1,98 +0,0 @@ -from __future__ import annotations -import logging -from aiohttp.web import Application, Request, Response, run_app -from dotenv import load_dotenv -from os import environ, path - -from semantic_kernel import Kernel -from semantic_kernel.utils.logging import setup_logging -from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion -from openai import AsyncAzureOpenAI - -from microsoft_agents.hosting.aiohttp import ( - CloudAdapter, - jwt_authorization_middleware, - start_agent_process, -) -from microsoft_agents.hosting.core import ( - Authorization, - AgentApplication, - TurnState, - MemoryStorage, -) -from microsoft_agents.authentication.msal import MsalConnectionManager -from microsoft_agents.activity import ( - load_configuration_from_env, - ConversationUpdateTypes, - ActivityTypes, -) -import re - -from .agent import Agent - -# Load environment variables -load_dotenv() - -# Load configuration -agents_sdk_config = load_configuration_from_env(environ) - -# Initialize storage and connection manager -STORAGE = MemoryStorage() -CONNECTION_MANAGER = MsalConnectionManager(**agents_sdk_config) -ADAPTER = CloudAdapter(connection_manager=CONNECTION_MANAGER) -AUTHORIZATION = Authorization(STORAGE, CONNECTION_MANAGER, **agents_sdk_config) - -# Initialize Semantic Kernel -kernel = Kernel() - -chat_completion = AzureChatCompletion( - deployment_name=environ.get("AZURE_OPENAI_DEPLOYMENT_NAME", "gpt-4o"), - base_url=environ.get("AZURE_OPENAI_ENDPOINT"), - api_key=environ.get("AZURE_OPENAI_API_KEY"), - service_id="adaptive_card_service", -) - -kernel.add_service(chat_completion) - -# Initialize Azure OpenAI client -client = AsyncAzureOpenAI( - api_version=environ.get("AZURE_OPENAI_API_VERSION"), - azure_endpoint=environ.get("AZURE_OPENAI_ENDPOINT"), - api_key=environ.get("AZURE_OPENAI_API_KEY"), -) - -# Initialize Agent Application -AGENT_APP_INSTANCE = AgentApplication[TurnState]( - storage=STORAGE, adapter=ADAPTER, authorization=AUTHORIZATION, **agents_sdk_config -) - -logger = logging.getLogger(__name__) - -# Create and configure the AgentBot -AGENT = Agent(client) -AGENT.register_handlers(AGENT_APP_INSTANCE) - - -# Listen for incoming requests on /api/messages -async def messages(req: Request) -> Response: - agent: AgentApplication = req.app["agent_app"] - adapter: CloudAdapter = req.app["adapter"] - return await start_agent_process( - req, - agent, - adapter, - ) - - -# Create the application -APP = Application(middlewares=[jwt_authorization_middleware]) -APP.router.add_post("/api/messages", messages) -APP["agent_configuration"] = CONNECTION_MANAGER.get_default_connection_configuration() -APP["agent_app"] = AGENT_APP_INSTANCE -APP["adapter"] = ADAPTER - -if __name__ == "__main__": - try: - run_app(APP, host="localhost", port=3978) - except Exception as error: - raise error diff --git a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/config.py b/dev/testing/cross-sdk-tests/agents/core-agent/python/src/config.py deleted file mode 100644 index bd78d1cd..00000000 --- a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/config.py +++ /dev/null @@ -1,18 +0,0 @@ -from os import environ -from microsoft_agents.hosting.core import AuthTypes, AgentAuthConfiguration - - -class DefaultConfig(AgentAuthConfiguration): - """Agent Configuration""" - - def __init__(self) -> None: - self.AUTH_TYPE = AuthTypes.client_secret - self.TENANT_ID = "" or environ.get("TENANT_ID") - self.CLIENT_ID = "" or environ.get("CLIENT_ID") - self.CLIENT_SECRET = "" or environ.get("CLIENT_SECRET") - self.AZURE_OPENAI_API_KEY = "" or environ.get("AZURE_OPENAI_API_KEY") - self.AZURE_OPENAI_ENDPOINT = "" or environ.get("AZURE_OPENAI_ENDPOINT") - self.AZURE_OPENAI_API_VERSION = "" or environ.get( - "AZURE_OPENAI_API_VERSION", "2024-06-01" - ) - self.PORT = 3978 diff --git a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/__init__.py b/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/agents/__init__.py b/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/agents/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/agents/weather_forecast_agent.py b/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/agents/weather_forecast_agent.py deleted file mode 100644 index b7a2d46c..00000000 --- a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/agents/weather_forecast_agent.py +++ /dev/null @@ -1,110 +0,0 @@ -import json -import os -from typing import Union, Literal, Any - -from pydantic import BaseModel - -from semantic_kernel import Kernel -from semantic_kernel.connectors.ai.open_ai import OpenAIPromptExecutionSettings -from semantic_kernel.connectors.ai.function_choice_behavior import ( - FunctionChoiceBehavior, -) -from semantic_kernel.functions import KernelArguments -from semantic_kernel.contents import ChatHistory -from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion -from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread - -from ..plugins import DateTimePlugin, WeatherForecastPlugin, AdaptiveCardPlugin - - -class WeatherForecastAgentResponse(BaseModel): - contentType: str = Literal["Text", "AdaptiveCard"] - content: Union[dict, str] - - -class WeatherForecastAgent: - - agent_name = "WeatherForecastAgent" - - agent_instructions = """ - You are a friendly assistant that helps people find a weather forecast for a given time and place. - You may ask follow up questions until you have enough information to answer the customers question, - but once you have a forecast forecast, make sure to format it nicely using an adaptive card. - You should use adaptive JSON format to display the information in a visually appealing way - You should include a button for more details that points at https://www.msn.com/en-us/weather/forecast/in-{location} (replace {location} with the location the user asked about). - You should use adaptive cards version 1.5 or later. - - Respond only in JSON format with the following JSON schema: - - { - "contentType": "'Text' or 'AdaptiveCard' only", - "content": "{The content of the response, may be plain text, or JSON based adaptive card}" - } - """ - - def __init__(self, client: AzureChatCompletion | None = None): - - if not client: - client = AzureChatCompletion( - api_version=os.environ["AZURE_OPENAI_API_VERSION"], - endpoint=os.environ["AZURE_OPENAI_ENDPOINT"], - api_key=os.environ["AZURE_OPENAI_API_KEY"], - deployment_name=os.environ.get( - "AZURE_OPENAI_DEPLOYMENT_NAME", "gpt-4o" - ), - ) - - self.client = client - - execution_settings = OpenAIPromptExecutionSettings() - execution_settings.function_choice_behavior = FunctionChoiceBehavior.Auto() - execution_settings.temperature = 0 - execution_settings.top_p = 1 - self.execution_settings = execution_settings - - async def invoke_agent( - self, input: str, chat_history: ChatHistory - ) -> dict[str, Any]: - - thread = ChatHistoryAgentThread() - kernel = Kernel() - - chat_history.add_user_message(input) - - agent = ChatCompletionAgent( - service=self.client, - name=WeatherForecastAgent.agent_name, - instructions=WeatherForecastAgent.agent_instructions, - kernel=kernel, - arguments=KernelArguments( - settings=self.execution_settings, - ), - ) - - agent.kernel.add_plugin(plugin=DateTimePlugin(), plugin_name="datetime") - kernel.add_plugin(plugin=AdaptiveCardPlugin(), plugin_name="adaptiveCard") - kernel.add_plugin(plugin=WeatherForecastPlugin(), plugin_name="weatherForecast") - - resp: str = "" - - async for chat in agent.invoke(chat_history.to_prompt(), thread=thread): - chat_history.add_message(chat.content) - resp += chat.content.content - - # if resp has a json\n prefix, remove it - if "json\n" in resp: - resp = resp.replace("json\n", "") - resp = resp.replace("```", "") - - resp = resp.strip() - - try: - json_node: dict = json.loads(resp) - result = WeatherForecastAgentResponse.model_validate(json_node) - return result - except Exception as e: - return await self.invoke_agent( - "That response did not match the expected format. Please try again. Error: " - + str(e), - chat_history, - ) diff --git a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/__init__.py b/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/__init__.py deleted file mode 100644 index 3638b566..00000000 --- a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -from .date_time_plugin import DateTimePlugin -from .weather_forecast_plugin import WeatherForecastPlugin -from .adaptive_card_plugin import AdaptiveCardPlugin - -__all__ = [ - "DateTimePlugin", - "WeatherForecastPlugin", - "AdaptiveCardPlugin", -] diff --git a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/adaptive_card_plugin.py b/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/adaptive_card_plugin.py deleted file mode 100644 index 33814600..00000000 --- a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/adaptive_card_plugin.py +++ /dev/null @@ -1,33 +0,0 @@ -from semantic_kernel.functions import kernel_function -from semantic_kernel.connectors.ai.open_ai import OpenAIPromptExecutionSettings -from semantic_kernel.contents import ChatHistory -from os import environ, path -from semantic_kernel import Kernel - - -class AdaptiveCardPlugin: - - @kernel_function() - async def get_adaptive_card_for_data(self, data: str, kernel) -> str: - - instructions = """ - When given data about the weather forecast for a given time and place, generate an adaptive card - that displays the information in a visually appealing way. Only return the valid adaptive card - JSON string in the response. - """ - - # Set up chat - chat = ChatHistory(instructions=instructions) - chat.add_user_message(data) - - chat_completion = kernel.get_service("adaptive_card_service") - - # Get the response - result = await chat_completion.get_chat_message_contents( - chat, OpenAIPromptExecutionSettings() - ) - - # Extract the message text (if result is a list of ChatMessageContent) - message = result[0].content if result else "No response" - - return message diff --git a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/date_time_plugin.py b/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/date_time_plugin.py deleted file mode 100644 index bd115f79..00000000 --- a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/date_time_plugin.py +++ /dev/null @@ -1,31 +0,0 @@ -from semantic_kernel.functions import kernel_function -from datetime import date -from datetime import datetime - - -class DateTimePlugin: - - @kernel_function( - name="today", - description="Get the current date", - ) - def today(self, formatProvider: str) -> str: - """ - Get the current date - """ - - _today = date.today() - formatted_date = _today.strftime(formatProvider) - return formatted_date - - @kernel_function( - name="now", - description="Get the current date and time in the local time zone", - ) - def now(self, formatProvider: str) -> str: - """ - Get the current date and time in the local time zone - """ - date_time = datetime.now() - formatted_date_time = date_time.strftime(formatProvider) - return formatted_date_time diff --git a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/weather_forecast.py b/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/weather_forecast.py deleted file mode 100644 index 49f1c78a..00000000 --- a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/weather_forecast.py +++ /dev/null @@ -1,7 +0,0 @@ -from pydantic import BaseModel - - -class WeatherForecast(BaseModel): - date: str - temperatureC: int - temperatureF: int diff --git a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/weather_forecast_plugin.py b/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/weather_forecast_plugin.py deleted file mode 100644 index 757dd6f1..00000000 --- a/dev/testing/cross-sdk-tests/agents/core-agent/python/src/weather/plugins/weather_forecast_plugin.py +++ /dev/null @@ -1,26 +0,0 @@ -from semantic_kernel.functions import kernel_function -from .weather_forecast import WeatherForecast -import random -from typing import Annotated - - -class WeatherForecastPlugin: - - @kernel_function( - name="get_forecast_for_date", - description="Get a weather forecast for a specific date and location", - ) - def get_forecast_for_date( - self, - date: Annotated[str, "The date for the forecast (e.g., '2025-08-01')"], - location: Annotated[str, "The location for the forecast (e.g., 'Seattle, WA'"], - ) -> Annotated[ - WeatherForecast, "Weather forecast object with temperature and date" - ]: - - temperatureC = int(random.uniform(15, 30)) - temperatureF = int((temperatureC * 9 / 5) + 32) - - return WeatherForecast( - date=date, temperatureC=temperatureC, temperatureF=temperatureF - ) diff --git a/dev/testing/cross-sdk-tests/agents/quickstart/README.md b/dev/testing/cross-sdk-tests/agents/quickstart/README.md deleted file mode 100644 index e37735c2..00000000 --- a/dev/testing/cross-sdk-tests/agents/quickstart/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Quickstart Agent - -This agent echos responses back to the user. As presently configured, the agent enables JWT token validation. \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/agents/quickstart/js/_run_agent.ps1 b/dev/testing/cross-sdk-tests/agents/quickstart/js/_run_agent.ps1 deleted file mode 100644 index 0970ac91..00000000 --- a/dev/testing/cross-sdk-tests/agents/quickstart/js/_run_agent.ps1 +++ /dev/null @@ -1,4 +0,0 @@ -npm install - -npm run build -npm run start:anon \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/agents/quickstart/js/env.TEMPLATE b/dev/testing/cross-sdk-tests/agents/quickstart/js/env.TEMPLATE deleted file mode 100644 index e170043b..00000000 --- a/dev/testing/cross-sdk-tests/agents/quickstart/js/env.TEMPLATE +++ /dev/null @@ -1,9 +0,0 @@ -# rename to .env -connections__serviceConnection__settings__clientId= # App ID of the App Registration used to log in. -connections__serviceConnection__settings__clientSecret= # Client secret of the App Registration used to log in -connections__serviceConnection__settings__tenantId= # Tenant ID of the App Registration used to log in - -connectionsMap__0__connection=serviceConnection -connectionsMap__0__serviceUrl=* - -DEBUG=agents:*:error \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/agents/quickstart/js/package-lock.json b/dev/testing/cross-sdk-tests/agents/quickstart/js/package-lock.json deleted file mode 100644 index 64fc102a..00000000 --- a/dev/testing/cross-sdk-tests/agents/quickstart/js/package-lock.json +++ /dev/null @@ -1,3077 +0,0 @@ -{ - "name": "node-empty-agent", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "node-empty-agent", - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "@microsoft/agents-hosting-express": "^1.1.0" - }, - "devDependencies": { - "@microsoft/m365agentsplayground": "^0.2.16", - "@types/node": "^22.15.18", - "npm-run-all": "^4.1.5", - "typescript": "^5.8.3" - } - }, - "node_modules/@azure/abort-controller": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", - "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", - "license": "MIT", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/core-auth": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.10.1.tgz", - "integrity": "sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==", - "license": "MIT", - "dependencies": { - "@azure/abort-controller": "^2.1.2", - "@azure/core-util": "^1.13.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@azure/core-util": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.13.1.tgz", - "integrity": "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==", - "license": "MIT", - "dependencies": { - "@azure/abort-controller": "^2.1.2", - "@typespec/ts-http-runtime": "^0.3.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@azure/msal-common": { - "version": "15.13.3", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.13.3.tgz", - "integrity": "sha512-shSDU7Ioecya+Aob5xliW9IGq1Ui8y4EVSdWGyI1Gbm4Vg61WpP95LuzcY214/wEjSn6w4PZYD4/iVldErHayQ==", - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@azure/msal-node": { - "version": "3.8.4", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-3.8.4.tgz", - "integrity": "sha512-lvuAwsDpPDE/jSuVQOBMpLbXuVuLsPNRwWCyK3/6bPlBk0fGWegqoZ0qjZclMWyQ2JNvIY3vHY7hoFmFmFQcOw==", - "license": "MIT", - "dependencies": { - "@azure/msal-common": "15.13.3", - "jsonwebtoken": "^9.0.0", - "uuid": "^8.3.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@microsoft/agents-activity": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@microsoft/agents-activity/-/agents-activity-1.1.1.tgz", - "integrity": "sha512-L7PHEHKFge99aIxV9eA7uFY3n9goYKzxcWaqLXGmxq3wMsau8hdsPzZgpV77LOQWQynLO3M5cbD8AavcVZszlQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.3", - "uuid": "^11.1.0", - "zod": "3.25.75" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@microsoft/agents-activity/node_modules/uuid": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", - "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "uuid": "dist/esm/bin/uuid" - } - }, - "node_modules/@microsoft/agents-hosting": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@microsoft/agents-hosting/-/agents-hosting-1.1.1.tgz", - "integrity": "sha512-ZO/BU0d/NxSlbg/W4SvtHDvwS4GDYrMG5CpBh+m2vnqkl6tphM0kkfbSYZFef0BoftrinOdPZcSvdvmVqpbM2w==", - "license": "MIT", - "dependencies": { - "@azure/core-auth": "^1.10.1", - "@azure/msal-node": "^3.8.2", - "@microsoft/agents-activity": "1.1.1", - "axios": "^1.13.2", - "jsonwebtoken": "^9.0.2", - "jwks-rsa": "^3.2.0", - "object-path": "^0.11.8" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@microsoft/agents-hosting-express": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@microsoft/agents-hosting-express/-/agents-hosting-express-1.1.1.tgz", - "integrity": "sha512-CDStIx23U2zyS/4nZoeVgrVlVbQ+EasoqR2dLq7IfU4rUyuUrKGPdlO55rcfS6Z/spLkhCnX35jbD6EBqrTkJg==", - "license": "MIT", - "dependencies": { - "@microsoft/agents-hosting": "1.1.1", - "express": "^5.1.0" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@microsoft/m365agentsplayground": { - "version": "0.2.18", - "resolved": "https://registry.npmjs.org/@microsoft/m365agentsplayground/-/m365agentsplayground-0.2.18.tgz", - "integrity": "sha512-8okNQ+fNQPPMBW/OSIudoCApBKqKxADNFIMivUGy/eaX9v8tFIG/gFo7DLwpaCzNuc1M8oOW9Sse1mX08Dxo0A==", - "dev": true, - "bin": { - "agentsplayground": "cli.js", - "teamsapptester": "cli.js" - } - }, - "node_modules/@types/body-parser": { - "version": "1.19.6", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz", - "integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==", - "license": "MIT", - "dependencies": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "node_modules/@types/connect": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", - "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/express": { - "version": "4.17.25", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.25.tgz", - "integrity": "sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==", - "license": "MIT", - "dependencies": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.33", - "@types/qs": "*", - "@types/serve-static": "^1" - } - }, - "node_modules/@types/express-serve-static-core": { - "version": "4.19.7", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.7.tgz", - "integrity": "sha512-FvPtiIf1LfhzsaIXhv/PHan/2FeQBbtBDtfX2QfvPxdUelMDEckK08SM6nqo1MIZY3RUlfA+HV8+hFUSio78qg==", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*", - "@types/send": "*" - } - }, - "node_modules/@types/http-errors": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", - "integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==", - "license": "MIT" - }, - "node_modules/@types/jsonwebtoken": { - "version": "9.0.10", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.10.tgz", - "integrity": "sha512-asx5hIG9Qmf/1oStypjanR7iKTv0gXQ1Ov/jfrX6kS/EO0OFni8orbmGCn0672NHR3kXHwpAwR+B368ZGN/2rA==", - "license": "MIT", - "dependencies": { - "@types/ms": "*", - "@types/node": "*" - } - }, - "node_modules/@types/mime": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", - "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "license": "MIT" - }, - "node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "22.18.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.18.1.tgz", - "integrity": "sha512-rzSDyhn4cYznVG+PCzGe1lwuMYJrcBS1fc3JqSa2PvtABwWo+dZ1ij5OVok3tqfpEBCBoaR4d7upFJk73HRJDw==", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@types/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==", - "license": "MIT" - }, - "node_modules/@types/range-parser": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", - "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "license": "MIT" - }, - "node_modules/@types/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz", - "integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==", - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/serve-static": { - "version": "1.15.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz", - "integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==", - "license": "MIT", - "dependencies": { - "@types/http-errors": "*", - "@types/node": "*", - "@types/send": "<1" - } - }, - "node_modules/@types/serve-static/node_modules/@types/send": { - "version": "0.17.6", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz", - "integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==", - "license": "MIT", - "dependencies": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "node_modules/@typespec/ts-http-runtime": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.2.tgz", - "integrity": "sha512-IlqQ/Gv22xUC1r/WQm4StLkYQmaaTsXAhUVsNE0+xiyf0yRFiH5++q78U3bw6bLKDCTmh0uqKB9eG9+Bt75Dkg==", - "license": "MIT", - "dependencies": { - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/async-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/axios": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", - "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/body-parser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", - "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", - "on-finished": "^2.4.1", - "qs": "^6.14.0", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "license": "BSD-3-Clause" - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", - "dev": true, - "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/content-disposition": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", - "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/cross-spawn": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", - "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", - "dev": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "engines": { - "node": ">=4.8" - } - }, - "node_modules/cross-spawn/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/data-view-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/inspect-js" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.3.0", - "get-proto": "^1.0.1", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.2.1", - "is-set": "^2.0.3", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.1", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.4", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "stop-iteration-iterator": "^1.1.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.19" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-to-primitive": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", - "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", - "dev": true, - "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", - "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.0", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/finalhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", - "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", - "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "dev": true, - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/form-data/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/form-data/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", - "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/has-bigints": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", - "dev": true, - "dependencies": { - "dunder-proto": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/iconv-lite": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", - "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/internal-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", - "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", - "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-async-function": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", - "dev": true, - "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", - "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", - "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-view": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-finalizationregistry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-generator-function": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", - "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "get-proto": "^1.0.0", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", - "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==" - }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", - "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", - "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", - "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "dev": true, - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/jose": { - "version": "4.15.9", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.9.tgz", - "integrity": "sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "node_modules/jsonwebtoken": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", - "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", - "license": "MIT", - "dependencies": { - "jws": "^4.0.1", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=12", - "npm": ">=6" - } - }, - "node_modules/jwa": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", - "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", - "license": "MIT", - "dependencies": { - "buffer-equal-constant-time": "^1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jwks-rsa": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-3.2.0.tgz", - "integrity": "sha512-PwchfHcQK/5PSydeKCs1ylNym0w/SSv8a62DgHJ//7x2ZclCoinlsjAfDxAAbpoTPybOum/Jgy+vkvMmKz89Ww==", - "license": "MIT", - "dependencies": { - "@types/express": "^4.17.20", - "@types/jsonwebtoken": "^9.0.4", - "debug": "^4.3.4", - "jose": "^4.15.4", - "limiter": "^1.1.5", - "lru-memoizer": "^2.2.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/jws": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", - "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", - "license": "MIT", - "dependencies": { - "jwa": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/limiter": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", - "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" - }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", - "license": "MIT" - }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", - "license": "MIT" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", - "license": "MIT" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", - "license": "MIT" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", - "license": "MIT" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "license": "MIT" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", - "license": "MIT" - }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", - "license": "MIT" - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/lru-memoizer": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.3.0.tgz", - "integrity": "sha512-GXn7gyHAMhO13WSKrIiNfztwxodVsP8IoZ3XfrJV4yH2x0/OeTO/FIaAHTY5YekdGgW94njfuKmyyt1E0mR6Ug==", - "license": "MIT", - "dependencies": { - "lodash.clonedeep": "^4.5.0", - "lru-cache": "6.0.0" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", - "dev": true, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", - "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" - }, - "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" - }, - "engines": { - "node": ">= 4" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object-path": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.11.8.tgz", - "integrity": "sha512-YJjNZrlXJFM42wTBn6zgOJVar9KFJvzx6sTWDte8sWZF//cnjl0BxHNpfZx+ZffXX63A9q0b1zsFiBX4g4X5KA==", - "license": "MIT", - "engines": { - "node": ">= 10.12.0" - } - }, - "node_modules/object.assign": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", - "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0", - "has-symbols": "^1.1.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/own-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", - "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.6", - "object-keys": "^1.1.1", - "safe-push-apply": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "dev": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-to-regexp": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", - "integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "dependencies": { - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/pidtree": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", - "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", - "dev": true, - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" - }, - "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", - "integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.7.0", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", - "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", - "dev": true, - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", - "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.1", - "which-builtin-type": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", - "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", - "dev": true, - "dependencies": { - "is-core-module": "^2.16.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/safe-array-concat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", - "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "has-symbols": "^1.1.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-push-apply": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", - "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", - "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", - "dependencies": { - "debug": "^4.3.5", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "mime-types": "^3.0.1", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/serve-static": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", - "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-proto": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", - "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", - "dev": true, - "dependencies": { - "dunder-proto": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shell-quote": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", - "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.22", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.22.tgz", - "integrity": "sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==", - "dev": true - }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/stop-iteration-iterator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", - "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "internal-slot": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/string.prototype.padend": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz", - "integrity": "sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", - "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-data-property": "^1.1.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-object-atoms": "^1.0.0", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", - "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", - "dependencies": { - "content-type": "^1.0.5", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", - "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", - "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.15", - "reflect.getprototypeof": "^1.0.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", - "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typescript": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", - "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/unbox-primitive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", - "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", - "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", - "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", - "dev": true, - "dependencies": { - "is-bigint": "^1.1.0", - "is-boolean-object": "^1.2.1", - "is-number-object": "^1.1.1", - "is-string": "^1.1.1", - "is-symbol": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", - "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", - "dev": true, - "dependencies": { - "call-bound": "^1.0.2", - "function.prototype.name": "^1.1.6", - "has-tostringtag": "^1.0.2", - "is-async-function": "^2.0.0", - "is-date-object": "^1.1.0", - "is-finalizationregistry": "^1.1.0", - "is-generator-function": "^1.0.10", - "is-regex": "^1.2.1", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.1.0", - "which-collection": "^1.0.2", - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "dev": true, - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", - "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, - "node_modules/zod": { - "version": "3.25.75", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.75.tgz", - "integrity": "sha512-OhpzAmVzabPOL6C3A3gpAifqr9MqihV/Msx3gor2b2kviCgcb+HM9SEOpMWwwNp9MRunWnhtAKUoo0AHhjyPPg==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } -} diff --git a/dev/testing/cross-sdk-tests/agents/quickstart/js/package.json b/dev/testing/cross-sdk-tests/agents/quickstart/js/package.json deleted file mode 100644 index e4cdab59..00000000 --- a/dev/testing/cross-sdk-tests/agents/quickstart/js/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "node-empty-agent", - "version": "1.0.0", - "private": true, - "description": "Agents echo bot sample", - "author": "Microsoft", - "license": "MIT", - "main": "./dist/index.js", - "scripts": { - "prebuild": "npm ci", - "build": "tsc --build", - "prestart": "npm run build", - "prestart:anon": "npm run build", - "start:anon": "node ./dist/index.js", - "start": "node --env-file .env ./dist/index.js", - "test-tool": "agentsplayground", - "test": "npm-run-all -p -r start:anon test-tool" - }, - "dependencies": { - "@microsoft/agents-hosting-express": "^1.1.0" - }, - "devDependencies": { - "@microsoft/m365agentsplayground": "^0.2.16", - "@types/node": "^22.15.18", - "npm-run-all": "^4.1.5", - "typescript": "^5.8.3" - }, - "keywords": [] -} \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/agents/quickstart/js/src/index.ts b/dev/testing/cross-sdk-tests/agents/quickstart/js/src/index.ts deleted file mode 100644 index 5796e398..00000000 --- a/dev/testing/cross-sdk-tests/agents/quickstart/js/src/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. -import { ActivityTypes } from '@microsoft/agents-activity'; -import { AgentApplication, AttachmentDownloader, MemoryStorage, TurnContext, TurnState } from '@microsoft/agents-hosting'; -import { startServer } from '@microsoft/agents-hosting-express'; - -// Create custom conversation state properties. This is -// used to store customer properties in conversation state. -interface ConversationState { - count: number; -} -type ApplicationTurnState = TurnState - -// Register IStorage. For development, MemoryStorage is suitable. -// For production Agents, persisted storage should be used so -// that state survives Agent restarts, and operates correctly -// in a cluster of Agent instances. -const storage = new MemoryStorage() - -const downloader = new AttachmentDownloader() - -const agentApp = new AgentApplication({ - storage, - fileDownloaders: [downloader] -}) - -// Display a welcome message when members are added -agentApp.onConversationUpdate('membersAdded', async (context: TurnContext, state: ApplicationTurnState) => { - await context.sendActivity('Hello and Welcome!') -}) - -// Listen for ANY message to be received. MUST BE AFTER ANY OTHER MESSAGE HANDLERS -agentApp.onActivity(ActivityTypes.Message, async (context: TurnContext, state: ApplicationTurnState) => { - // Increment count state - let count = state.conversation.count ?? 0 - state.conversation.count = ++count - - // Echo back users message - await context.sendActivity(`[${count}] You said: ${context.activity.text}`) -}) - -startServer(agentApp) \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/agents/quickstart/js/tsconfig.json b/dev/testing/cross-sdk-tests/agents/quickstart/js/tsconfig.json deleted file mode 100644 index 0e188450..00000000 --- a/dev/testing/cross-sdk-tests/agents/quickstart/js/tsconfig.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "compilerOptions": { - "incremental": true, - "lib": ["ES2021"], - "target": "es2019", - "module": "commonjs", - "declaration": true, - "sourceMap": true, - "composite": true, - "strict": true, - "moduleResolution": "node", - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "rootDir": "src", - "outDir": "dist", - "tsBuildInfoFile": "dist/.tsbuildinfo" - } -} \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/agents/quickstart/net/AspNetExtensions.cs b/dev/testing/cross-sdk-tests/agents/quickstart/net/AspNetExtensions.cs deleted file mode 100644 index 944e6844..00000000 --- a/dev/testing/cross-sdk-tests/agents/quickstart/net/AspNetExtensions.cs +++ /dev/null @@ -1,270 +0,0 @@ -īģŋīģŋ// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using Microsoft.Agents.Authentication; -using Microsoft.Agents.Core; -using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.IdentityModel.Protocols; -using Microsoft.IdentityModel.Protocols.OpenIdConnect; -using Microsoft.IdentityModel.Tokens; -using Microsoft.IdentityModel.Validators; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Globalization; -using System.IdentityModel.Tokens.Jwt; -using System.Linq; -using System.Net.Http; -using System.Threading.Tasks; - -public static class AspNetExtensions -{ - private static readonly ConcurrentDictionary> _openIdMetadataCache = new(); - - /// - /// Adds AspNet token validation typical for ABS/SMBA and agent-to-agent using settings in configuration. - /// - /// - /// - /// Name of the config section to read. - /// Optional logger to use for authentication event logging. - /// - /// This extension reads settings from configuration. If configuration is missing JWT token - /// is not enabled. - ///

The minimum, but typical, configuration is:

- /// - /// "TokenValidation": { - /// "Enabled": boolean, - /// "Audiences": [ - /// "{{ClientId}}" // this is the Client ID used for the Azure Bot - /// ], - /// "TenantId": "{{TenantId}}" - /// } - /// - /// The full options are: - /// - /// "TokenValidation": { - /// "Enabled": boolean, - /// "Audiences": [ - /// "{required:agent-appid}" - /// ], - /// "TenantId": "{recommended:tenant-id}", - /// "ValidIssuers": [ - /// "{default:Public-AzureBotService}" - /// ], - /// "IsGov": {optional:false}, - /// "AzureBotServiceOpenIdMetadataUrl": optional, - /// "OpenIdMetadataUrl": optional, - /// "AzureBotServiceTokenHandling": "{optional:true}" - /// "OpenIdMetadataRefresh": "optional-12:00:00" - /// } - /// - ///
- public static void AddAgentAspNetAuthentication(this IServiceCollection services, IConfiguration configuration, string tokenValidationSectionName = "TokenValidation") - { - IConfigurationSection tokenValidationSection = configuration.GetSection(tokenValidationSectionName); - - if (!tokenValidationSection.Exists() || !tokenValidationSection.GetValue("Enabled", true)) - { - // Noop if TokenValidation section missing or disabled. - System.Diagnostics.Trace.WriteLine("AddAgentAspNetAuthentication: Auth disabled"); - return; - } - - services.AddAgentAspNetAuthentication(tokenValidationSection.Get()!); - } - - /// - /// Adds AspNet token validation typical for ABS/SMBA and agent-to-agent. - /// - public static void AddAgentAspNetAuthentication(this IServiceCollection services, TokenValidationOptions validationOptions) - { - AssertionHelpers.ThrowIfNull(validationOptions, nameof(validationOptions)); - - // Must have at least one Audience. - if (validationOptions.Audiences == null || validationOptions.Audiences.Count == 0) - { - throw new ArgumentException($"{nameof(TokenValidationOptions)}:Audiences requires at least one ClientId"); - } - - // Audience values must be GUID's - foreach (var audience in validationOptions.Audiences) - { - if (!Guid.TryParse(audience, out _)) - { - throw new ArgumentException($"{nameof(TokenValidationOptions)}:Audiences values must be a GUID"); - } - } - - // If ValidIssuers is empty, default for ABS Public Cloud - if (validationOptions.ValidIssuers == null || validationOptions.ValidIssuers.Count == 0) - { - validationOptions.ValidIssuers = - [ - "https://api.botframework.com", - "https://sts.windows.net/d6d49420-f39b-4df7-a1dc-d59a935871db/", - "https://login.microsoftonline.com/d6d49420-f39b-4df7-a1dc-d59a935871db/v2.0", - "https://sts.windows.net/f8cdef31-a31e-4b4a-93e4-5f571e91255a/", - "https://login.microsoftonline.com/f8cdef31-a31e-4b4a-93e4-5f571e91255a/v2.0", - "https://sts.windows.net/69e9b82d-4842-4902-8d1e-abc5b98a55e8/", - "https://login.microsoftonline.com/69e9b82d-4842-4902-8d1e-abc5b98a55e8/v2.0", - ]; - - if (!string.IsNullOrEmpty(validationOptions.TenantId) && Guid.TryParse(validationOptions.TenantId, out _)) - { - validationOptions.ValidIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidTokenIssuerUrlTemplateV1, validationOptions.TenantId)); - validationOptions.ValidIssuers.Add(string.Format(CultureInfo.InvariantCulture, AuthenticationConstants.ValidTokenIssuerUrlTemplateV2, validationOptions.TenantId)); - } - } - - // If the `AzureBotServiceOpenIdMetadataUrl` setting is not specified, use the default based on `IsGov`. This is what is used to authenticate ABS tokens. - if (string.IsNullOrEmpty(validationOptions.AzureBotServiceOpenIdMetadataUrl)) - { - validationOptions.AzureBotServiceOpenIdMetadataUrl = validationOptions.IsGov ? AuthenticationConstants.GovAzureBotServiceOpenIdMetadataUrl : AuthenticationConstants.PublicAzureBotServiceOpenIdMetadataUrl; - } - - // If the `OpenIdMetadataUrl` setting is not specified, use the default based on `IsGov`. This is what is used to authenticate Entra ID tokens. - if (string.IsNullOrEmpty(validationOptions.OpenIdMetadataUrl)) - { - validationOptions.OpenIdMetadataUrl = validationOptions.IsGov ? AuthenticationConstants.GovOpenIdMetadataUrl : AuthenticationConstants.PublicOpenIdMetadataUrl; - } - - var openIdMetadataRefresh = validationOptions.OpenIdMetadataRefresh ?? BaseConfigurationManager.DefaultAutomaticRefreshInterval; - - _ = services.AddAuthentication(options => - { - options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; - options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; - }) - .AddJwtBearer(options => - { - options.SaveToken = true; - options.TokenValidationParameters = new TokenValidationParameters - { - ValidateIssuer = true, - ValidateAudience = true, - ValidateLifetime = true, - ClockSkew = TimeSpan.FromMinutes(5), - ValidIssuers = validationOptions.ValidIssuers, - ValidAudiences = validationOptions.Audiences, - ValidateIssuerSigningKey = true, - RequireSignedTokens = true, - }; - - // Using Microsoft.IdentityModel.Validators - options.TokenValidationParameters.EnableAadSigningKeyIssuerValidation(); - - options.Events = new JwtBearerEvents - { - // Create a ConfigurationManager based on the requestor. This is to handle ABS non-Entra tokens. - OnMessageReceived = async context => - { - string authorizationHeader = context.Request.Headers.Authorization.ToString(); - - if (string.IsNullOrEmpty(authorizationHeader)) - { - // Default to AadTokenValidation handling - context.Options.TokenValidationParameters.ConfigurationManager ??= options.ConfigurationManager as BaseConfigurationManager; - await Task.CompletedTask.ConfigureAwait(false); - return; - } - - string[] parts = authorizationHeader?.Split(' ')!; - if (parts.Length != 2 || parts[0] != "Bearer") - { - // Default to AadTokenValidation handling - context.Options.TokenValidationParameters.ConfigurationManager ??= options.ConfigurationManager as BaseConfigurationManager; - await Task.CompletedTask.ConfigureAwait(false); - return; - } - - JwtSecurityToken token = new(parts[1]); - string issuer = token.Claims.FirstOrDefault(claim => claim.Type == AuthenticationConstants.IssuerClaim)?.Value!; - - if (validationOptions.AzureBotServiceTokenHandling && AuthenticationConstants.BotFrameworkTokenIssuer.Equals(issuer)) - { - // Use the Azure Bot authority for this configuration manager - context.Options.TokenValidationParameters.ConfigurationManager = _openIdMetadataCache.GetOrAdd(validationOptions.AzureBotServiceOpenIdMetadataUrl, key => - { - return new ConfigurationManager(validationOptions.AzureBotServiceOpenIdMetadataUrl, new OpenIdConnectConfigurationRetriever(), new HttpClient()) - { - AutomaticRefreshInterval = openIdMetadataRefresh - }; - }); - } - else - { - context.Options.TokenValidationParameters.ConfigurationManager = _openIdMetadataCache.GetOrAdd(validationOptions.OpenIdMetadataUrl, key => - { - return new ConfigurationManager(validationOptions.OpenIdMetadataUrl, new OpenIdConnectConfigurationRetriever(), new HttpClient()) - { - AutomaticRefreshInterval = openIdMetadataRefresh - }; - }); - } - - await Task.CompletedTask.ConfigureAwait(false); - }, - - OnTokenValidated = context => - { - return Task.CompletedTask; - }, - OnForbidden = context => - { - return Task.CompletedTask; - }, - OnAuthenticationFailed = context => - { - return Task.CompletedTask; - } - }; - }); - } - - public class TokenValidationOptions - { - public IList? Audiences { get; set; } - - /// - /// TenantId of the Azure Bot. Optional but recommended. - /// - public string? TenantId { get; set; } - - /// - /// Additional valid issuers. Optional, in which case the Public Azure Bot Service issuers are used. - /// - public IList? ValidIssuers { get; set; } - - /// - /// Can be omitted, in which case public Azure Bot Service and Azure Cloud metadata urls are used. - /// - public bool IsGov { get; set; } = false; - - /// - /// Azure Bot Service OpenIdMetadataUrl. Optional, in which case default value depends on IsGov. - /// - /// - /// - public string? AzureBotServiceOpenIdMetadataUrl { get; set; } - - /// - /// Entra OpenIdMetadataUrl. Optional, in which case default value depends on IsGov. - /// - /// - /// - public string? OpenIdMetadataUrl { get; set; } - - /// - /// Determines if Azure Bot Service tokens are handled. Defaults to true and should always be true until Azure Bot Service sends Entra ID token. - /// - public bool AzureBotServiceTokenHandling { get; set; } = true; - - /// - /// OpenIdMetadata refresh interval. Defaults to 12 hours. - /// - public TimeSpan? OpenIdMetadataRefresh { get; set; } - } -} \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/agents/quickstart/net/MyAgent.cs b/dev/testing/cross-sdk-tests/agents/quickstart/net/MyAgent.cs deleted file mode 100644 index 9e65e5f1..00000000 --- a/dev/testing/cross-sdk-tests/agents/quickstart/net/MyAgent.cs +++ /dev/null @@ -1,36 +0,0 @@ -īģŋīģŋ// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using Microsoft.Agents.Builder; -using Microsoft.Agents.Builder.App; -using Microsoft.Agents.Builder.State; -using Microsoft.Agents.Core.Models; -using System.Threading.Tasks; -using System.Threading; - -namespace QuickStart; - -public class MyAgent : AgentApplication -{ - public MyAgent(AgentApplicationOptions options) : base(options) - { - OnConversationUpdate(ConversationUpdateEvents.MembersAdded, WelcomeMessageAsync); - OnActivity(ActivityTypes.Message, OnMessageAsync, rank: RouteRank.Last); - } - - private async Task WelcomeMessageAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken cancellationToken) - { - foreach (ChannelAccount member in turnContext.Activity.MembersAdded) - { - if (member.Id != turnContext.Activity.Recipient.Id) - { - await turnContext.SendActivityAsync(MessageFactory.Text("Hello and Welcome!"), cancellationToken); - } - } - } - - private async Task OnMessageAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken cancellationToken) - { - await turnContext.SendActivityAsync($"You said: {turnContext.Activity.Text}", cancellationToken: cancellationToken); - } -} \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/agents/quickstart/net/Program.cs b/dev/testing/cross-sdk-tests/agents/quickstart/net/Program.cs deleted file mode 100644 index 24375d2b..00000000 --- a/dev/testing/cross-sdk-tests/agents/quickstart/net/Program.cs +++ /dev/null @@ -1,51 +0,0 @@ -īģŋ -īģŋ// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -using QuickStart; -using Microsoft.Agents.Hosting.AspNetCore; -using Microsoft.Agents.Storage; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; - -WebApplicationBuilder builder = WebApplication.CreateBuilder(args); - -builder.Services.AddHttpClient(); - -// Add AgentApplicationOptions from appsettings section "AgentApplication". -builder.AddAgentApplicationOptions(); - -// Add the AgentApplication, which contains the logic for responding to -// user messages. -builder.AddAgent(); - -// Register IStorage. For development, MemoryStorage is suitable. -// For production Agents, persisted storage should be used so -// that state survives Agent restarts, and operates correctly -// in a cluster of Agent instances. -builder.Services.AddSingleton(); - -// Configure the HTTP request pipeline. - -// Add AspNet token validation for Azure Bot Service and Entra. Authentication is -// configured in the appsettings.json "TokenValidation" section. -builder.Services.AddControllers(); -builder.Services.AddAgentAspNetAuthentication(builder.Configuration); - -WebApplication app = builder.Build(); - -// Enable AspNet authentication and authorization -app.UseAuthentication(); -app.UseAuthorization(); - -// Map GET "/" -app.MapAgentRootEndpoint(); - -// Map the endpoints for all agents using the [AgentInterface] attribute. -// If there is a single IAgent/AgentApplication, the endpoints will be mapped to (e.g. "/api/message"). -app.MapAgentApplicationEndpoints(requireAuth: !app.Environment.IsDevelopment()); - -app.Urls.Add($"http://localhost:3978"); - -app.Run(); diff --git a/dev/testing/cross-sdk-tests/agents/quickstart/net/Quickstart.csproj b/dev/testing/cross-sdk-tests/agents/quickstart/net/Quickstart.csproj deleted file mode 100644 index 14a818ca..00000000 --- a/dev/testing/cross-sdk-tests/agents/quickstart/net/Quickstart.csproj +++ /dev/null @@ -1,15 +0,0 @@ -īģŋ - - - net8.0 - latest - disable - enable - - - - - - - - \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/agents/quickstart/net/_run_agent.ps1 b/dev/testing/cross-sdk-tests/agents/quickstart/net/_run_agent.ps1 deleted file mode 100644 index bca86d74..00000000 --- a/dev/testing/cross-sdk-tests/agents/quickstart/net/_run_agent.ps1 +++ /dev/null @@ -1,2 +0,0 @@ -dotnet build -dotnet run \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/agents/quickstart/python/_run_agent.ps1 b/dev/testing/cross-sdk-tests/agents/quickstart/python/_run_agent.ps1 deleted file mode 100644 index 3dace17f..00000000 --- a/dev/testing/cross-sdk-tests/agents/quickstart/python/_run_agent.ps1 +++ /dev/null @@ -1,6 +0,0 @@ -python -m venv venv -.\venv\Scripts\Activate.ps1 - -pip install -r requirements.txt - -python -m src.main \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/agents/quickstart/python/env.TEMPLATE b/dev/testing/cross-sdk-tests/agents/quickstart/python/env.TEMPLATE deleted file mode 100644 index e69de29b..00000000 diff --git a/dev/testing/cross-sdk-tests/agents/quickstart/python/requirements.txt b/dev/testing/cross-sdk-tests/agents/quickstart/python/requirements.txt deleted file mode 100644 index 0ca6c392..00000000 --- a/dev/testing/cross-sdk-tests/agents/quickstart/python/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -microsoft-agents-hosting-core -microsoft-agents-hosting-aiohttp -microsoft-agents-authentication-msal \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/agents/quickstart/python/src/__init__.py b/dev/testing/cross-sdk-tests/agents/quickstart/python/src/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/dev/testing/cross-sdk-tests/agents/quickstart/python/src/agent.py b/dev/testing/cross-sdk-tests/agents/quickstart/python/src/agent.py deleted file mode 100644 index 33571cbf..00000000 --- a/dev/testing/cross-sdk-tests/agents/quickstart/python/src/agent.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -import re -import sys -import traceback -from dotenv import load_dotenv - -from os import environ -from microsoft_agents.hosting.aiohttp import CloudAdapter -from microsoft_agents.hosting.core import ( - Authorization, - AgentApplication, - TurnState, - TurnContext, - MemoryStorage, -) -from microsoft_agents.authentication.msal import MsalConnectionManager -from microsoft_agents.activity import load_configuration_from_env - -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") -async def on_members_added(context: TurnContext, _state: TurnState): - await context.send_activity( - "Welcome to the empty agent! " - "This agent is designed to be a starting point for your own agent development." - ) - return True - - -@AGENT_APP.message(re.compile(r"^hello$")) -async def on_hello(context: TurnContext, _state: TurnState): - await context.send_activity("Hello!") - - -@AGENT_APP.activity("message") -async def on_message(context: TurnContext, _state: TurnState): - await context.send_activity(f"you said: {context.activity.text}") - - -@AGENT_APP.error -async def on_error(context: TurnContext, error: Exception): - # This check writes out errors to console log .vs. app insights. - # NOTE: In production environment, you should consider logging this to Azure - # application insights. - print(f"\n [on_turn_error] unhandled error: {error}", file=sys.stderr) - traceback.print_exc() - - # Send a message to the user - await context.send_activity("The bot encountered an error or bug.") diff --git a/dev/testing/cross-sdk-tests/agents/quickstart/python/src/main.py b/dev/testing/cross-sdk-tests/agents/quickstart/python/src/main.py deleted file mode 100644 index 9139fe33..00000000 --- a/dev/testing/cross-sdk-tests/agents/quickstart/python/src/main.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. - -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/dev/testing/cross-sdk-tests/agents/quickstart/python/src/start_server.py b/dev/testing/cross-sdk-tests/agents/quickstart/python/src/start_server.py deleted file mode 100644 index 9a747e75..00000000 --- a/dev/testing/cross-sdk-tests/agents/quickstart/python/src/start_server.py +++ /dev/null @@ -1,39 +0,0 @@ -from os import environ -import logging - -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 - -logger = logging.getLogger(__name__) - -def start_server( - agent_application: AgentApplication, auth_configuration: AgentAuthConfiguration -): - async def entry_point(req: Request) -> Response: - - logger.info("Request received at /api/messages endpoint.") - 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 diff --git a/dev/testing/cross-sdk-tests/env.TEMPLATE b/dev/testing/cross-sdk-tests/env.TEMPLATE deleted file mode 100644 index df82361b..00000000 --- a/dev/testing/cross-sdk-tests/env.TEMPLATE +++ /dev/null @@ -1,5 +0,0 @@ -CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTID= -CONNECTIONS__SERVICE_CONNECTION__SETTINGS__CLIENTSECRET= -CONNECTIONS__SERVICE_CONNECTION__SETTINGS__TENANTID= - -LOGGING__LOGLEVEL__microsoft_agents.hosting.core=INFO \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/pytest.ini b/dev/testing/cross-sdk-tests/pytest.ini deleted file mode 100644 index 9908f4bf..00000000 --- a/dev/testing/cross-sdk-tests/pytest.ini +++ /dev/null @@ -1,33 +0,0 @@ -[pytest] -# Pytest configuration for Microsoft Agents for Python - -filterwarnings = - ignore::DeprecationWarning - ignore::PendingDeprecationWarning - ignore::aiohttp.web.NotAppKeyWarning - -# Test discovery configuration -testpaths = tests -python_files = test_*.py *_test.py -python_classes = Test* -python_functions = test_* -asyncio_mode=auto - -# Output configuration -addopts = - --strict-markers - --strict-config - --verbose - --tb=short - --durations=10 - -# Minimum version requirement -minversion = 6.0 - -# Markers for test categorization -markers = - unit: Unit tests - integration: Integration tests - slow: Slow tests that may take longer to run - requires_network: Tests that require network access - requires_auth: Tests that require authentication \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/tests/__init__.py b/dev/testing/cross-sdk-tests/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/dev/testing/cross-sdk-tests/tests/_common/__init__.py b/dev/testing/cross-sdk-tests/tests/_common/__init__.py deleted file mode 100644 index b04ac09c..00000000 --- a/dev/testing/cross-sdk-tests/tests/_common/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -from .types import SDKVersion - -from .utils import ( - create_agent_path, - create_scenario, -) - -__all__ = [ - "create_agent_path", - "create_scenario", - "SDKVersion", -] \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/tests/_common/constants.py b/dev/testing/cross-sdk-tests/tests/_common/constants.py deleted file mode 100644 index 49f5acda..00000000 --- a/dev/testing/cross-sdk-tests/tests/_common/constants.py +++ /dev/null @@ -1,7 +0,0 @@ -import pathlib - -_AGENTS_DIR_NAME = "agents" -AGENTS_PATH = pathlib.Path.cwd() / _AGENTS_DIR_NAME -ENTRY_POINT_NAME = "_run_agent.ps1" - -DEFAULT_LOCAL_AGENT_ENDPOINT = "http://localhost:3978/api/messages" diff --git a/dev/testing/cross-sdk-tests/tests/_common/source_scenario.py b/dev/testing/cross-sdk-tests/tests/_common/source_scenario.py deleted file mode 100644 index c19cb8fd..00000000 --- a/dev/testing/cross-sdk-tests/tests/_common/source_scenario.py +++ /dev/null @@ -1,78 +0,0 @@ -import asyncio -import shutil -import subprocess - -from pathlib import Path - -from collections.abc import AsyncIterator -from contextlib import asynccontextmanager - -from microsoft_agents.testing import ( - ActivityTemplate, - ClientConfig, - ExternalScenario, - ScenarioConfig, -) -from microsoft_agents.testing.core import ClientFactory - -from .constants import DEFAULT_LOCAL_AGENT_ENDPOINT - -_TEMPLATE = { - "channel_id": "webchat", - "locale": "en-US", - "conversation": {"id": "conv1"}, - "from": {"id": "user1", "name": "User"}, - "recipient": {"id": "bot", "name": "Bot"}, -} - -client_config=ClientConfig( - activity_template=ActivityTemplate(_TEMPLATE) -) - -class SourceScenario(ExternalScenario): - """Base class for script-based test scenarios.""" - - def __init__( - self, - script_path: str, - delay: float = 0.0, - config: ScenarioConfig | None = None - ) -> None: - super().__init__(DEFAULT_LOCAL_AGENT_ENDPOINT, config) - self._script_path = Path(script_path) - self._delay = delay - - @asynccontextmanager - async def _run_script(self) -> AsyncIterator[None]: - - script_path = self._script_path.resolve() - - runner = shutil.which("pwsh") or shutil.which("powershell") - if runner is None: - raise FileNotFoundError("Could not find pwsh or powershell in PATH") - - try: - process = subprocess.Popen( - [runner, "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", str(script_path)], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - cwd=script_path.parent, - shell=True, # Needed to ensure the process group is correctly set up for termination - ) - - # wait for the agent to start running - await asyncio.sleep(self._delay) - - yield - - process.terminate() - except Exception as ex: - process.kill() - raise ex - - @asynccontextmanager - async def run(self) -> AsyncIterator[ClientFactory]: - """Start callback server and yield a client factory.""" - async with self._run_script(): - async with super().run() as factory: - yield factory \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/tests/_common/types.py b/dev/testing/cross-sdk-tests/tests/_common/types.py deleted file mode 100644 index 305ef1a3..00000000 --- a/dev/testing/cross-sdk-tests/tests/_common/types.py +++ /dev/null @@ -1,7 +0,0 @@ -from enum import Enum - -class SDKVersion(str, Enum): - - PYTHON = "python" - JS = "js" - NET = "net" \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/tests/_common/utils.py b/dev/testing/cross-sdk-tests/tests/_common/utils.py deleted file mode 100644 index a545d3f6..00000000 --- a/dev/testing/cross-sdk-tests/tests/_common/utils.py +++ /dev/null @@ -1,21 +0,0 @@ -from microsoft_agents.testing import Scenario - -from . import constants -from .source_scenario import SourceScenario -from .types import SDKVersion - -def create_agent_path(agent_name: str, sdk_version: SDKVersion) -> str: - - agent_path = constants.AGENTS_PATH / agent_name / sdk_version.value / constants.ENTRY_POINT_NAME - if not agent_path.exists(): - raise FileNotFoundError(f"Agent path does not exist: {agent_path}") - - return str(agent_path.resolve()) - -def create_scenario(agent_name: str, sdk_version: SDKVersion, delay: float = 5.0) -> Scenario: - - agent_path = create_agent_path(agent_name, sdk_version) - return SourceScenario( - agent_path, - delay=delay, - ) \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/tests/basic/__init__.py b/dev/testing/cross-sdk-tests/tests/basic/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/dev/testing/cross-sdk-tests/tests/basic/test_quickstart.py b/dev/testing/cross-sdk-tests/tests/basic/test_quickstart.py deleted file mode 100644 index 4b43937e..00000000 --- a/dev/testing/cross-sdk-tests/tests/basic/test_quickstart.py +++ /dev/null @@ -1,71 +0,0 @@ -import pytest - -from microsoft_agents.testing import AgentClient - -from tests._common import ( - create_scenario, - SDKVersion, -) - -AGENT_NAME = "quickstart" -PYTHON_SCENARIO = create_scenario(AGENT_NAME, SDKVersion.PYTHON) -NET_SCENARIO = create_scenario(AGENT_NAME, SDKVersion.NET) -JS_SCENARIO = create_scenario(AGENT_NAME, SDKVersion.JS) - -class BaseTestQuickstart: - """Integration tests for the Quickstart scenario.""" - - @pytest.mark.asyncio - async def test_conversation_update(self, agent_client: AgentClient): - """Test sending a conversation update activity.""" - input_activity = agent_client.template.create({ - "type": "conversationUpdate", - "members_added": [ - {"id": "bot-id", "name": "Bot"}, - {"id": "user1", "name": "User"}, - ], - "textFormat": "plain", - "entities": [ - { - "type": "ClientCapabilities", - "requiresBotState": True, - "supportsTts": True - } - ], - "channel_data": {"clientActivityId": 123} - }) - - await agent_client.send(input_activity, wait=10) - agent_client.expect().that_for_one(type="message", text="~Welcome") - - @pytest.mark.asyncio - async def test_send_hello(self, agent_client: AgentClient): - """Test sending a 'hello' message and receiving a response.""" - await agent_client.send("hello", wait=10) - agent_client.expect().that_for_one(type="message", text="Hello!") - - @pytest.mark.asyncio - async def test_send_hi(self, agent_client: AgentClient): - """Test sending a 'hi' message and receiving a response.""" - - await agent_client.send("hi", wait=10) - responses = agent_client.recent() - - assert len(responses) == 2 - assert len(agent_client.history()) == 2 - - agent_client.expect().that_for_one(type="message", text="you said: hi") - agent_client.expect().that_for_one(type="typing") - - -@pytest.mark.agent_test(PYTHON_SCENARIO) -class TestQuickstartPython(BaseTestQuickstart): - pass - -@pytest.mark.agent_test(NET_SCENARIO) -class TestQuickstartNet(BaseTestQuickstart): - pass - -@pytest.mark.agent_test(JS_SCENARIO) -class TestQuickstartJS(BaseTestQuickstart): - pass \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/tests/core/__init__.py b/dev/testing/cross-sdk-tests/tests/core/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/dev/testing/cross-sdk-tests/tests/core/test_basic_agent_base.py b/dev/testing/cross-sdk-tests/tests/core/test_basic_agent_base.py deleted file mode 100644 index 010059c7..00000000 --- a/dev/testing/cross-sdk-tests/tests/core/test_basic_agent_base.py +++ /dev/null @@ -1,33 +0,0 @@ -from microsoft_agents.testing.core.external_scenario import ExternalScenario -import pytest - -from microsoft_agents.testing import ( - ActivityTemplate, - ClientConfig, - ExternalScenario, - ScenarioConfig, -) - -_TEMPLATE = ActivityTemplate({ - "channel_id": "directline", - "locale": "en-US", - "conversation.id": "conv1", - "from.id": "user1", - "from.name": "User", - "recipient.id": "bot", - "recipient.name": "Bot", -}) - -_SCENARIO = ExternalScenario( - "http://localhost:3978/api/messages/", - config=ScenarioConfig( - client_config=ClientConfig( - activity_template=_TEMPLATE - ) - ) -) - -@pytest.mark.skip(reason="Base class for other tests") -@pytest.mark.agent_test(_SCENARIO, agent_name="basic-agent") -class TestBasicAgentBase: - """Base test class for basic agent.""" \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/tests/core/test_directline.py b/dev/testing/cross-sdk-tests/tests/core/test_directline.py deleted file mode 100644 index 8f697a11..00000000 --- a/dev/testing/cross-sdk-tests/tests/core/test_directline.py +++ /dev/null @@ -1,454 +0,0 @@ -import pytest -import asyncio - -from typing import cast - -from microsoft_agents.activity import ( - Activity, - ActivityTypes, - ChannelAccount, - ConversationAccount, - DeliveryModes, - Entity, -) -from microsoft_agents.testing import AgentClient, Expect - -from .test_basic_agent_base import TestBasicAgentBase - - -class TestBasicAgentDirectLine(TestBasicAgentBase): - """Test DirectLine channel for basic agent.""" - - @pytest.mark.asyncio - async def test__send_activity__conversation_update__returns_welcome_message( - self, agent_client: AgentClient - ): - """Test that ConversationUpdate activity returns welcome message.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.conversation_update, - id="activity-conv-update-001", - timestamp="2025-07-30T23:01:11.000Z", - from_property=ChannelAccount(id="user1"), - recipient=ChannelAccount(id="basic-agent", name="basic-agent"), - members_added=[ - ChannelAccount(id="basic-agent", name="basic-agent"), - ChannelAccount(id="user1"), - ], - local_timestamp="2025-07-30T15:59:55.000-07:00", - local_timezone="America/Los_Angeles", - text_format="plain", - attachments=[], - entities=[ - Entity.model_validate({ - "type": "ClientCapabilities", - "requiresBotState": True, - "supportsListening": True, - "supportsTts": True, - }) - ], - channel_data={"clientActivityID": "client-activity-001"}, - )) - - await agent_client.send(activity, wait=1.0) - - agent_client.expect().that_for_one( - type="message", - text="~Hello and Welcome!" - ) - - @pytest.mark.asyncio - async def test__send_activity__sends_hello_world__returns_hello_world( - self, agent_client, response_client - ): - """Test that sending 'hello world' returns echo response.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message, - id="activityA37", - timestamp="2025-07-30T22:59:55.000Z", - text="hello world", - text_format="plain", - attachments=[], - entities=[ - Entity.model_validate({ - "type": "ClientCapabilities", - "requiresBotState": True, - "supportsListening": True, - "supportsTts": True, - }) - ], - channel_data={"clientActivityID": "client-act-id"}, - )) - - await agent_client.send(activity, wait=1.0) - - agent_client.expect().that_for_one( - type="message", - text="~You said: hello world" - ) - - @pytest.mark.asyncio - async def test__send_activity__sends_poem__returns_apollo_poem( - self, agent_client: AgentClient - ): - """Test that sending 'poem' returns poem about Apollo.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message, - delivery_mode=DeliveryModes.expect_replies, - text="poem", - text_format="plain", - attachments=[], - )) - - responses = await agent_client.send_expect_replies(activity) - - await asyncio.sleep(1.0) # Allow time for responses to be processed - - assert len(agent_client.history()) == len(responses), "History length mismatch with expect_replies responses" - - Expect(responses).that_for_one(type=ActivityTypes.typing) - Expect(responses).that_for_one(text="~Apollo") - Expect(responses).that_for_one(text="~Hold on for an awesome poem") - - @pytest.mark.asyncio - async def test__send_activity__sends_seattle_weather__returns_weather( - self, agent_client: AgentClient - ): - """Test that sending 'w: Seattle for today' returns weather data.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message, - text="w: Seattle for today", - mode=DeliveryModes.expect_replies, - )) - await agent_client.send(activity) - agent_client.expect().that_for_any( - type=ActivityTypes.typing - ) - - @pytest.mark.asyncio - async def test__send_activity__sends_message_with_ac_submit__returns_response( - self, agent_client: AgentClient - ): - """Test Action.Submit button on Adaptive Card.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message, - id="activityY1F", - timestamp="2025-07-30T23:06:37.000Z", - attachments=[], - channel_data={ - "postBack": True, - "clientActivityID": "client-act-id", - }, - value={ - "verb": "doStuff", - "id": "doStuff", - "type": "Action.Submit", - "test": "test", - "data": {"name": "test"}, - "usertext": "hello", - }, - )) - - await agent_client.send(activity) - # Expect a response that includes the verb, action type, and user text - agent_client.expect().that_for_any( - type="message", - text=lambda x: "doStuff" in x and "Action.Submit" in x and "hello" in x - ) - - @pytest.mark.asyncio - async def test__send_activity__ends_conversation( - self, agent_client: AgentClient - ): - """Test that sending 'end' ends the conversation.""" - await agent_client.send("end", wait=1.0) - agent_client.expect()\ - .that_for_any(type=ActivityTypes.message)\ - .that_for_any(type=ActivityTypes.end_of_conversation)\ - .that_for_any(text="~Ending conversation") - - @pytest.mark.asyncio - async def test__send_activity__message_reaction_heart_added( - self, agent_client: AgentClient - ): - """Test that adding heart reaction returns reaction acknowledgement.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message_reaction, - timestamp="2025-07-10T02:25:04.000Z", - id="1752114287789", - from_property=ChannelAccount(id="from29ed", aad_object_id="aad-user1"), - conversation=ConversationAccount( - conversation_type="personal", - tenant_id="tenant6d4", - id="cpersonal-chat-id", - ), - recipient=ChannelAccount(id="basic-agent", name="basic-agent"), - channel_data={ - "tenant": {"id": "tenant6d4"}, - "legacy": {"replyToId": "legacy_id"}, - }, - reactions_added=[{"type": "heart"}], - reply_to_id="1752114287789", - )) - - await agent_client.send(activity, wait=1.0) - agent_client.expect().that_for_one( - type=ActivityTypes.message, - text="~Message Reaction Added: heart" - ) - - @pytest.mark.asyncio - async def test__send_activity__message_reaction_heart_removed( - self, agent_client: AgentClient, - ): - """Test that removing heart reaction returns reaction acknowledgement.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message_reaction, - timestamp="2025-07-10T02:25:04.000Z", - id="1752114287789", - from_property=ChannelAccount(id="from29ed", aad_object_id="aad-user1"), - conversation=ConversationAccount( - conversation_type="personal", - tenant_id="tenant6d4", - id="cpersonal-chat-id", - ), - recipient=ChannelAccount(id="basic-agent", name="basic-agent"), - channel_data={ - "tenant": {"id": "tenant6d4"}, - "legacy": {"replyToId": "legacy_id"}, - }, - reactions_removed=[{"type": "heart"}], - reply_to_id="1752114287789", - )) - - await agent_client.send(activity, wait=1.0) - agent_client.expect().that_for_any( - type="message", - text="~Message Reaction Removed: heart" - ) - - @pytest.mark.asyncio - async def test__send_expected_replies__sends_poem__returns_poem( - self, agent_client: AgentClient - ): - """Test send_expected_replies with poem request.""" - responses = await agent_client.send_expect_replies("poem") - assert len(responses) > 0, "No responses received for expectedReplies" - Expect(responses).that_for_any(text="~Apollo") - - @pytest.mark.asyncio - async def test__send_expected_replies__sends_weather__returns_weather( - self, agent_client: AgentClient - ): - """Test send_expected_replies with weather request.""" - responses = await agent_client.send_expect_replies("w: Seattle for today") - assert len(responses) > 0, "No responses received for expectedReplies" - - @pytest.mark.asyncio - async def test__send_invoke__basic_invoke__returns_response( - self, agent_client: AgentClient - ): - """Test basic invoke activity.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.invoke, - id="invoke456", - from_property=ChannelAccount(id="user-id-0", name="Alex Wilber", aad_object_id="aad-user-alex"), - timestamp="2025-07-22T19:21:03.000Z", - conversation=ConversationAccount( - conversation_type="personal", - tenant_id="tenant-001", - id="personal-chat-id", - ), - recipient=ChannelAccount(id="bot-001", name="Test Bot"), - entities=[ - Entity.model_validate({ - "type": "clientInfo", - "locale": "en-US", - "country": "US", - "platform": "Web", - "timezone": "America/Los_Angeles", - }) - ], - value={ - "parameters": [{"value": "hi"}], - }, - service_url="http://localhost:63676/_connector", - )) - assert activity.type == "invoke" - - response = await agent_client.invoke(activity) - - assert response is not None, "No invoke response received" - assert response.status == 200, f"Unexpected status: {response.status}" - - @pytest.mark.asyncio - async def test__send_invoke__query_link( - self, agent_client: AgentClient - ): - """Test invoke for query link.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.invoke, - id="invoke_query_link", - from_property=ChannelAccount(id="user-id-0"), - name="composeExtension/queryLink", - value={}, - )) - response = await agent_client.invoke(activity) - assert response is not None, "No invoke response received" - assert response.status == 200, f"Unexpected status: {response.status}" - - @pytest.mark.asyncio - async def test__send_invoke__query_package( - self, agent_client: AgentClient - ): - """Test invoke for query package.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.invoke, - id="invoke_query_package", - from_property=ChannelAccount(id="user-id-0"), - name="composeExtension/queryPackage", - value={}, - )) - - response = await agent_client.invoke(activity) - assert response is not None, "No invoke response received" - assert response.status == 200, f"Unexpected status: {response.status}" - - @pytest.mark.asyncio - async def test__send_invoke__select_item__returns_attachment( - self, agent_client: AgentClient - ): - """Test invoke for selectItem to return package details.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.invoke, - id="invoke123", - from_property=ChannelAccount(id="user-id-0", name="Alex Wilber"), - conversation=ConversationAccount( - conversation_type="personal", - tenant_id="tenant-001", - id="personal-chat-id", - ), - recipient=ChannelAccount(id="bot-001", name="Test Bot"), - name="composeExtension/selectItem", - value={ - "@id": "https://www.nuget.org/packages/Newtonsoft.Json/13.0.1", - "id": "Newtonsoft.Json", - "version": "13.0.1", - "description": "Json.NET is a popular high-performance JSON framework for .NET", - "projectUrl": "https://www.newtonsoft.com/json", - "iconUrl": "https://www.newtonsoft.com/favicon.ico", - }, - )) - - response = await agent_client.invoke(activity) - - assert response is not None, "No invoke response received" - assert response.status == 200, f"Unexpected status: {response.status}" - if response.body: - assert "Newtonsoft.Json" in str(response.body), "Package name not in response" - - @pytest.mark.asyncio - async def test__send_invoke__adaptive_card_submit__returns_response( - self, agent_client: AgentClient - ): - """Test invoke for Adaptive Card Action.Submit.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.invoke, - id="ac_invoke_001", - from_property=ChannelAccount(id="user-id-0"), - name="adaptiveCard/action", - value={ - "action": { - "type": "Action.Submit", - "id": "submit-action", - "data": {"usertext": "hi"}, - } - }, - )) - - response = await agent_client.invoke(activity) - assert response is not None, "No invoke response received" - - @pytest.mark.asyncio - async def test__send_activity__sends_hi_5__returns_5_responses( - self, agent_client: AgentClient - ): - """Test that sending 'hi 5' returns 5 message responses.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message, - id="activity989", - timestamp="2025-07-22T19:21:03.000Z", - from_property=ChannelAccount(id="user-id-0", name="Alex Wilber"), - conversation=ConversationAccount( - conversation_type="personal", - tenant_id="tenant-001", - id="personal-chat-id-hi5", - ), - recipient=ChannelAccount(id="bot-001", name="Test Bot"), - text="hi 5", - )) - - responses = await agent_client.send(activity, wait=3.0) - - assert len(responses) >= 5, f"Expected at least 5 responses, got {len(responses)}" - - message_responses = cast(list[Activity], agent_client.select().where(type=ActivityTypes.message).get()) - - # Verify each message contains the expected pattern - for i in range(5): - combined_text = " ".join(r.text or "" for r in message_responses) - assert f"[{i}] You said: hi" in combined_text, f"Expected message [{i}] not found" - - @pytest.mark.asyncio - async def test__send_stream__stream_message__returns_stream_responses( - self, agent_client: AgentClient - ): - """Test streaming message responses.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message, - id="activity-stream-001", - timestamp="2025-06-18T18:47:46.000Z", - from_property=ChannelAccount(id="user1"), - conversation=ConversationAccount(id="conversation-stream-001"), - recipient=ChannelAccount(id="basic-agent", name="basic-agent"), - text="stream", - text_format="plain", - attachments=[], - entities=[ - Entity.model_validate({ - "type": "ClientCapabilities", - "requiresBotState": True, - "supportsListening": True, - "supportsTts": True, - }) - ], - channel_data={"clientActivityID": "client-activity-stream-001"}, - )) - - responses = await agent_client.send(activity, wait=1.0) - # Stream tests just verify responses are received - assert len(responses) > 0, "No stream responses received" - - @pytest.mark.asyncio - async def test__send_activity__simulate_message_loop__weather_query( - self, agent_client: AgentClient, - ): - """Test multiple message exchanges simulating message loop.""" - # First message: weather question - activity1 = agent_client.template.create(dict( - type=ActivityTypes.message, - text="w: what's the weather?", - conversation=ConversationAccount(id="conversation-simulate-002"), - )) - - responses1 = await agent_client.send(activity1, wait=1.0) - assert len(responses1) > 0, "No response to weather question" - - # Second message: location - activity2 = agent_client.template.create(dict( - type=ActivityTypes.message, - text="w: Seattle for today", - conversation=ConversationAccount(id="conversation-simulate-002"), - )) - - responses2 = await agent_client.send(activity2, wait=1.0) - assert len(responses2) > 0, "No response to location message" \ No newline at end of file diff --git a/dev/testing/cross-sdk-tests/tests/core/test_msteams.py b/dev/testing/cross-sdk-tests/tests/core/test_msteams.py deleted file mode 100644 index 6027995f..00000000 --- a/dev/testing/cross-sdk-tests/tests/core/test_msteams.py +++ /dev/null @@ -1,746 +0,0 @@ -import pytest -import asyncio - -from typing import cast - -from microsoft_agents.activity import ( - Activity, - ActivityTypes, - ChannelAccount, - ConversationAccount, - DeliveryModes, - Entity, -) -from microsoft_agents.testing import AgentClient, Expect - -from .test_basic_agent_base import TestBasicAgentBase - - -class TestBasicAgentMSTeams(TestBasicAgentBase): - """Test MSTeams channel for basic agent.""" - - @pytest.mark.asyncio - async def test__send_activity__conversation_update__returns_welcome_message( - self, agent_client: AgentClient - ): - """Test that ConversationUpdate activity returns welcome message.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.conversation_update, - id="activity123", - timestamp="2025-06-23T19:48:15.625+00:00", - service_url="http://localhost:62491/_connector", - from_property=ChannelAccount(id="user-id-0", aad_object_id="aad-user-alex", role="user"), - conversation=ConversationAccount( - conversation_type="personal", - tenant_id="tenant-001", - id="personal-chat-id", - ), - recipient=ChannelAccount(id="bot-001", name="Test Bot"), - members_added=[ - ChannelAccount(id="user-id-0", aad_object_id="aad-user-alex"), - ChannelAccount(id="bot-001"), - ], - members_removed=[], - reactions_added=[], - reactions_removed=[], - attachments=[], - entities=[], - channel_data={ - "tenant": {"id": "tenant-001"}, - }, - listen_for=[], - text_highlights=[], - )) - - await agent_client.send(activity, wait=1.0) - - agent_client.expect().that_for_one( - type="message", - text="~Hello and Welcome!" - ) - - @pytest.mark.asyncio - async def test__send_activity__sends_hello_world__returns_hello_world( - self, agent_client: AgentClient - ): - """Test that sending 'hello world' returns echo response.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message, - id="activity-hello-msteams-001", - timestamp="2025-06-18T18:47:46.000Z", - local_timestamp="2025-06-18T11:47:46.000-07:00", - local_timezone="America/Los_Angeles", - from_property=ChannelAccount(id="user1", name=""), - conversation=ConversationAccount(id="conversation-hello-msteams-001"), - recipient=ChannelAccount(id="basic-agent@sometext", name="basic-agent"), - text_format="plain", - text="hello world", - attachments=[], - entities=[ - Entity.model_validate({ - "type": "ClientCapabilities", - "requiresBotState": True, - "supportsListening": True, - "supportsTts": True, - }) - ], - channel_data={ - "clientActivityID": "client-activity-hello-msteams-001", - }, - )) - - await agent_client.send(activity, wait=1.0) - - agent_client.expect().that_for_one( - type="message", - text="~You said: hello world" - ) - - @pytest.mark.asyncio - async def test__send_activity__sends_poem__returns_apollo_poem( - self, agent_client: AgentClient - ): - """Test that sending 'poem' returns poem about Apollo.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message, - delivery_mode=DeliveryModes.expect_replies, - text="poem", - text_format="plain", - attachments=[], - )) - - responses = await agent_client.send_expect_replies(activity) - - await asyncio.sleep(1.0) # Allow time for responses to be processed - - assert len(agent_client.history()) == len(responses), "History length mismatch with expect_replies responses" - - Expect(responses).that_for_one(type=ActivityTypes.typing) - Expect(responses).that_for_one(text="~Apollo") - Expect(responses).that_for_one(text="~Hold on for an awesome poem") - - @pytest.mark.asyncio - async def test__send_activity__sends_seattle_weather__returns_weather( - self, agent_client: AgentClient - ): - """Test that sending weather query returns weather data.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message, - text="w: Seattle for today", - mode=DeliveryModes.expect_replies, - )) - await agent_client.send(activity) - agent_client.expect().that_for_any( - type=ActivityTypes.typing - ) - - @pytest.mark.asyncio - async def test__send_activity__sends_message_with_ac_submit__returns_response( - self, agent_client: AgentClient - ): - """Test Action.Submit button on Adaptive Card.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message, - id="activity123", - timestamp="2025-06-27T17:24:16.000Z", - local_timestamp="2025-06-27T17:24:16.000Z", - local_timezone="America/Los_Angeles", - service_url="https://smba.trafficmanager.net/amer/", - from_property=ChannelAccount(id="from29ed", name="Basic User", aad_object_id="aad-user1"), - conversation=ConversationAccount( - conversation_type="personal", - tenant_id="tenant6d4", - id="cpersonal-chat-id", - ), - recipient=ChannelAccount(id="basic-agent@sometext", name="basic-agent"), - reply_to_id="activity123", - value={ - "verb": "doStuff", - "id": "doStuff", - "type": "Action.Submit", - "test": "test", - "data": {"name": "test"}, - "usertext": "hello", - }, - channel_data={ - "tenant": {"id": "tenant6d4"}, - "source": {"name": "message"}, - "legacy": {"replyToId": "legacy_id"}, - }, - entities=[ - Entity.model_validate({ - "type": "clientInfo", - "locale": "en-US", - "country": "US", - "platform": "Web", - "timezone": "America/Los_Angeles", - }) - ], - )) - - await agent_client.send(activity) - # Expect a response that includes the verb, action type, and user text - agent_client.expect().that_for_any( - type="message", - text=lambda x: "doStuff" in x and "Action.Submit" in x and "hello" in x - ) - - @pytest.mark.asyncio - async def test__send_activity__ends_conversation( - self, agent_client: AgentClient - ): - """Test that sending 'end' ends the conversation.""" - await agent_client.send("end", wait=1.0) - agent_client.expect()\ - .that_for_any(type=ActivityTypes.message)\ - .that_for_any(type=ActivityTypes.end_of_conversation)\ - .that_for_any(text="~Ending conversation") - - @pytest.mark.asyncio - async def test__send_activity__message_reaction_heart_added( - self, agent_client: AgentClient - ): - """Test that adding heart reaction returns reaction acknowledgement.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message_reaction, - timestamp="2025-07-10T02:25:04.000Z", - id="activity175", - from_property=ChannelAccount(id="from29ed", aad_object_id="aad-user1"), - conversation=ConversationAccount( - conversation_type="personal", - tenant_id="tenant6d4", - id="cpersonal-chat-id", - ), - recipient=ChannelAccount(id="basic-agent@sometext", name="basic-agent"), - channel_data={ - "tenant": {"id": "tenant6d4"}, - "legacy": {"replyToId": "legacy_id"}, - }, - reactions_added=[{"type": "heart"}], - reply_to_id="activity175", - )) - - await agent_client.send(activity, wait=1.0) - agent_client.expect().that_for_one( - type=ActivityTypes.message, - text="~Message Reaction Added: heart" - ) - - @pytest.mark.asyncio - async def test__send_activity__message_reaction_heart_removed( - self, agent_client: AgentClient, - ): - """Test that removing heart reaction returns reaction acknowledgement.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message_reaction, - timestamp="2025-07-10T02:30:00.000Z", - id="activity175", - from_property=ChannelAccount(id="from29ed", aad_object_id="d6dab"), - conversation=ConversationAccount( - conversation_type="personal", - tenant_id="tenant6d4", - id="cpersonal-chat-id", - ), - recipient=ChannelAccount(id="basic-agent@sometext", name="basic-agent"), - channel_data={ - "tenant": {"id": "tenant6d4"}, - "legacy": {"replyToId": "legacy_id"}, - }, - reactions_removed=[{"type": "heart"}], - reply_to_id="activity175", - )) - - await agent_client.send(activity, wait=1.0) - agent_client.expect().that_for_any( - type="message", - text="~Message Reaction Removed: heart" - ) - - @pytest.mark.asyncio - async def test__send_expected_replies__sends_poem__returns_poem( - self, agent_client: AgentClient - ): - """Test send_expected_replies with poem request.""" - responses = await agent_client.send_expect_replies("poem") - assert len(responses) > 0, "No responses received for expectedReplies" - Expect(responses).that_for_any(text="~Apollo") - - @pytest.mark.asyncio - async def test__send_expected_replies__sends_weather__returns_weather( - self, agent_client: AgentClient - ): - """Test send_expected_replies with weather request.""" - responses = await agent_client.send_expect_replies("w: Seattle for today") - assert len(responses) > 0, "No responses received for expectedReplies" - - @pytest.mark.asyncio - async def test__send_invoke__basic_invoke__returns_response( - self, agent_client: AgentClient - ): - """Test basic invoke activity.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.invoke, - id="invoke456", - from_property=ChannelAccount(id="user-id-0", name="Alex Wilber", aad_object_id="aad-user-alex"), - timestamp="2025-07-22T19:21:03.000Z", - conversation=ConversationAccount( - conversation_type="personal", - tenant_id="tenant-001", - id="personal-chat-id", - ), - recipient=ChannelAccount(id="bot-001", name="Test Bot"), - entities=[ - Entity.model_validate({ - "type": "clientInfo", - "locale": "en-US", - "country": "US", - "platform": "Web", - "timezone": "America/Los_Angeles", - }) - ], - value={ - "parameters": [{"value": "hi"}], - }, - service_url="http://localhost:63676/_connector", - )) - assert activity.type == "invoke" - - response = await agent_client.invoke(activity) - - assert response is not None, "No invoke response received" - assert response.status == 200, f"Unexpected status: {response.status}" - - @pytest.mark.asyncio - async def test__send_invoke__query_link( - self, agent_client: AgentClient - ): - """Test invoke for query link.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.invoke, - id="invoke_query_link", - from_property=ChannelAccount(id="user-id-0"), - name="composeExtension/queryLink", - value={ - "url": "https://github.com/microsoft/Agents-for-net/blob/users/tracyboehrer/cards-sample/src/samples/Teams/TeamsAgent/TeamsAgent.cs", - }, - )) - response = await agent_client.invoke(activity) - assert response is not None, "No invoke response received" - - @pytest.mark.asyncio - async def test__send_invoke__query_package( - self, agent_client: AgentClient - ): - """Test invoke for query package.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.invoke, - id="invoke_query_package", - from_property=ChannelAccount(id="user-id-0"), - name="composeExtension/query", - value={ - "commandId": "findNuGetPackage", - "parameters": [ - {"name": "NuGetPackageName", "value": "Newtonsoft.Json"} - ], - "queryOptions": { - "skip": 0, - "count": 10 - }, - }, - )) - - response = await agent_client.invoke(activity) - assert response is not None, "No invoke response received" - - @pytest.mark.asyncio - async def test__send_invoke__select_item__returns_attachment( - self, agent_client: AgentClient - ): - """Test invoke for selectItem to return package details.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.invoke, - id="invoke123", - from_property=ChannelAccount(id="user-id-0", name="Alex Wilber"), - conversation=ConversationAccount( - conversation_type="personal", - tenant_id="tenant-001", - id="personal-chat-id", - ), - recipient=ChannelAccount(id="bot-001", name="Test Bot"), - name="composeExtension/selectItem", - value={ - "@id": "https://www.nuget.org/packages/Newtonsoft.Json/13.0.1", - "id": "Newtonsoft.Json", - "version": "13.0.1", - "description": "Json.NET is a popular high-performance JSON framework for .NET", - "projectUrl": "https://www.newtonsoft.com/json", - "iconUrl": "https://www.newtonsoft.com/favicon.ico", - }, - )) - - response = await agent_client.invoke(activity) - - assert response is not None, "No invoke response received" - assert response.status == 200, f"Unexpected status: {response.status}" - if response.body: - assert "Newtonsoft.Json" in str(response.body), "Package name not in response" - - @pytest.mark.asyncio - async def test__send_invoke__adaptive_card_execute__returns_response( - self, agent_client: AgentClient - ): - """Test invoke for Adaptive Card Action.Execute.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.invoke, - id="ac_invoke_001", - from_property=ChannelAccount(id="user-id-0"), - name="adaptiveCard/action", - value={ - "action": { - "type": "Action.Execute", - "title": "Execute doStuff", - "verb": "doStuff", - "data": {"usertext": "hi"}, - }, - "trigger": "manual", - }, - )) - - response = await agent_client.invoke(activity) - assert response is not None, "No invoke response received" - - @pytest.mark.asyncio - async def test__send_activity__sends_hi_5__returns_5_responses( - self, agent_client: AgentClient - ): - """Test that sending 'hi 5' returns 5 message responses.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message, - id="activity989", - timestamp="2025-07-22T19:21:03.000Z", - from_property=ChannelAccount(id="user-id-0", name="Alex Wilber"), - conversation=ConversationAccount( - conversation_type="personal", - tenant_id="tenant-001", - id="personal-chat-id-hi5", - ), - recipient=ChannelAccount(id="bot-001", name="Test Bot"), - text="hi 5", - )) - - responses = await agent_client.send(activity, wait=3.0) - - assert len(responses) >= 5, f"Expected at least 5 responses, got {len(responses)}" - - message_responses = cast(list[Activity], agent_client.select().where(type=ActivityTypes.message).get()) - - # Verify each message contains the expected pattern - for i in range(5): - combined_text = " ".join(r.text or "" for r in message_responses) - assert f"[{i}] You said: hi" in combined_text, f"Expected message [{i}] not found" - - @pytest.mark.asyncio - async def test__send_stream__stream_message__returns_stream_responses( - self, agent_client: AgentClient - ): - """Test streaming message responses.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message, - id="activity-stream-001", - timestamp="2025-06-18T18:47:46.000Z", - from_property=ChannelAccount(id="user1"), - conversation=ConversationAccount(id="conversation-stream-001"), - recipient=ChannelAccount(id="basic-agent", name="basic-agent"), - text="stream", - text_format="plain", - attachments=[], - entities=[ - Entity.model_validate({ - "type": "ClientCapabilities", - "requiresBotState": True, - "supportsListening": True, - "supportsTts": True, - }) - ], - channel_data={"clientActivityID": "client-activity-stream-001"}, - )) - - responses = await agent_client.send(activity, wait=1.0) - # Stream tests just verify responses are received - assert len(responses) > 0, "No stream responses received" - - @pytest.mark.asyncio - async def test__send_activity__start_teams_meeting__expect_message( - self, agent_client: AgentClient - ): - """Test Teams meeting start event.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.event, - id="activity989", - timestamp="2025-07-07T21:24:15.000Z", - local_timestamp="2025-07-07T14:24:15.000-07:00", - local_timezone="America/Los_Angeles", - text_format="plain", - name="application/vnd.microsoft.meetingStart", - from_property=ChannelAccount(id="user-001", name="Jordan Lee"), - conversation=ConversationAccount(id="conversation-abc123"), - recipient=ChannelAccount(id="bot-001", name="TeamHelperBot"), - service_url="https://smba.trafficmanager.net/amer/", - entities=[ - Entity.model_validate({ - "type": "clientInfo", - "locale": "en-US", - "country": "US", - "platform": "Web", - "timezone": "America/Los_Angeles", - }) - ], - channel_data={ - "tenant": {"id": "tenant-001"}, - }, - value={ - "trigger": "onMeetingStart", - "id": "meeting-12345", - "title": "Quarterly Planning Meeting", - "startTime": "2025-07-28T21:00:00Z", - "joinUrl": "https://teams.microsoft.com/l/meetup-join/...", - "meetingType": "scheduled", - "meeting": { - "organizer": { - "id": "user-002", - "name": "Morgan Rivera", - }, - "participants": [ - {"id": "user-001", "name": "Jordan Lee"}, - {"id": "user-003", "name": "Taylor Kim"}, - {"id": "user-004", "name": "Riley Chen"}, - ], - "location": "Microsoft Teams Meeting", - }, - }, - )) - - await agent_client.send(activity, wait=1.0) - agent_client.expect().that_for_one( - type=ActivityTypes.message, - text="~Meeting started with ID: meeting-12345" - ) - - @pytest.mark.asyncio - async def test__send_activity__end_teams_meeting__expect_message( - self, agent_client: AgentClient - ): - """Test Teams meeting end event.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.event, - id="activity989", - timestamp="2025-07-07T21:24:15.000Z", - local_timestamp="2025-07-07T14:24:15.000-07:00", - local_timezone="America/Los_Angeles", - text_format="plain", - name="application/vnd.microsoft.meetingEnd", - from_property=ChannelAccount(id="user-001", name="Jordan Lee"), - conversation=ConversationAccount(id="conversation-abc123"), - recipient=ChannelAccount(id="bot-001", name="TeamHelperBot"), - service_url="https://smba.trafficmanager.net/amer/", - entities=[ - Entity.model_validate({ - "type": "clientInfo", - "locale": "en-US", - "country": "US", - "platform": "Web", - "timezone": "America/Los_Angeles", - }) - ], - channel_data={ - "tenant": {"id": "tenant-001"}, - }, - value={ - "trigger": "onMeetingStart", - "id": "meeting-12345", - "title": "Quarterly Planning Meeting", - "endTime": "2025-07-28T21:00:00Z", - "joinUrl": "https://teams.microsoft.com/l/meetup-join/...", - "meetingType": "scheduled", - "meeting": { - "organizer": { - "id": "user-002", - "name": "Morgan Rivera", - }, - "participants": [ - {"id": "user-001", "name": "Jordan Lee"}, - {"id": "user-003", "name": "Taylor Kim"}, - {"id": "user-004", "name": "Riley Chen"}, - ], - "location": "Microsoft Teams Meeting", - }, - }, - )) - - await agent_client.send(activity, wait=1.0) - agent_client.expect().that_for_one( - type=ActivityTypes.message, - text="~Meeting ended with ID: meeting-12345" - ) - - @pytest.mark.asyncio - async def test__send_activity__participant_joins_teams_meeting__expect_message( - self, agent_client: AgentClient - ): - """Test Teams meeting participant join event.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.event, - id="activity989", - timestamp="2025-07-07T21:24:15.000Z", - local_timestamp="2025-07-07T14:24:15.000-07:00", - local_timezone="America/Los_Angeles", - text_format="plain", - name="application/vnd.microsoft.meetingParticipantJoin", - from_property=ChannelAccount(id="user-001", name="Jordan Lee"), - conversation=ConversationAccount(id="conversation-abc123"), - recipient=ChannelAccount(id="bot-001", name="TeamHelperBot"), - service_url="https://smba.trafficmanager.net/amer/", - entities=[ - Entity.model_validate({ - "type": "clientInfo", - "locale": "en-US", - "country": "US", - "platform": "Web", - "timezone": "America/Los_Angeles", - }) - ], - channel_data={ - "tenant": {"id": "tenant-001"}, - }, - value={ - "trigger": "onMeetingStart", - "id": "meeting-12345", - "title": "Quarterly Planning Meeting", - "endTime": "2025-07-28T21:00:00Z", - "joinUrl": "https://teams.microsoft.com/l/meetup-join/...", - "meetingType": "scheduled", - "meeting": { - "organizer": { - "id": "user-002", - "name": "Morgan Rivera", - }, - "participants": [ - {"id": "user-001", "name": "Jordan Lee"}, - {"id": "user-003", "name": "Taylor Kim"}, - {"id": "user-004", "name": "Riley Chen"}, - ], - "location": "Microsoft Teams Meeting", - }, - }, - )) - - await agent_client.send(activity, wait=1.0) - agent_client.expect().that_for_one( - type=ActivityTypes.message, - text="~Welcome to the meeting!" - ) - - @pytest.mark.asyncio - async def test__send_activity__edit_message__receive_update( - self, agent_client: AgentClient - ): - """Test message edit event.""" - # First send an initial message - activity1 = agent_client.template.create(dict( - type=ActivityTypes.message, - id="activity989", - timestamp="2025-07-07T21:24:15.930Z", - local_timestamp="2025-07-07T14:24:15.930-07:00", - local_timezone="America/Los_Angeles", - service_url="http://localhost:60209/_connector", - from_property=ChannelAccount(id="user-id-0", name="Alex Wilber", aad_object_id="aad-user-alex"), - conversation=ConversationAccount( - conversation_type="personal", - tenant_id="tenant-001", - id="personal-chat-id", - ), - recipient=ChannelAccount(id="bot-001", name="Test Bot"), - text_format="plain", - text="Hello", - entities=[ - Entity.model_validate({ - "type": "clientInfo", - "locale": "en-US", - "country": "US", - "platform": "Web", - "timezone": "America/Los_Angeles", - }) - ], - channel_data={ - "tenant": {"id": "tenant-001"}, - }, - )) - - await agent_client.send(activity1, wait=1.0) - agent_client.expect().that_for_one( - type=ActivityTypes.message, - text="~Hello" - ) - - # Then send a message update - activity2 = agent_client.template.create(dict( - type=ActivityTypes.message_update, - id="activity989", - timestamp="2025-07-07T21:24:15.930Z", - local_timestamp="2025-07-07T14:24:15.930-07:00", - local_timezone="America/Los_Angeles", - service_url="http://localhost:60209/_connector", - from_property=ChannelAccount(id="user-id-0", name="Alex Wilber", aad_object_id="aad-user-alex"), - conversation=ConversationAccount( - conversation_type="personal", - tenant_id="tenant-001", - id="personal-chat-id", - ), - recipient=ChannelAccount(id="bot-001", name="Test Bot"), - text_format="plain", - text="This is the updated message content.", - entities=[ - Entity.model_validate({ - "type": "clientInfo", - "locale": "en-US", - "country": "US", - "platform": "Web", - "timezone": "America/Los_Angeles", - }) - ], - channel_data={ - "eventType": "editMessage", - "tenant": {"id": "tenant-001"}, - }, - )) - - await agent_client.send(activity2, wait=1.0) - agent_client.expect().that_for_any( - type=ActivityTypes.message, - text="~Message Edited: activity989" - ) - - @pytest.mark.asyncio - async def test__send_activity__simulate_message_loop__weather_query( - self, agent_client: AgentClient, - ): - """Test multiple message exchanges simulating message loop.""" - # First message: weather question - activity1 = agent_client.template.create(dict( - type=ActivityTypes.message, - text="w: what's the weather?", - conversation=ConversationAccount(id="conversation-simulate-002"), - )) - - responses1 = await agent_client.send(activity1, wait=1.0) - assert len(responses1) > 0, "No response to weather question" - - # Second message: location - activity2 = agent_client.template.create(dict( - type=ActivityTypes.message, - text="w: Seattle for today", - conversation=ConversationAccount(id="conversation-simulate-002"), - )) - - responses2 = await agent_client.send(activity2, wait=1.0) - assert len(responses2) > 0, "No response to location message" diff --git a/dev/testing/cross-sdk-tests/tests/core/test_webchat.py b/dev/testing/cross-sdk-tests/tests/core/test_webchat.py deleted file mode 100644 index 0aeddecd..00000000 --- a/dev/testing/cross-sdk-tests/tests/core/test_webchat.py +++ /dev/null @@ -1,455 +0,0 @@ -import pytest -import asyncio - -from typing import cast - -from microsoft_agents.activity import ( - Activity, - ActivityTypes, - ChannelAccount, - ConversationAccount, - DeliveryModes, - Entity, -) -from microsoft_agents.testing import AgentClient, Expect - -from .test_basic_agent_base import TestBasicAgentBase - - -class TestBasicAgentWebChat(TestBasicAgentBase): - """Test WebChat channel for basic agent.""" - - @pytest.mark.asyncio - async def test__send_activity__conversation_update__returns_welcome_message( - self, agent_client: AgentClient - ): - """Test that ConversationUpdate activity returns welcome message.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.conversation_update, - members_added=[ - ChannelAccount(id="user1", name="User"), - ], - members_removed=[], - reactions_added=[], - reactions_removed=[], - attachments=[], - entities=[], - channel_data={}, - )) - - await agent_client.send(activity, wait=1.0) - - agent_client.expect().that_for_one( - type="message", - text="~Hello and Welcome!" - ) - - @pytest.mark.asyncio - async def test__send_activity__sends_hello_world__returns_hello_world( - self, agent_client: AgentClient - ): - """Test that sending 'hello world' returns echo response.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message, - id="activity-hello-webchat-001", - timestamp="2025-07-30T22:59:55.000Z", - local_timestamp="2025-07-30T15:59:55.000-07:00", - local_timezone="America/Los_Angeles", - from_property=ChannelAccount(id="user1", name=""), - conversation=ConversationAccount(id="conversation-hello-webchat-001"), - recipient=ChannelAccount(id="basic-agent@sometext", name="basic-agent"), - text_format="plain", - text="hello world", - attachments=[], - entities=[ - Entity.model_validate({ - "type": "ClientCapabilities", - "requiresBotState": True, - "supportsListening": True, - "supportsTts": True, - }) - ], - channel_data={ - "clientActivityID": "client-activity-hello-webchat-001", - }, - )) - - await agent_client.send(activity, wait=1.0) - - agent_client.expect().that_for_one( - type="message", - text="~You said: hello world" - ) - - @pytest.mark.asyncio - async def test__send_activity__sends_poem__returns_apollo_poem( - self, agent_client: AgentClient - ): - """Test that sending 'poem' returns poem about Apollo.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message, - delivery_mode=DeliveryModes.expect_replies, - text="poem", - text_format="plain", - attachments=[], - )) - - responses = await agent_client.send_expect_replies(activity) - - await asyncio.sleep(1.0) # Allow time for responses to be processed - - assert len(agent_client.history()) == len(responses), "History length mismatch with expect_replies responses" - - Expect(responses).that_for_one(type=ActivityTypes.typing) - Expect(responses).that_for_one(text="~Apollo") - Expect(responses).that_for_one(text="~Hold on for an awesome poem") - - @pytest.mark.asyncio - async def test__send_activity__sends_seattle_weather__returns_weather( - self, agent_client: AgentClient - ): - """Test that sending weather query returns weather data.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message, - text="w: Seattle for today", - mode=DeliveryModes.expect_replies, - )) - await agent_client.send(activity) - agent_client.expect().that_for_any( - type=ActivityTypes.typing - ) - - @pytest.mark.asyncio - async def test__send_activity__sends_message_with_ac_submit__returns_response( - self, agent_client: AgentClient - ): - """Test Action.Submit button on Adaptive Card.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message, - id="activity-submit-001", - timestamp="2025-07-30T23:06:37.000Z", - local_timestamp="2025-07-30T16:06:37.000-07:00", - local_timezone="America/Los_Angeles", - service_url="https://webchat.botframework.com/", - from_property=ChannelAccount(id="user1", name=""), - conversation=ConversationAccount(id="conversation-submit-001"), - recipient=ChannelAccount(id="basic-agent@sometext", name="basic-agent"), - attachments=[], - channel_data={ - "postBack": True, - "clientActivityID": "client-activity-submit-001", - }, - value={ - "verb": "doStuff", - "id": "doStuff", - "type": "Action.Submit", - "test": "test", - "data": {"name": "test"}, - "usertext": "hello", - }, - )) - - await agent_client.send(activity) - # Expect a response that includes the verb, action type, and user text - agent_client.expect().that_for_any( - type="message", - text=lambda x: "doStuff" in x and "Action.Submit" in x and "hello" in x - ) - - @pytest.mark.asyncio - async def test__send_activity__ends_conversation( - self, agent_client: AgentClient - ): - """Test that sending 'end' ends the conversation.""" - await agent_client.send("end", wait=1.0) - agent_client.expect()\ - .that_for_any(type=ActivityTypes.message)\ - .that_for_any(type=ActivityTypes.end_of_conversation)\ - .that_for_any(text="~Ending conversation") - - @pytest.mark.asyncio - async def test__send_activity__message_reaction_heart_added( - self, agent_client: AgentClient - ): - """Test that adding heart reaction returns reaction acknowledgement.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message_reaction, - timestamp="2025-07-10T02:25:04.000Z", - id="1752114287789", - from_property=ChannelAccount(id="from29ed", aad_object_id="aad-user1"), - conversation=ConversationAccount( - conversation_type="personal", - tenant_id="tenant6d4", - id="cpersonal-chat-id", - ), - recipient=ChannelAccount(id="basic-agent@sometext", name="basic-agent"), - channel_data={ - "tenant": {"id": "tenant6d4"}, - "legacy": {"replyToId": "legacy_id"}, - }, - reactions_added=[{"type": "heart"}], - reply_to_id="1752114287789", - )) - - await agent_client.send(activity, wait=1.0) - agent_client.expect().that_for_one( - type=ActivityTypes.message, - text="~Message Reaction Added: heart" - ) - - @pytest.mark.asyncio - async def test__send_activity__message_reaction_heart_removed( - self, agent_client: AgentClient - ): - """Test that removing heart reaction returns reaction acknowledgement.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message_reaction, - timestamp="2025-07-10T02:30:00.000Z", - id="1752114287789", - from_property=ChannelAccount(id="from29ed", aad_object_id="aad-user1"), - conversation=ConversationAccount( - conversation_type="personal", - tenant_id="tenant6d4", - id="cpersonal-chat-id", - ), - recipient=ChannelAccount(id="basic-agent@sometext", name="basic-agent"), - channel_data={ - "tenant": {"id": "tenant6d4"}, - "legacy": {"replyToId": "legacy_id"}, - }, - reactions_removed=[{"type": "heart"}], - reply_to_id="1752114287789", - )) - - await agent_client.send(activity, wait=1.0) - agent_client.expect().that_for_any( - type="message", - text="~Message Reaction Removed: heart" - ) - - @pytest.mark.asyncio - async def test__send_expected_replies__sends_poem__returns_poem( - self, agent_client: AgentClient - ): - """Test send_expected_replies with poem request.""" - responses = await agent_client.send_expect_replies("poem") - assert len(responses) > 0, "No responses received for expectedReplies" - Expect(responses).that_for_any(text="~Apollo") - - @pytest.mark.asyncio - async def test__send_expected_replies__sends_weather__returns_weather( - self, agent_client: AgentClient - ): - """Test send_expected_replies with weather request.""" - responses = await agent_client.send_expect_replies("w: Seattle for today") - assert len(responses) > 0, "No responses received for expectedReplies" - - @pytest.mark.asyncio - async def test__send_invoke__basic_invoke__returns_response( - self, agent_client: AgentClient - ): - """Test basic invoke activity.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.invoke, - id="invoke456", - from_property=ChannelAccount(id="user-id-0", name="Alex Wilber", aad_object_id="aad-user-alex"), - timestamp="2025-07-22T19:21:03.000Z", - conversation=ConversationAccount( - conversation_type="personal", - tenant_id="tenant-001", - id="personal-chat-id", - ), - recipient=ChannelAccount(id="bot-001", name="Test Bot"), - entities=[ - Entity.model_validate({ - "type": "clientInfo", - "locale": "en-US", - "country": "US", - "platform": "Web", - "timezone": "America/Los_Angeles", - }) - ], - value={ - "parameters": [{"value": "hi"}], - }, - service_url="http://localhost:63676/_connector", - )) - assert activity.type == "invoke" - - response = await agent_client.invoke(activity) - - assert response is not None, "No invoke response received" - assert response.status == 200, f"Unexpected status: {response.status}" - - @pytest.mark.asyncio - async def test__send_invoke__query_link( - self, agent_client: AgentClient - ): - """Test invoke for query link.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.invoke, - id="invoke_query_link", - from_property=ChannelAccount(id="user-id-0"), - name="composeExtension/queryLink", - value={}, - )) - response = await agent_client.invoke(activity) - assert response is not None, "No invoke response received" - assert response.status == 200, f"Unexpected status: {response.status}" - - @pytest.mark.asyncio - async def test__send_invoke__query_package( - self, agent_client: AgentClient - ): - """Test invoke for query package.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.invoke, - id="invoke_query_package", - from_property=ChannelAccount(id="user-id-0"), - name="composeExtension/queryPackage", - value={}, - )) - - response = await agent_client.invoke(activity) - assert response is not None, "No invoke response received" - assert response.status == 200, f"Unexpected status: {response.status}" - - @pytest.mark.asyncio - async def test__send_invoke__select_item__returns_attachment( - self, agent_client: AgentClient - ): - """Test invoke for selectItem to return package details.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.invoke, - id="invoke123", - from_property=ChannelAccount(id="user-id-0", name="Alex Wilber"), - conversation=ConversationAccount( - conversation_type="personal", - tenant_id="tenant-001", - id="personal-chat-id", - ), - recipient=ChannelAccount(id="bot-001", name="Test Bot"), - name="composeExtension/selectItem", - value={ - "@id": "https://www.nuget.org/packages/Newtonsoft.Json/13.0.1", - "id": "Newtonsoft.Json", - "version": "13.0.1", - "description": "Json.NET is a popular high-performance JSON framework for .NET", - "projectUrl": "https://www.newtonsoft.com/json", - "iconUrl": "https://www.newtonsoft.com/favicon.ico", - }, - )) - - response = await agent_client.invoke(activity) - - assert response is not None, "No invoke response received" - assert response.status == 200, f"Unexpected status: {response.status}" - if response.body: - assert "Newtonsoft.Json" in str(response.body), "Package name not in response" - - @pytest.mark.asyncio - async def test__send_invoke__adaptive_card_submit__returns_response( - self, agent_client: AgentClient - ): - """Test invoke for Adaptive Card Action.Submit.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.invoke, - id="ac_invoke_001", - from_property=ChannelAccount(id="user-id-0"), - name="adaptiveCard/action", - value={ - "action": { - "type": "Action.Submit", - "id": "submit-action", - "data": {"usertext": "hi"}, - } - }, - )) - - response = await agent_client.invoke(activity) - assert response is not None, "No invoke response received" - - @pytest.mark.asyncio - async def test__send_activity__sends_hi_5__returns_5_responses( - self, agent_client: AgentClient - ): - """Test that sending 'hi 5' returns 5 message responses.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message, - id="activity989", - timestamp="2025-07-22T19:21:03.000Z", - from_property=ChannelAccount(id="user-id-0", name="Alex Wilber"), - conversation=ConversationAccount( - conversation_type="personal", - tenant_id="tenant-001", - id="personal-chat-id-hi5", - ), - recipient=ChannelAccount(id="bot-001", name="Test Bot"), - text="hi 5", - )) - - responses = await agent_client.send(activity, wait=3.0) - - assert len(responses) >= 5, f"Expected at least 5 responses, got {len(responses)}" - - message_responses = cast(list[Activity], agent_client.select().where(type=ActivityTypes.message).get()) - - # Verify each message contains the expected pattern - for i in range(5): - combined_text = " ".join(r.text or "" for r in message_responses) - assert f"[{i}] You said: hi" in combined_text, f"Expected message [{i}] not found" - - @pytest.mark.asyncio - async def test__send_stream__stream_message__returns_stream_responses( - self, agent_client: AgentClient - ): - """Test streaming message responses.""" - activity = agent_client.template.create(dict( - type=ActivityTypes.message, - id="activity-stream-001", - timestamp="2025-06-18T18:47:46.000Z", - from_property=ChannelAccount(id="user1"), - conversation=ConversationAccount(id="conversation-stream-001"), - recipient=ChannelAccount(id="basic-agent", name="basic-agent"), - text="stream", - text_format="plain", - attachments=[], - entities=[ - Entity.model_validate({ - "type": "ClientCapabilities", - "requiresBotState": True, - "supportsListening": True, - "supportsTts": True, - }) - ], - channel_data={"clientActivityID": "client-activity-stream-001"}, - )) - - responses = await agent_client.send(activity, wait=1.0) - # Stream tests just verify responses are received - assert len(responses) > 0, "No stream responses received" - - @pytest.mark.asyncio - async def test__send_activity__simulate_message_loop__weather_query( - self, agent_client: AgentClient, - ): - """Test multiple message exchanges simulating message loop.""" - # First message: weather question - activity1 = agent_client.template.create(dict( - type=ActivityTypes.message, - text="w: what's the weather?", - conversation=ConversationAccount(id="conversation-simulate-002"), - )) - - responses1 = await agent_client.send(activity1, wait=1.0) - assert len(responses1) > 0, "No response to weather question" - - # Second message: location - activity2 = agent_client.template.create(dict( - type=ActivityTypes.message, - text="w: Seattle for today", - conversation=ConversationAccount(id="conversation-simulate-002"), - )) - - responses2 = await agent_client.send(activity2, wait=1.0) - assert len(responses2) > 0, "No response to location message" diff --git a/dev/testing/cross-sdk-tests/tests/telemetry/__init__.py b/dev/testing/cross-sdk-tests/tests/telemetry/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/dev/testing/cross-sdk-tests/tests/telemetry/test_basic_telemetry.py b/dev/testing/cross-sdk-tests/tests/telemetry/test_basic_telemetry.py deleted file mode 100644 index f4f2b5ac..00000000 --- a/dev/testing/cross-sdk-tests/tests/telemetry/test_basic_telemetry.py +++ /dev/null @@ -1,28 +0,0 @@ -import pytest - -from tests._common import ( - create_scenario, - SDKVersion, -) - -AGENT_NAME = "quickstart" -PYTHON_SCENARIO = create_scenario(AGENT_NAME, SDKVersion.PYTHON) -NET_SCENARIO = create_scenario(AGENT_NAME, SDKVersion.NET) -JS_SCENARIO = create_scenario(AGENT_NAME, SDKVersion.JS) - -class BaseTelemetryTests: - def test_telemetry(self, agent_client): - # This is a placeholder test. The actual telemetry tests will be implemented here. - assert True - -@pytest.mark.agent_test(PYTHON_SCENARIO) -class TestPythonTelemetry(BaseTelemetryTests): - pass - -@pytest.mark.agent_test(NET_SCENARIO) -class TestNetTelemetry(BaseTelemetryTests): - pass - -@pytest.mark.agent_test(JS_SCENARIO) -class TestJSTelemetry(BaseTelemetryTests): - pass \ No newline at end of file From 85877f8be9d02e530bbaf3dda65794b17a3b4407 Mon Sep 17 00:00:00 2001 From: Rodrigo Brandao Date: Fri, 10 Apr 2026 13:30:45 -0700 Subject: [PATCH 2/2] Adding dummy file to avoid CodeQL problem --- dev/testing/cross-sdk-tests/Program.cs | 1 + 1 file changed, 1 insertion(+) create mode 100644 dev/testing/cross-sdk-tests/Program.cs diff --git a/dev/testing/cross-sdk-tests/Program.cs b/dev/testing/cross-sdk-tests/Program.cs new file mode 100644 index 00000000..a685ba66 --- /dev/null +++ b/dev/testing/cross-sdk-tests/Program.cs @@ -0,0 +1 @@ +// to avoid CodeQL problem \ No newline at end of file