mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: Add Python parity for HttpRequestAction in declarative workflow (#5599)
* Add Python parity for HttpRequestAction in declarative workflow * Ran pyupgrade and pright to fix CI issues * Fix conversation ID dot parsing for http executor * Removed unnecessary export command
This commit is contained in:
committed by
GitHub
Unverified
parent
18293ffb31
commit
bc42874690
@@ -0,0 +1,97 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Invoke HTTP Request sample - demonstrates the HttpRequestAction declarative action.
|
||||
|
||||
This sample shows how to:
|
||||
1. Configure a ``WorkflowFactory`` with a ``HttpRequestHandler`` so the YAML
|
||||
``HttpRequestAction`` can dispatch real HTTP calls.
|
||||
2. Fetch JSON from a public REST endpoint (the GitHub repository API) and
|
||||
bind the parsed response to a workflow variable.
|
||||
3. Mirror the response body into the conversation via ``conversationId`` so
|
||||
a downstream Foundry agent can answer questions about it using only that
|
||||
conversation context.
|
||||
|
||||
Security note:
|
||||
``DefaultHttpRequestHandler`` issues HTTP calls to whatever URL the
|
||||
workflow author specifies and performs **no** allowlisting or SSRF
|
||||
guards. For production use, replace it with a custom handler that
|
||||
enforces an allowlist or DNS-rebinding-resistant policy and adds any
|
||||
required authentication headers per call.
|
||||
|
||||
Run with:
|
||||
python -m samples.03-workflows.declarative.invoke_http_request.main
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from agent_framework import Agent
|
||||
from agent_framework.declarative import (
|
||||
DefaultHttpRequestHandler,
|
||||
WorkflowFactory,
|
||||
)
|
||||
from agent_framework.foundry import FoundryChatClient
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
GITHUB_REPO_INFO_AGENT_INSTRUCTIONS = """\
|
||||
You answer the user's question about a GitHub repository using ONLY the JSON
|
||||
data already present in the conversation history. If the answer is not
|
||||
contained in the conversation, say so plainly rather than guessing. Be concise
|
||||
and helpful.
|
||||
"""
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
"""Run the invoke HTTP request workflow."""
|
||||
chat_client = FoundryChatClient(
|
||||
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
|
||||
model=os.environ["FOUNDRY_MODEL"],
|
||||
credential=AzureCliCredential(),
|
||||
)
|
||||
|
||||
# The agent has no tools — it answers the question about the GitHub
|
||||
# repository using only the JSON data that ``HttpRequestAction`` adds to
|
||||
# the conversation.
|
||||
github_repo_info_agent = Agent(
|
||||
client=chat_client,
|
||||
name="GitHubRepoInfoAgent",
|
||||
instructions=GITHUB_REPO_INFO_AGENT_INSTRUCTIONS,
|
||||
)
|
||||
|
||||
agents = {"GitHubRepoInfoAgent": github_repo_info_agent}
|
||||
|
||||
# The default HttpRequestHandler is sufficient for this sample because
|
||||
# the GitHub REST endpoint used here does not require authentication.
|
||||
# For authenticated endpoints, supply a custom client_provider callback
|
||||
# to DefaultHttpRequestHandler so each request can be routed through a
|
||||
# pre-configured httpx.AsyncClient with the appropriate credentials.
|
||||
async with DefaultHttpRequestHandler() as http_handler:
|
||||
factory = WorkflowFactory(
|
||||
agents=agents,
|
||||
http_request_handler=http_handler,
|
||||
)
|
||||
|
||||
workflow_path = Path(__file__).parent / "workflow.yaml"
|
||||
workflow = factory.create_workflow_from_yaml_path(workflow_path)
|
||||
|
||||
print("=" * 60)
|
||||
print("Invoke HTTP Request Workflow Demo")
|
||||
print("=" * 60)
|
||||
print()
|
||||
print("Ask one question about the microsoft/agent-framework repo.")
|
||||
print()
|
||||
|
||||
user_input = input("You: ").strip() # noqa: ASYNC250
|
||||
if not user_input:
|
||||
user_input = "Please summarize the repository."
|
||||
|
||||
print("\nAgent: ", end="", flush=True)
|
||||
async for event in workflow.run(user_input, stream=True):
|
||||
if event.type == "output" and isinstance(event.data, str):
|
||||
print(event.data, end="", flush=True)
|
||||
print()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,57 @@
|
||||
#
|
||||
# This workflow demonstrates the HttpRequestAction declarative action.
|
||||
#
|
||||
# HttpRequestAction lets a workflow author issue an HTTP call directly from
|
||||
# YAML without writing any Python glue. It can:
|
||||
#
|
||||
# - fetch data from external REST endpoints,
|
||||
# - store the parsed response in a workflow variable, and
|
||||
# - add the response body to the conversation so a downstream agent can
|
||||
# answer questions based on it.
|
||||
#
|
||||
# This sample fetches public metadata for the microsoft/agent-framework
|
||||
# repository from the GitHub REST API (no authentication required) and uses
|
||||
# a Foundry agent to answer a single question about it.
|
||||
#
|
||||
# Example input:
|
||||
# How many open issues does the repository have?
|
||||
#
|
||||
kind: Workflow
|
||||
trigger:
|
||||
|
||||
kind: OnConversationStart
|
||||
id: workflow_invoke_http_request_demo
|
||||
actions:
|
||||
|
||||
# Set the repository org/name used to form the request URL.
|
||||
- kind: SetVariable
|
||||
id: set_repo_name
|
||||
variable: Local.RepoName
|
||||
value: microsoft/agent-framework
|
||||
|
||||
# Invoke the GitHub repo API. The response body is parsed into
|
||||
# Local.RepoInfo and also added to the conversation (via conversationId)
|
||||
# so the agent below can answer questions based on it.
|
||||
- kind: HttpRequestAction
|
||||
id: fetch_repo_info
|
||||
conversationId: =System.ConversationId
|
||||
method: GET
|
||||
url: =Concatenate("https://api.github.com/repos/", Local.RepoName)
|
||||
headers:
|
||||
Accept: application/vnd.github+json
|
||||
User-Agent: agent-framework-sample
|
||||
response: Local.RepoInfo
|
||||
|
||||
# Use the agent to answer the user's question using the conversation
|
||||
# context (which now contains the GitHub JSON response). The user's
|
||||
# original message is already in the conversation as System.LastMessage,
|
||||
# and the executor's input fallback chain extracts its ``Text`` field
|
||||
# automatically when ``input.messages`` is omitted.
|
||||
- kind: InvokeAzureAgent
|
||||
id: answer_question
|
||||
conversationId: =System.ConversationId
|
||||
agent:
|
||||
name: GitHubRepoInfoAgent
|
||||
output:
|
||||
autoSend: true
|
||||
messages: Local.AgentResponse
|
||||
Reference in New Issue
Block a user