chore: import upstream snapshot with attribution
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
# Customer Support Workflow Sample
|
||||
|
||||
Multi-agent workflow demonstrating automated troubleshooting with escalation paths.
|
||||
|
||||
## Overview
|
||||
|
||||
Coordinates six specialized agents to handle customer support requests:
|
||||
|
||||
1. **SelfServiceAgent** - Initial troubleshooting with user
|
||||
2. **TicketingAgent** - Creates tickets when escalation needed
|
||||
3. **TicketRoutingAgent** - Routes to appropriate team
|
||||
4. **WindowsSupportAgent** - Windows-specific troubleshooting
|
||||
5. **TicketResolutionAgent** - Resolves tickets
|
||||
6. **TicketEscalationAgent** - Escalates to human support
|
||||
|
||||
## Files
|
||||
|
||||
- `workflow.yaml` - Workflow definition with conditional routing
|
||||
- `main.py` - Agent definitions and workflow execution
|
||||
- `ticketing_plugin.py` - Mock ticketing system plugin
|
||||
|
||||
## Running
|
||||
|
||||
```bash
|
||||
python main.py
|
||||
```
|
||||
|
||||
## Example Input
|
||||
|
||||
```
|
||||
My PC keeps rebooting and I can't use it.
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- Azure OpenAI endpoint configured
|
||||
- `az login` for authentication
|
||||
@@ -0,0 +1 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
@@ -0,0 +1,361 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""
|
||||
CustomerSupport workflow sample.
|
||||
|
||||
This workflow demonstrates using multiple agents to provide automated
|
||||
troubleshooting steps to resolve common issues with escalation options.
|
||||
|
||||
Example input: "My PC keeps rebooting and I can't use it."
|
||||
|
||||
Usage:
|
||||
python main.py
|
||||
|
||||
The workflow:
|
||||
1. SelfServiceAgent: Works with user to provide troubleshooting steps
|
||||
2. TicketingAgent: Creates a ticket if issue needs escalation
|
||||
3. TicketRoutingAgent: Determines which team should handle the ticket
|
||||
4. WindowsSupportAgent: Provides Windows-specific troubleshooting
|
||||
5. TicketResolutionAgent: Resolves the ticket when issue is fixed
|
||||
6. TicketEscalationAgent: Escalates to human support if needed
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import Agent
|
||||
from agent_framework.declarative import (
|
||||
AgentExternalInputRequest,
|
||||
AgentExternalInputResponse,
|
||||
WorkflowFactory,
|
||||
)
|
||||
from agent_framework.foundry import FoundryChatClient
|
||||
from agent_framework.openai import OpenAIChatOptions
|
||||
from azure.identity import AzureCliCredential
|
||||
from dotenv import load_dotenv
|
||||
from pydantic import BaseModel, Field
|
||||
from ticketing_plugin import TicketingPlugin # ty: ignore[unresolved-import] # pyrefly: ignore[missing-import]
|
||||
|
||||
logging.basicConfig(level=logging.ERROR)
|
||||
|
||||
# Load environment variables from .env file
|
||||
load_dotenv()
|
||||
|
||||
|
||||
# ANSI color codes for output formatting
|
||||
CYAN = "\033[36m"
|
||||
GREEN = "\033[32m"
|
||||
YELLOW = "\033[33m"
|
||||
MAGENTA = "\033[35m"
|
||||
RESET = "\033[0m"
|
||||
|
||||
# Agent Instructions
|
||||
|
||||
SELF_SERVICE_INSTRUCTIONS = """
|
||||
Use your knowledge to work with the user to provide the best possible troubleshooting steps.
|
||||
|
||||
- If the user confirms that the issue is resolved, then the issue is resolved.
|
||||
- If the user reports that the issue persists, then escalate.
|
||||
""".strip()
|
||||
|
||||
TICKETING_INSTRUCTIONS = """Always create a ticket in Azure DevOps using the available tools.
|
||||
|
||||
Include the following information in the TicketSummary.
|
||||
|
||||
- Issue description: {{IssueDescription}}
|
||||
- Attempted resolution steps: {{AttemptedResolutionSteps}}
|
||||
|
||||
After creating the ticket, provide the user with the ticket ID."""
|
||||
|
||||
TICKET_ROUTING_INSTRUCTIONS = """Determine how to route the given issue to the appropriate support team.
|
||||
|
||||
Choose from the available teams and their functions:
|
||||
- Windows Activation Support: Windows license activation issues
|
||||
- Windows Support: Windows related issues
|
||||
- Azure Support: Azure related issues
|
||||
- Network Support: Network related issues
|
||||
- Hardware Support: Hardware related issues
|
||||
- Microsoft Office Support: Microsoft Office related issues
|
||||
- General Support: General issues not related to the above categories"""
|
||||
|
||||
WINDOWS_SUPPORT_INSTRUCTIONS = """
|
||||
Use your knowledge to work with the user to provide the best possible troubleshooting steps
|
||||
for issues related to Windows operating system.
|
||||
|
||||
- Utilize the "Attempted Resolutions Steps" as a starting point for your troubleshooting.
|
||||
- Never escalate without troubleshooting with the user.
|
||||
- If the user confirms that the issue is resolved, then the issue is resolved.
|
||||
- If the user reports that the issue persists, then escalate.
|
||||
|
||||
Issue: {{IssueDescription}}
|
||||
Attempted Resolution Steps: {{AttemptedResolutionSteps}}"""
|
||||
|
||||
RESOLUTION_INSTRUCTIONS = """Resolve the following ticket in Azure DevOps.
|
||||
Always include the resolution details.
|
||||
|
||||
- Ticket ID: #{{TicketId}}
|
||||
- Resolution Summary: {{ResolutionSummary}}"""
|
||||
|
||||
ESCALATION_INSTRUCTIONS = """
|
||||
You escalate the provided issue to human support team by sending an email.
|
||||
|
||||
Here are some additional details that might help:
|
||||
- TicketId : {{TicketId}}
|
||||
- IssueDescription : {{IssueDescription}}
|
||||
- AttemptedResolutionSteps : {{AttemptedResolutionSteps}}
|
||||
|
||||
Before escalating, gather the user's email address for follow-up.
|
||||
If not known, ask the user for their email address so that the support team can reach them when needed.
|
||||
|
||||
When sending the email, include the following details:
|
||||
- To: support@contoso.com
|
||||
- Cc: user's email address
|
||||
- Subject of the email: "Support Ticket - {TicketId} - [Compact Issue Description]"
|
||||
- Body:
|
||||
- Issue description
|
||||
- Attempted resolution steps
|
||||
- User's email address
|
||||
- Any other relevant information from the conversation history
|
||||
|
||||
Assure the user that their issue will be resolved and provide them with a ticket ID for reference."""
|
||||
|
||||
|
||||
# Pydantic models for structured outputs
|
||||
class SelfServiceResponse(BaseModel):
|
||||
"""Response from self-service agent evaluation."""
|
||||
|
||||
IsResolved: bool = Field(description="True if the user issue/ask has been resolved.")
|
||||
NeedsTicket: bool = Field(description="True if the user issue/ask requires that a ticket be filed.")
|
||||
IssueDescription: str = Field(description="A concise description of the issue.")
|
||||
AttemptedResolutionSteps: str = Field(description="An outline of the steps taken to attempt resolution.")
|
||||
|
||||
|
||||
class TicketingResponse(BaseModel):
|
||||
"""Response from ticketing agent."""
|
||||
|
||||
TicketId: str = Field(description="The identifier of the ticket created in response to the user issue.")
|
||||
TicketSummary: str = Field(description="The summary of the ticket created in response to the user issue.")
|
||||
|
||||
|
||||
class RoutingResponse(BaseModel):
|
||||
"""Response from routing agent."""
|
||||
|
||||
TeamName: str = Field(description="The name of the team to route the issue")
|
||||
|
||||
|
||||
class SupportResponse(BaseModel):
|
||||
"""Response from support agent."""
|
||||
|
||||
IsResolved: bool = Field(description="True if the user issue/ask has been resolved.")
|
||||
NeedsEscalation: bool = Field(
|
||||
description="True resolution could not be achieved and the issue/ask requires escalation."
|
||||
)
|
||||
ResolutionSummary: str = Field(description="The summary of the steps that led to resolution.")
|
||||
|
||||
|
||||
class EscalationResponse(BaseModel):
|
||||
"""Response from escalation agent."""
|
||||
|
||||
IsComplete: bool = Field(description="Has the email been sent and no more user input is required.")
|
||||
UserMessage: str = Field(description="A natural language message to the user.")
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
"""Run the customer support workflow."""
|
||||
# Create ticketing plugin
|
||||
plugin = TicketingPlugin()
|
||||
|
||||
# Create Azure OpenAI client
|
||||
client = FoundryChatClient(
|
||||
project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
|
||||
# This sample has been tested only on `gpt-5.1` and may not work as intended on other models
|
||||
# This sample is known to fail on `gpt-5-mini` reasoning input (GH issue #4059)
|
||||
model=os.environ["FOUNDRY_MODEL"],
|
||||
credential=AzureCliCredential(),
|
||||
)
|
||||
|
||||
# Create agents with structured outputs
|
||||
self_service_agent = Agent(
|
||||
client=client,
|
||||
name="SelfServiceAgent",
|
||||
instructions=SELF_SERVICE_INSTRUCTIONS,
|
||||
default_options=OpenAIChatOptions[Any](response_format=SelfServiceResponse),
|
||||
)
|
||||
|
||||
ticketing_agent = Agent(
|
||||
client=client,
|
||||
name="TicketingAgent",
|
||||
instructions=TICKETING_INSTRUCTIONS,
|
||||
tools=plugin.get_functions(),
|
||||
default_options=OpenAIChatOptions[Any](response_format=TicketingResponse),
|
||||
)
|
||||
|
||||
routing_agent = Agent(
|
||||
client=client,
|
||||
name="TicketRoutingAgent",
|
||||
instructions=TICKET_ROUTING_INSTRUCTIONS,
|
||||
tools=[plugin.get_ticket],
|
||||
default_options=OpenAIChatOptions[Any](response_format=RoutingResponse),
|
||||
)
|
||||
|
||||
windows_support_agent = Agent(
|
||||
client=client,
|
||||
name="WindowsSupportAgent",
|
||||
instructions=WINDOWS_SUPPORT_INSTRUCTIONS,
|
||||
tools=[plugin.get_ticket],
|
||||
default_options=OpenAIChatOptions[Any](response_format=SupportResponse),
|
||||
)
|
||||
|
||||
resolution_agent = Agent(
|
||||
client=client,
|
||||
name="TicketResolutionAgent",
|
||||
instructions=RESOLUTION_INSTRUCTIONS,
|
||||
tools=[plugin.resolve_ticket],
|
||||
)
|
||||
|
||||
escalation_agent = Agent(
|
||||
client=client,
|
||||
name="TicketEscalationAgent",
|
||||
instructions=ESCALATION_INSTRUCTIONS,
|
||||
tools=[plugin.get_ticket, plugin.send_notification],
|
||||
default_options=OpenAIChatOptions[Any](response_format=EscalationResponse),
|
||||
)
|
||||
|
||||
# Agent registry for lookup
|
||||
agents = {
|
||||
"SelfServiceAgent": self_service_agent,
|
||||
"TicketingAgent": ticketing_agent,
|
||||
"TicketRoutingAgent": routing_agent,
|
||||
"WindowsSupportAgent": windows_support_agent,
|
||||
"TicketResolutionAgent": resolution_agent,
|
||||
"TicketEscalationAgent": escalation_agent,
|
||||
}
|
||||
|
||||
# Print loaded agents (similar to .NET "PROMPT AGENT: AgentName:1")
|
||||
for agent_name in agents:
|
||||
print(f"{CYAN}PROMPT AGENT: {agent_name}:1{RESET}")
|
||||
|
||||
# Create workflow factory
|
||||
factory = WorkflowFactory(agents=agents)
|
||||
|
||||
# Load workflow from YAML
|
||||
samples_root = Path(__file__).parent.parent.parent.parent.parent.parent.parent
|
||||
workflow_path = samples_root / "declarative-agents" / "workflow-samples" / "CustomerSupport.yaml"
|
||||
if not workflow_path.exists():
|
||||
# Fall back to local copy if declarative-agents/workflow-samples doesn't exist
|
||||
workflow_path = Path(__file__).parent / "workflow.yaml"
|
||||
|
||||
workflow = factory.create_workflow_from_yaml_path(workflow_path)
|
||||
|
||||
print()
|
||||
print("=" * 60)
|
||||
|
||||
# Example input
|
||||
user_input = "My computer won't boot"
|
||||
pending_request_id: str | None = None
|
||||
|
||||
# Track responses for formatting
|
||||
accumulated_response: str = ""
|
||||
last_agent_name: str | None = None
|
||||
|
||||
print(f"\n{GREEN}INPUT:{RESET} {user_input}\n")
|
||||
|
||||
while True:
|
||||
if pending_request_id:
|
||||
# Continue workflow with user response
|
||||
print(f"\n{YELLOW}WORKFLOW:{RESET} Restore\n")
|
||||
response = AgentExternalInputResponse(user_input=user_input)
|
||||
stream = workflow.run(stream=True, responses={pending_request_id: response})
|
||||
pending_request_id = None
|
||||
else:
|
||||
# Start workflow
|
||||
stream = workflow.run(user_input, stream=True)
|
||||
|
||||
async for event in stream:
|
||||
if event.type == "output":
|
||||
data = event.data
|
||||
# source_executor_id is only available on request_info events.
|
||||
# For output events, use executor_id to identify the emitting node.
|
||||
source_id = event.executor_id or ""
|
||||
|
||||
# Check if this is a SendActivity output (activity text from log_ticket, log_route, etc.)
|
||||
if "log_" in source_id.lower():
|
||||
# Print any accumulated agent response first
|
||||
if accumulated_response and last_agent_name:
|
||||
msg_id = f"msg_{uuid.uuid4().hex[:32]}"
|
||||
print(f"{CYAN}{last_agent_name.upper()}:{RESET} [{msg_id}]")
|
||||
try:
|
||||
parsed = json.loads(accumulated_response)
|
||||
print(json.dumps(parsed))
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
print(accumulated_response)
|
||||
accumulated_response = ""
|
||||
last_agent_name = None
|
||||
# Print activity
|
||||
print(f"\n{MAGENTA}ACTIVITY:{RESET}")
|
||||
print(data)
|
||||
else:
|
||||
# Accumulate agent response (streaming text)
|
||||
if isinstance(data, str):
|
||||
accumulated_response += data
|
||||
else:
|
||||
accumulated_response += str(data)
|
||||
|
||||
elif event.type == "request_info" and isinstance(event.data, AgentExternalInputRequest):
|
||||
request = event.data
|
||||
|
||||
# The agent_response from the request contains the structured response
|
||||
agent_name = request.agent_name
|
||||
agent_response = request.agent_response
|
||||
|
||||
# Print the agent's response
|
||||
if agent_response:
|
||||
msg_id = f"msg_{uuid.uuid4().hex[:32]}"
|
||||
print(f"{CYAN}{agent_name.upper()}:{RESET} [{msg_id}]")
|
||||
try:
|
||||
parsed = json.loads(agent_response)
|
||||
print(json.dumps(parsed))
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
print(agent_response)
|
||||
|
||||
# Clear accumulated since we printed from the request
|
||||
accumulated_response = ""
|
||||
last_agent_name = agent_name
|
||||
|
||||
pending_request_id = event.request_id
|
||||
print(f"\n{YELLOW}WORKFLOW:{RESET} Yield")
|
||||
|
||||
# Print any remaining accumulated response at end of stream
|
||||
if accumulated_response:
|
||||
# Try to identify which agent this came from based on content
|
||||
msg_id = f"msg_{uuid.uuid4().hex[:32]}"
|
||||
print(f"\nResponse: [{msg_id}]")
|
||||
try:
|
||||
parsed = json.loads(accumulated_response)
|
||||
print(json.dumps(parsed))
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
print(accumulated_response)
|
||||
accumulated_response = ""
|
||||
|
||||
if not pending_request_id:
|
||||
break
|
||||
|
||||
# Get next user input
|
||||
user_input = input(f"\n{GREEN}INPUT:{RESET} ").strip() # noqa: ASYNC250
|
||||
if not user_input:
|
||||
print("Exiting...")
|
||||
break
|
||||
print()
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("Workflow Complete")
|
||||
print("=" * 60)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,79 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
"""Ticketing plugin for CustomerSupport workflow."""
|
||||
|
||||
import uuid
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
|
||||
# ANSI color codes
|
||||
MAGENTA = "\033[35m"
|
||||
RESET = "\033[0m"
|
||||
|
||||
|
||||
class TicketStatus(Enum):
|
||||
"""Status of a support ticket."""
|
||||
|
||||
OPEN = "open"
|
||||
IN_PROGRESS = "in_progress"
|
||||
RESOLVED = "resolved"
|
||||
CLOSED = "closed"
|
||||
|
||||
|
||||
@dataclass
|
||||
class TicketItem:
|
||||
"""A support ticket."""
|
||||
|
||||
id: str
|
||||
subject: str = ""
|
||||
description: str = ""
|
||||
notes: str = ""
|
||||
status: TicketStatus = TicketStatus.OPEN
|
||||
|
||||
|
||||
class TicketingPlugin:
|
||||
"""Mock ticketing plugin for customer support workflow."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._ticket_store: dict[str, TicketItem] = {}
|
||||
|
||||
def _trace(self, function_name: str) -> None:
|
||||
print(f"\n{MAGENTA}FUNCTION: {function_name}{RESET}")
|
||||
|
||||
def get_ticket(self, id: str) -> TicketItem | None:
|
||||
"""Retrieve a ticket by identifier from Azure DevOps."""
|
||||
self._trace("get_ticket")
|
||||
return self._ticket_store.get(id)
|
||||
|
||||
def create_ticket(self, subject: str, description: str, notes: str) -> str:
|
||||
"""Create a ticket in Azure DevOps and return its identifier."""
|
||||
self._trace("create_ticket")
|
||||
ticket_id = uuid.uuid4().hex
|
||||
ticket = TicketItem(
|
||||
id=ticket_id,
|
||||
subject=subject,
|
||||
description=description,
|
||||
notes=notes,
|
||||
)
|
||||
self._ticket_store[ticket_id] = ticket
|
||||
return ticket_id
|
||||
|
||||
def resolve_ticket(self, id: str, resolution_summary: str) -> None:
|
||||
"""Resolve an existing ticket in Azure DevOps given its identifier."""
|
||||
self._trace("resolve_ticket")
|
||||
if ticket := self._ticket_store.get(id):
|
||||
ticket.status = TicketStatus.RESOLVED
|
||||
|
||||
def send_notification(self, id: str, email: str, cc: str, body: str) -> None:
|
||||
"""Send an email notification to escalate ticket engagement."""
|
||||
self._trace("send_notification")
|
||||
|
||||
def get_functions(self) -> list[Callable[..., object]]:
|
||||
"""Return all plugin functions for registration."""
|
||||
return [
|
||||
self.get_ticket,
|
||||
self.create_ticket,
|
||||
self.resolve_ticket,
|
||||
self.send_notification,
|
||||
]
|
||||
@@ -0,0 +1,164 @@
|
||||
#
|
||||
# This workflow demonstrates using multiple agents to provide automated
|
||||
# troubleshooting steps to resolve common issues with escalation options.
|
||||
#
|
||||
# Example input:
|
||||
# My PC keeps rebooting and I can't use it.
|
||||
#
|
||||
kind: Workflow
|
||||
trigger:
|
||||
|
||||
kind: OnConversationStart
|
||||
id: workflow_demo
|
||||
actions:
|
||||
|
||||
# Interact with user until the issue has been resolved or
|
||||
# a determination is made that a ticket is required.
|
||||
- kind: InvokeAzureAgent
|
||||
id: service_agent
|
||||
conversationId: =System.ConversationId
|
||||
agent:
|
||||
name: SelfServiceAgent
|
||||
input:
|
||||
externalLoop:
|
||||
when: |-
|
||||
=Not(Local.ServiceParameters.IsResolved)
|
||||
And
|
||||
Not(Local.ServiceParameters.NeedsTicket)
|
||||
output:
|
||||
responseObject: Local.ServiceParameters
|
||||
|
||||
# All done if issue is resolved.
|
||||
- kind: ConditionGroup
|
||||
id: check_if_resolved
|
||||
conditions:
|
||||
|
||||
- condition: =Local.ServiceParameters.IsResolved
|
||||
id: test_if_resolved
|
||||
actions:
|
||||
- kind: GotoAction
|
||||
id: end_when_resolved
|
||||
actionId: all_done
|
||||
|
||||
# Create the ticket.
|
||||
- kind: InvokeAzureAgent
|
||||
id: ticket_agent
|
||||
agent:
|
||||
name: TicketingAgent
|
||||
input:
|
||||
arguments:
|
||||
IssueDescription: =Local.ServiceParameters.IssueDescription
|
||||
AttemptedResolutionSteps: =Local.ServiceParameters.AttemptedResolutionSteps
|
||||
output:
|
||||
responseObject: Local.TicketParameters
|
||||
|
||||
# Capture the attempted resolution steps.
|
||||
- kind: SetVariable
|
||||
id: capture_attempted_resolution
|
||||
variable: Local.ResolutionSteps
|
||||
value: =Local.ServiceParameters.AttemptedResolutionSteps
|
||||
|
||||
# Notify user of ticket identifier.
|
||||
- kind: SendActivity
|
||||
id: log_ticket
|
||||
activity: "Created ticket #{Local.TicketParameters.TicketId}"
|
||||
|
||||
# Determine which team for which route the ticket.
|
||||
- kind: InvokeAzureAgent
|
||||
id: routing_agent
|
||||
agent:
|
||||
name: TicketRoutingAgent
|
||||
input:
|
||||
messages: =UserMessage(Local.ServiceParameters.IssueDescription)
|
||||
output:
|
||||
responseObject: Local.RoutingParameters
|
||||
|
||||
# Notify user of routing decision.
|
||||
- kind: SendActivity
|
||||
id: log_route
|
||||
activity: Routing to {Local.RoutingParameters.TeamName}
|
||||
|
||||
- kind: ConditionGroup
|
||||
id: check_routing
|
||||
conditions:
|
||||
|
||||
- condition: =Local.RoutingParameters.TeamName = "Windows Support"
|
||||
id: route_to_support
|
||||
actions:
|
||||
|
||||
# Invoke the support agent to attempt to resolve the issue.
|
||||
- kind: CreateConversation
|
||||
id: conversation_support
|
||||
conversationId: Local.SupportConversationId
|
||||
|
||||
- kind: InvokeAzureAgent
|
||||
id: support_agent
|
||||
conversationId: =Local.SupportConversationId
|
||||
agent:
|
||||
name: WindowsSupportAgent
|
||||
input:
|
||||
arguments:
|
||||
IssueDescription: =Local.ServiceParameters.IssueDescription
|
||||
AttemptedResolutionSteps: =Local.ServiceParameters.AttemptedResolutionSteps
|
||||
externalLoop:
|
||||
when: |-
|
||||
=Not(Local.SupportParameters.IsResolved)
|
||||
And
|
||||
Not(Local.SupportParameters.NeedsEscalation)
|
||||
output:
|
||||
autoSend: true
|
||||
responseObject: Local.SupportParameters
|
||||
|
||||
# Capture the attempted resolution steps.
|
||||
- kind: SetVariable
|
||||
id: capture_support_resolution
|
||||
variable: Local.ResolutionSteps
|
||||
value: =Local.SupportParameters.ResolutionSummary
|
||||
|
||||
# Check if the issue was resolved by support.
|
||||
- kind: ConditionGroup
|
||||
id: check_resolved
|
||||
conditions:
|
||||
|
||||
# Resolve ticket
|
||||
- condition: =Local.SupportParameters.IsResolved
|
||||
id: handle_if_resolved
|
||||
actions:
|
||||
|
||||
- kind: InvokeAzureAgent
|
||||
id: resolution_agent
|
||||
agent:
|
||||
name: TicketResolutionAgent
|
||||
input:
|
||||
arguments:
|
||||
TicketId: =Local.TicketParameters.TicketId
|
||||
ResolutionSummary: =Local.SupportParameters.ResolutionSummary
|
||||
|
||||
- kind: GotoAction
|
||||
id: end_when_solved
|
||||
actionId: all_done
|
||||
|
||||
# Escalate the ticket by sending an email notification.
|
||||
- kind: CreateConversation
|
||||
id: conversation_escalate
|
||||
conversationId: Local.EscalationConversationId
|
||||
|
||||
- kind: InvokeAzureAgent
|
||||
id: escalate_agent
|
||||
conversationId: =Local.EscalationConversationId
|
||||
agent:
|
||||
name: TicketEscalationAgent
|
||||
input:
|
||||
arguments:
|
||||
TicketId: =Local.TicketParameters.TicketId
|
||||
IssueDescription: =Local.ServiceParameters.IssueDescription
|
||||
ResolutionSummary: =Local.ResolutionSteps
|
||||
externalLoop:
|
||||
when: =Not(Local.EscalationParameters.IsComplete)
|
||||
output:
|
||||
autoSend: true
|
||||
responseObject: Local.EscalationParameters
|
||||
|
||||
# All done
|
||||
- kind: EndWorkflow
|
||||
id: all_done
|
||||
Reference in New Issue
Block a user